From: Tuukka Lehtonen August 17, 2006 The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at http://www.eclipse.org/legal/epl-v10.html.
+For purposes of the EPL, "Program" will mean the Content. If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at http://www.eclipse.org. The Content includes items that have been sourced from third parties as set out below. If you
+did not receive this Content directly from the Eclipse Foundation, the following is provided
+for informational purposes only, and you should look to the Redistributor’s license for
+terms and conditions of use. This software is based in part on the work of the Independent JPEG Group's JPEG software release 6b ("LIBJPEG").
+LIBJPEG was used to implement the decoding of JPEG format files in Java (TM). The Content does NOT include any portion of the LIBJPEG file ansi2knr.c. Your use of LIBJPEG is subject to the terms and conditions located in the about_files/IJG_README file which is included
+with the Content. The IJG's website is located at http://ijg.org. The class org.eclipse.swt.internal.image.JPEGFileFormat is based on following files from LIBJPEG: The class org.eclipse.swt.internal.image.JPEGDecoder is based on the following files from LIBJPEG: The following changes were made to the LIBJPEG code in the Content: Portions of the SWT class org/eclipse/swt/internal/image/PngDeflater are based on PuTTY's sshzlib.c. PuTTY is made available by Mozilla.org. Use of PuTTY is governed by the terms and
+conditions of the the following MIT-style license: PuTTY is copyright 1997-2007 Simon Tatham. Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn, and CORE SDI S.A. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. A copy of the license is also available at http://www.chiark.greenend.org.uk/~sgtatham/putty/licence.html. Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
+ * By defining constants like UP and DOWN in a single class, SWT
+ * can share common names and concepts at the same time minimizing
+ * the number of classes, names and constants for the application
+ * programmer.
+ *
+ * Note that some of the constants provided by this class represent
+ * optional, appearance related aspects of widgets which are available
+ * either only on some window systems, or for a differing set of
+ * widgets on each window system. These constants are marked
+ * as HINTs. The set of widgets which support a particular
+ * HINT may change from release to release, although we typically
+ * will not withdraw support for a HINT once it is made available.
+ *
+ * The settings changed event is sent when an operating system
+ * property, such as a system font or color, has been changed.
+ * The event occurs after the property has been changed, but
+ * before any widget is redrawn. Applications that cache operating
+ * system properties can use this event to update their caches.
+ * A specific property change can be detected by querying the
+ * new value of a property and comparing it with the equivalent
+ * cached value. The operating system automatically redraws and
+ * lays out all widgets after this event is sent.
+ *
+ * The IME composition event is sent to allow
+ * custom text editors to implement in-line
+ * editing of international text.
+ *
+ * On some platforms the orientation of text widgets
+ * can be changed by keyboard shortcut.
+ * The application can use the
+ * The skin event is sent by the display when a widget needs to
+ * be skinned.
+ *
+ * This event is sent when SWT receives notification that a document
+ * should be opened.
+ *
+ * This event is sent when a touch has been performed
+ * on a touch-based input source.
+ *
+ * This event is sent when a gesture has been performed.
+ *
+ * This event is sent when text content has been changed.
+ *
+ * This event is sent before an event other than {@link #PreExternalEventDispatch} or
+ * {@link #PostExternalEventDispatch} is dispatched.
+ *
+ * The detail field of the event contains the type of the following event.
+ *
+ * This event is sent after an event other than {@link #PreExternalEventDispatch} or
+ * {@link #PostExternalEventDispatch} is dispatched.
+ *
+ * The detail field of the event contains the type of the prior event.
+ *
+ * This event is sent before calling a blocking method that does its own event dispatch outside
+ * of the SWT code.
+ *
+ * This event is sent after calling a blocking method that does its own event dispatch outside
+ * of the SWT code.
+ *
+ * This event is sent when SWT receives notification that a URL
+ * should be opened.
+ *
+ * This event is sent on
+ * Note that this is a HINT and is not sent on platforms that do not
+ * support dynamic DPI changes. This event is currently sent on Windows 10 and GTK
+ * only.
+ * Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By:
+ * A tool window is a window intended to be used as a floating toolbar.
+ * It typically has a title bar that is shorter than a normal title bar,
+ * and the window title is typically drawn using a smaller font.
+ * Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Note that this is a HINT.
+ * Used By: Used By: Used By:
+ * When neither H_SCROLL or V_SCROLL are specified, controls
+ * are free to create the default scroll bars for the control.
+ * Using NO_SCROLL overrides the default and forces the control
+ * to have no scroll bars.
+ *
+ * Used By: Used By: Used By: Used By: Used By:
+ * A sheet window is a window intended to be used as a temporary modal
+ * dialog that is attached to a parent window. It is typically used to
+ * prompt the user before proceeding. The window trim, positioning and
+ * general look of a sheet window is platform specific. For example,
+ * on the Macintosh, at the time this documentation was written, the
+ * window title is not visible.
+ * Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By:
+ * By default, before a widget paints, the client area is filled with the current background.
+ * When this style is specified, the background is not filled, and the application is responsible
+ * for filling every pixel of the client area.
+ * This style might be used as an alternative to "double-buffering" in order to reduce flicker.
+ * This style does not mean "transparent" - widgets that are obscured will not draw through.
+ * Used By:
+ * Normally, when the user clicks on a control, focus is assigned to that
+ * control, providing the control has no children. Some controls, such as
+ * tool bars and sashes, don't normally take focus when the mouse is clicked
+ * or accept focus when assigned from within the program. This style allows
+ * Composites to implement "no focus" mouse behavior.
+ *
+ * Used By:
+ * This style stops the entire client area from being invalidated when the size
+ * of the Canvas changes. Specifically, when the size of the Canvas gets smaller,
+ * the SWT.Paint event is not sent. When it gets bigger, an SWT.Paint event is
+ * sent with a GC clipped to only the new areas to be painted. Without this
+ * style, the entire client area will be repainted.
+ *
+ * Used By: Used By: Used By:
+ * When orientation is not explicitly specified, orientation is
+ * inherited. This means that children will be assigned the
+ * orientation of their parent. To override this behavior and
+ * force an orientation for a child, explicitly set the orientation
+ * of the child when that child is created.
+ * Used By:
+ * When orientation is not explicitly specified, orientation is
+ * inherited. This means that children will be assigned the
+ * orientation of their parent. To override this behavior and
+ * force an orientation for a child, explicitly set the orientation
+ * of the child when that child is created.
+ * Used By: Used By: Used By: Used By: Used By:
+ * By default, before a widget paints, the client area is filled with the current background.
+ * When this style is specified, the background is not filled and widgets that are obscured
+ * will draw through.
+ * Used By:
+ * When the bit is set, text direction mismatches the widget orientation.
+ * Used By:
+ * When the bit is set, text direction is derived from the direction of the
+ * first strong Bidi character.
+ * Used By: Used By: Used By: Used By: Used By: Used By:
+ * If the text color or the underline color are not set in the range
+ * the usage of Used By: Used By: Used By: Used By: Used By: Used By: Used By: Used By:
+ * This constant can also be used to representing the left keyboard
+ * location during a key event.
+ * Used By:
+ * This constant can also be used to representing the right keyboard
+ * location during a key event.
+ * Used By: Used By: Used By: Used By: Used By: Used By: Used By:
+ * A short date displays the month and year.
+ * A short time displays hours and minutes.
+ * Used By:
+ * A medium date displays the day, month and year.
+ * A medium time displays hours, minutes, and seconds.
+ * Used By:
+ * A long date displays the day, month and year.
+ * A long time displays hours, minutes, and seconds.
+ * The day and month names may be displayed.
+ * Used By: Used By: Used By: Used By: Used By: Used By:
+ * {@link #CTRL} on most platforms ({@link #COMMAND} on the Mac).
+ *
+ * {@link #SHIFT} on most platforms.
+ *
+ * {@link #ALT} on most platforms.
+ *
+ * Undefined on most platforms ({@link #CTRL} on the Mac).
+ * Used By: Used By: Used By: Used By: Used By:
+ * This pseudo-color can be used to set a transparent background on SWT
+ * controls. Used By: Used By: Used By: Used By: Used By: Used By:
+ * Note: SWT currently doesn't read or process this property. The only
+ * effect of setting this property is to trigger a call to
+ * {@link Widget#reskin(int) Widget#reskin(SWT.ALL)}.
+ *
+ * Note: SWT currently doesn't read or process this property. The only
+ * effect of setting this property is to trigger a call to
+ * {@link Widget#reskin(int) Widget#reskin(SWT.ALL)}.
+ *
+ * In SWT, errors are reported by throwing one of three exceptions:
+ *
+ * In SWT, errors are reported by throwing one of three exceptions:
+ *
+ * SWTErrors are thrown when something fails internally which
+ * either leaves SWT in an unknown state (eg. the o/s call to
+ * remove an item from a list returns an error code) or when SWT
+ * is left in a known-to-be-unrecoverable state (eg. it runs out
+ * of callback resources). SWTErrors should not occur in typical
+ * programs, although "high reliability" applications should
+ * still catch them.
+ *
+ * This class also provides support methods used by SWT to match
+ * error codes to the appropriate exception class (SWTError,
+ * SWTException, or IllegalArgumentException) and to provide
+ * human readable strings for SWT error codes.
+ *
+ * NOTE: This method overrides Throwable.getCause() that was
+ * added to JDK1.4. It is necessary to override this method
+ * in order for inherited printStackTrace() methods to work.
+ *
+ * It is combined with the message string of the Throwable
+ * which caused this SWTError (if this information is available).
+ *
+ * Note: printStackTrace(PrintStream) and printStackTrace(PrintWriter)
+ * are not provided in order to maintain compatibility with CLDC.
+ *
+ * SWTExceptions are thrown when something fails internally,
+ * but SWT is left in a known stable state (eg. a widget call
+ * was made from a non-u/i thread, or there is failure while
+ * reading an Image because the source file was corrupt).
+ *
+ * NOTE: This method overrides Throwable.getCause() that was
+ * added to JDK1.4. It is necessary to override this method
+ * in order for inherited printStackTrace() methods to work.
+ *
+ * It is combined with the message string of the Throwable
+ * which caused this SWTException (if this information is available).
+ *
+ * Note: printStackTrace(PrintStream) and printStackTrace(PrintWriter)
+ * are not provided in order to maintain compatibility with CLDC.
+ *
+ * The eventData object is an array of 2 ints specifying the following:
+ * Note: only send one notification for the topmost object that has changed.
+ *
+ * The eventData object is an array of 2 Numbers specifying the following:
+ * The eventData object is an Integer that represents the index of the selected link
+ * in the hypertext object.
+ *
+ * The eventData object is an array of 5 ints specifying the following:
+ * The eventData object is an array of 4 objects specifying the following:About This Content
+
+License
+
+Third Party Content
+
+Independent JPEG Group's JPEG software release 6b
+
+
+
+
+
+
+
+
+
+
+PuTTY 0.58 (derivative work)
+
+
+
+
+ *
+ *
+ * @see org.eclipse.swt.widgets.Widget#addListener
+ * @see org.eclipse.swt.widgets.Display#addFilter
+ * @see org.eclipse.swt.widgets.Event
+ *
+ * @since 3.4
+ */
+ public static final int ImeComposition = 43;
+
+ /**
+ * The orientation change event type (value is 44).
+ * doit
field
+ * of the event to stop the change from happening.
+ * Shell
when the SWT zoom has changed. The SWT
+ * zoom changes when the operating system DPI or scale factor changes dynamically.
+ *
+ *
+ *
+ * @see org.eclipse.swt.widgets.Composite#layout(org.eclipse.swt.widgets.Control[], int)
+ *
+ * @since 3.6
+ */
+ public static final int CHANGED = 1 << 1;
+
+ /**
+ * A constant indicating that a given operation should be deferred.
+ * (value is 1<<2).
+ *
+ * Composite
layout
+ *
+ *
+ * @see org.eclipse.swt.widgets.Composite#layout(org.eclipse.swt.widgets.Control[], int)
+ *
+ * @since 3.6
+ */
+ public static final int DEFER = 1 << 2;
+
+ /**
+ * A constant known to be zero (0), typically used in operations
+ * which take bit flags to indicate that "no bits are set".
+ */
+ public static final int NONE = 0;
+
+ /**
+ * A constant known to be zero (0), used in operations which
+ * take pointers to indicate a null argument.
+ */
+ public static final int NULL = 0;
+
+ /**
+ * Indicates that a default should be used (value is -1).
+ */
+ public static final int DEFAULT = -1;
+
+ /**
+ * Indicates that a property is off (value is 0).
+ *
+ * @since 3.1
+ */
+ public static final int OFF = 0;
+
+ /**
+ * Indicates that a property is on (value is 1).
+ *
+ * @since 3.1
+ */
+ public static final int ON = 1;
+
+ /**
+ * Indicates low quality (value is 1).
+ *
+ * @since 3.1
+ */
+ public static final int LOW = 1;
+
+ /**
+ * Indicates high quality (value is 2).
+ *
+ * @since 3.1
+ */
+ public static final int HIGH = 2;
+
+ /**
+ * Style constant for menu bar behavior (value is 1<<1).
+ * Composite
layout
+ *
+ */
+ public static final int BAR = 1 << 1;
+
+ /**
+ * Style constant for drop down menu/list behavior (value is 1<<2).
+ * Menu
+ *
+ */
+ public static final int DROP_DOWN = 1 << 2;
+
+ /**
+ * Style constant for pop up menu behavior (value is 1<<3).
+ * Menu
ToolItem
CoolItem
Combo
DateTime
+ *
+ */
+ public static final int POP_UP = 1 << 3;
+
+ /**
+ * Style constant for line separator behavior (value is 1<<1).
+ * Menu
+ *
+ */
+ public static final int SEPARATOR = 1 << 1;
+
+ /**
+ * Constant representing a flexible space separator in a ToolBar.
+ * Label
MenuItem
ToolItem
+ *
+ *
+ * @since 3.7
+ */
+ public static final int SEPARATOR_FILL = -2;
+
+ /**
+ * Style constant for toggle button behavior (value is 1<<1).
+ * ToolItem.setWidth()
+ *
+ */
+ public static final int TOGGLE = 1 << 1;
+
+ /**
+ * Style constant for arrow button behavior (value is 1<<2).
+ * Button
+ *
+ */
+ public static final int ARROW = 1 << 2;
+
+ /**
+ * Style constant for push button behavior (value is 1<<3).
+ * Button
+ *
+ */
+ public static final int PUSH = 1 << 3;
+
+ /**
+ * Style constant for radio button behavior (value is 1<<4).
+ * Button
MenuItem
ToolItem
+ *
+ */
+ public static final int RADIO = 1 << 4;
+
+ /**
+ * Style constant for check box behavior (value is 1<<5).
+ * Button
MenuItem
ToolItem
+ *
+ */
+ public static final int CHECK = 1 << 5;
+
+ /**
+ * Style constant for cascade behavior (value is 1<<6).
+ * Button
MenuItem
ToolItem
Table
Tree
+ *
+ */
+ public static final int CASCADE = 1 << 6;
+
+ /**
+ * Style constant for multi-selection behavior in lists
+ * and multiple line support on text fields (value is 1<<1).
+ * MenuItem
+ *
+ */
+ public static final int MULTI = 1 << 1;
+
+ /**
+ * Style constant for single selection behavior in lists
+ * and single line support on text fields (value is 1<<2).
+ * Text
List
Table
Tree
FileDialog
+ *
+ */
+ public static final int SINGLE = 1 << 2;
+
+ /**
+ * Style constant for read-only behavior (value is 1<<3).
+ * Text
List
Table
Tree
+ *
+ */
+ public static final int READ_ONLY = 1 << 3;
+
+ /**
+ * Style constant for automatic line wrap behavior (value is 1<<6).
+ * Combo
Text
+ *
+ */
+ public static final int WRAP = 1 << 6;
+
+ /**
+ * Style constant for search behavior (value is 1<<7).
+ * Button
Label
Text
ToolBar
Spinner
+ *
+ *
+ * @since 3.3
+ */
+ public static final int SEARCH = 1 << 7;
+
+ /**
+ * Style constant for simple (not drop down) behavior (value is 1<<6).
+ * Text
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int SIMPLE = 1 << 6;
+
+ /**
+ * Style constant for password behavior (value is 1<<22).
+ * Combo
+ *
+ *
+ * @since 3.0
+ */
+ public static final int PASSWORD = 1 << 22;
+
+ /**
+ * Style constant for shadow in behavior (value is 1<<2).
+ * Text
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int SHADOW_IN = 1 << 2;
+
+ /**
+ * Style constant for shadow out behavior (value is 1<<3).
+ * Label
Group
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int SHADOW_OUT = 1 << 3;
+
+ /**
+ * Style constant for shadow etched in behavior (value is 1<<4).
+ * Label
Group
ToolBar
Note that this is a HINT. It is currently ignored on all platforms.
+ *
+ *
+ */
+ public static final int SHADOW_ETCHED_IN = 1 << 4;
+
+ /**
+ * Style constant for shadow etched out behavior (value is 1<<6).
+ * Group
Note that this is a HINT. It is currently ignored on all platforms.
+ *
+ *
+ */
+ public static final int SHADOW_ETCHED_OUT = 1 << 6;
+
+ /**
+ * Style constant for no shadow behavior (value is 1<<5).
+ * Group
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int SHADOW_NONE = 1 << 5;
+
+ /**
+ * Style constant for progress bar behavior (value is 1<<1).
+ * Label
Group
+ *
+ */
+ public static final int INDETERMINATE = 1 << 1;
+
+ /**
+ * Style constant for tool window behavior (value is 1<<2).
+ * ProgressBar
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int TOOL = 1 << 2;
+
+ /**
+ * Style constant to ensure no trimmings are used (value is 1<<3).
+ * Decorations
and subclasses
Note that this overrides all other trim styles.
+ *
+ *
+ */
+ public static final int NO_TRIM = 1 << 3;
+
+ /**
+ * Style constant for resize box trim (value is 1<<4).
+ * Decorations
and subclasses
+ *
+ */
+ public static final int RESIZE = 1 << 4;
+
+ /**
+ * Style constant for title area trim (value is 1<<5).
+ * Decorations
and subclassesTracker
+ *
+ */
+ public static final int TITLE = 1 << 5;
+
+ /**
+ * Style constant for close box trim (value is 1<<6,
+ * since we do not distinguish between CLOSE style and MENU style).
+ * Decorations
and subclasses
+ *
+ */
+ public static final int CLOSE = 1 << 6;
+
+ /**
+ * Style constant for shell menu trim (value is 1<<6,
+ * since we do not distinguish between CLOSE style and MENU style).
+ * Decorations
and subclasses
+ *
+ */
+ public static final int MENU = CLOSE;
+
+ /**
+ * Style constant for minimize box trim (value is 1<<7).
+ * Decorations
and subclasses
+ *
+ */
+ public static final int MIN = 1 << 7;
+
+ /**
+ * Style constant for maximize box trim (value is 1<<10).
+ * Decorations
and subclasses
+ *
+ */
+ public static final int MAX = 1 << 10;
+
+ /**
+ * Style constant for the no move behavior (value is 1<<23).
+ * Creates the title trim when no other trim style is specified.
+ * Doesn't create the title trim when NO_TRIM is specified.
+ * Decorations
and subclasses
+ *
+ * @since 3.105
+ */
+ public static final int NO_MOVE = 1 << 23;
+
+ /**
+ * Style constant for horizontal scrollbar behavior (value is 1<<8).
+ * Shell
+ *
+ */
+ public static final int H_SCROLL = 1 << 8;
+
+ /**
+ * Style constant for vertical scrollbar behavior (value is 1<<9).
+ * Scrollable
and subclasses
+ *
+ */
+ public static final int V_SCROLL = 1 << 9;
+
+ /**
+ * Style constant for no scrollbar behavior (value is 1<<4).
+ * Scrollable
and subclasses
+ *
+ *
+ * @since 3.4
+ */
+ public static final int NO_SCROLL = 1 << 4;
+
+ /**
+ * Style constant for bordered behavior (value is 1<<11).
+ * Tree
Table
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int BORDER = 1 << 11;
+
+ /**
+ * Style constant indicating that the window manager should clip
+ * a widget's children with respect to its viewable area. (value is 1<<12).
+ * Control
and subclasses
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int CLIP_CHILDREN = 1 << 12;
+
+ /**
+ * Style constant indicating that the window manager should clip
+ * a widget's siblings with respect to its viewable area. (value is 1<<13).
+ * Control
and subclasses
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int CLIP_SIBLINGS = 1 << 13;
+
+ /**
+ * Style constant for always on top behavior (value is 1<<14).
+ * Control
and subclasses
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int ON_TOP = 1 << 14;
+
+ /**
+ * Style constant for sheet window behavior (value is 1<<28).
+ * Shell
and subclasses
Note that this is a HINT.
+ *
+ *
+ *
+ * @since 3.5
+ */
+ public static final int SHEET = 1 << 28;
+
+ /**
+ * Trim style convenience constant for the most common top level shell appearance
+ * (value is CLOSE|TITLE|MIN|MAX|RESIZE).
+ * Dialog
and subclassesShell
and subclasses
+ *
+ */
+ public static final int SHELL_TRIM = CLOSE | TITLE | MIN | MAX | RESIZE;
+
+ /**
+ * Trim style convenience constant for the most common dialog shell appearance
+ * (value is CLOSE|TITLE|BORDER).
+ * Shell
+ *
+ */
+ public static final int DIALOG_TRIM = TITLE | CLOSE | BORDER;
+
+ /**
+ * Style constant for modeless behavior (value is 0).
+ * Shell
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int MODELESS = 0;
+
+ /**
+ * Style constant for primary modal behavior (value is 1<<15).
+ * Dialog
Shell
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int PRIMARY_MODAL = 1 << 15;
+
+ /**
+ * Style constant for application modal behavior (value is 1<<16).
+ * Dialog
Shell
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int APPLICATION_MODAL = 1 << 16;
+
+ /**
+ * Style constant for system modal behavior (value is 1<<17).
+ * Dialog
Shell
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int SYSTEM_MODAL = 1 << 17;
+
+ /**
+ * Style constant for selection hiding behavior when the widget loses focus (value is 1<<15).
+ * Dialog
Shell
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int HIDE_SELECTION = 1 << 15;
+
+ /**
+ * Style constant for full row selection behavior and
+ * selection constant indicating that a full line should be
+ * drawn. (value is 1<<16).
+ * Table
Note that for some widgets this is a HINT.
+ *
+ *
+ */
+ public static final int FULL_SELECTION = 1 << 16;
+
+ /**
+ * Style constant for flat appearance. (value is 1<<23).
+ * Table
Tree
StyledText
TextLayout
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int FLAT = 1 << 23;
+
+ /**
+ * Style constant for smooth appearance. (value is 1<<16).
+ * Button
ToolBar
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int SMOOTH = 1 << 16;
+
+ /**
+ * Style constant for no background behavior (value is 1<<18).
+ * ProgressBar
Sash
+ *
+ */
+ public static final int NO_BACKGROUND = 1 << 18;
+
+ /**
+ * Style constant for no focus from the mouse behavior (value is 1<<19).
+ * Composite
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int NO_FOCUS = 1 << 19;
+
+ /**
+ * Style constant for no redraw on resize behavior (value is 1<<20).
+ * Composite
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int NO_REDRAW_RESIZE = 1 << 20;
+
+ /**
+ * Style constant for no paint event merging behavior (value is 1<<21).
+ *
+ * Composite
Note that this is a HINT.
+ *
+ *
+ */
+ public static final int NO_MERGE_PAINTS = 1 << 21;
+
+ /**
+ * Style constant for preventing child radio group behavior (value is 1<<22).
+ * Composite
+ *
+ */
+ public static final int NO_RADIO_GROUP = 1 << 22;
+
+ /**
+ * Style constant for left to right orientation (value is 1<<25).
+ * Composite
Menu
Note that this is a HINT.
+ *
+ *
+ *
+ * @since 2.1.2
+ */
+ public static final int LEFT_TO_RIGHT = 1 << 25;
+
+ /**
+ * Style constant for right to left orientation (value is 1<<26).
+ * Control
Menu
GC
Note that this is a HINT.
+ *
+ *
+ *
+ * @since 2.1.2
+ */
+ public static final int RIGHT_TO_LEFT = 1 << 26;
+
+ /**
+ * Style constant to indicate coordinate mirroring (value is 1<<27).
+ * Control
Menu
GC
+ *
+ *
+ * @since 2.1.2
+ */
+ public static final int MIRRORED = 1 << 27;
+
+ /**
+ * Style constant to allow embedding (value is 1<<24).
+ * Control
Menu
+ *
+ *
+ * @since 3.0
+ */
+ public static final int EMBEDDED = 1 << 24;
+
+ /**
+ * Style constant to allow virtual data (value is 1<<28).
+ * Composite
+ *
+ *
+ * @since 3.0
+ */
+ public static final int VIRTUAL = 1 << 28;
+
+ /**
+ * Style constant to indicate double buffering (value is 1<<29).
+ * Table
Tree
+ *
+ *
+ * @since 3.1
+ */
+ public static final int DOUBLE_BUFFERED = 1 << 29;
+
+ /**
+ * Style constant for transparent behavior (value is 1<<30).
+ * Control
+ *
+ *
+ * @since 3.4
+ *
+ * WARNING: THIS API IS UNDER CONSTRUCTION AND SHOULD NOT BE USED
+ */
+ public static final int TRANSPARENT = 1 << 30;
+
+ /**
+ * Style constant to indicate base text direction (value is 1<<31).
+ * Composite
Note that this is a HINT.
+ *
+ *
+ *
+ * @see org.eclipse.swt.widgets.Control#setTextDirection(int)
+ * @see org.eclipse.swt.widgets.Control#getTextDirection()
+ *
+ * @since 3.102
+ */
+ public static final int FLIP_TEXT_DIRECTION = 1 << 31;
+
+ /**
+ * A bit mask to indicate Bidi "auto" text direction.
+ * Control
Note that this is a HINT and it works on Windows only.
+ *
+ *
+ *
+ * @see org.eclipse.swt.widgets.Control#setTextDirection(int)
+ * @see org.eclipse.swt.graphics.TextLayout#setTextDirection(int)
+ *
+ * @since 3.105
+ */
+ public static final int AUTO_TEXT_DIRECTION = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+
+ /**
+ * Style constant for align up behavior (value is 1<<7,
+ * since align UP and align TOP are considered the same).
+ * Control
TextLayout
+ *
+ */
+ public static final int UP = 1 << 7;
+
+ /**
+ * Style constant to indicate single underline (value is 0).
+ * Button
with ARROW
styleTracker
Table
Tree
+ *
+ *
+ * @since 3.4
+ */
+ public static final int UNDERLINE_SINGLE = 0;
+
+ /**
+ * Style constant to indicate double underline (value is 1).
+ * TextStyle
+ *
+ *
+ * @since 3.4
+ */
+ public static final int UNDERLINE_DOUBLE = 1;
+
+ /**
+ * Style constant to indicate error underline (value is 2).
+ * TextStyle
+ *
+ *
+ * @since 3.4
+ */
+ public static final int UNDERLINE_ERROR = 2;
+
+ /**
+ * Style constant to indicate squiggle underline (value is 3).
+ * TextStyle
+ *
+ *
+ * @since 3.4
+ */
+ public static final int UNDERLINE_SQUIGGLE = 3;
+
+ /**
+ * Style constant to indicate link underline (value is 0).
+ * TextStyle
UNDERLINE_LINK
will change these colors
+ * to the preferred link color of the platform.
+ * Note that clients that use this style, such as StyledText
,
+ * will include code to track the mouse and change the cursor to the hand
+ * cursor when mouse is over the link.
+ *
+ *
+ *
+ * @since 3.5
+ */
+ public static final int UNDERLINE_LINK = 4;
+
+ /**
+ * Style constant to indicate solid border (value is 1).
+ * TextStyle
+ *
+ *
+ * @since 3.4
+ */
+ public static final int BORDER_SOLID = 1;
+
+ /**
+ * Style constant to indicate dashed border (value is 2).
+ * TextStyle
+ *
+ *
+ * @since 3.4
+ */
+ public static final int BORDER_DASH = 2;
+
+ /**
+ * Style constant to indicate dotted border (value is 4).
+ * TextStyle
+ *
+ *
+ * @since 3.4
+ */
+ public static final int BORDER_DOT = 4;
+
+ /**
+ * Style constant for align top behavior (value is 1<<7,
+ * since align UP and align TOP are considered the same).
+ * TextStyle
+ *
+ */
+ public static final int TOP = UP;
+
+ /**
+ * Style constant for align down behavior (value is 1<<10,
+ * since align DOWN and align BOTTOM are considered the same).
+ * FormAttachment
in a FormLayout
+ *
+ */
+ public static final int DOWN = 1 << 10;
+
+ /**
+ * Style constant for align bottom behavior (value is 1<<10,
+ * since align DOWN and align BOTTOM are considered the same).
+ * Button
with ARROW
styleTracker
Table
Tree
+ *
+ */
+ public static final int BOTTOM = DOWN;
+
+ /**
+ * Style constant for leading alignment (value is 1<<14).
+ * FormAttachment
in a FormLayout
TabFolder
+ *
+ *
+ * @since 2.1.2
+ */
+ public static final int LEAD = 1 << 14;
+
+ /**
+ * Style constant for align left behavior (value is 1<<14).
+ * This is a synonym for {@link #LEAD} (value is 1<<14). Newer
+ * applications should use {@link #LEAD} instead of {@link #LEFT} to make code more
+ * understandable on right-to-left platforms.
+ * Button
Label
Text
TableColumn
TreeColumn
Tracker
FormAttachment
in a FormLayout
+ *
+ *
+ * @since 2.1.2
+ */
+ public static final int TRAIL = 1 << 17;
+
+ /**
+ * Style constant for align right behavior (value is 1<<17).
+ * This is a synonym for {@link #TRAIL} (value is 1<<17). Newer
+ * applications should use {@link #TRAIL} instead of {@link #RIGHT} to make code more
+ * understandable on right-to-left platforms.
+ * Button
Label
Text
TableColumn
TreeColumn
Tracker
FormAttachment
in a FormLayout
+ *
+ */
+ public static final int CENTER = 1 << 24;
+
+ /**
+ * Style constant for horizontal alignment or orientation behavior (value is 1<<8).
+ * Button
Label
TableColumn
FormAttachment
in a FormLayout
+ *
+ */
+ public static final int HORIZONTAL = 1 << 8;
+
+ /**
+ * Style constant for vertical alignment or orientation behavior (value is 1<<9).
+ * Label
ProgressBar
Sash
Scale
ScrollBar
Slider
ToolBar
FillLayout
typeRowLayout
type
+ *
+ */
+ public static final int VERTICAL = 1 << 9;
+
+ /**
+ * Style constant for date display (value is 1<<5).
+ * Label
ProgressBar
Sash
Scale
ScrollBar
Slider
ToolBar
CoolBar
FillLayout
typeRowLayout
type
+ *
+ *
+ * @since 3.3
+ */
+ public static final int DATE = 1 << 5;
+
+ /**
+ * Style constant for time display (value is 1<<7).
+ * DateTime
+ *
+ *
+ * @since 3.3
+ */
+ public static final int TIME = 1 << 7;
+
+ /**
+ * Style constant for calendar display (value is 1<<10).
+ * DateTime
+ *
+ *
+ * @since 3.3
+ */
+ public static final int CALENDAR = 1 << 10;
+
+ /**
+ * Style constant for displaying week numbers in the calendar.
+ * DateTime
Note that this is a HINT and is supported on Windows & GTK platforms only.
+ *
+ *
+ *
+ * @since 3.108
+ */
+ public static final int CALENDAR_WEEKNUMBERS = 1 << 14;
+
+ /**
+ * Style constant for short date/time format (value is 1<<15).
+ * DateTime
Note that this is a HINT.
+ *
+ *
+ *
+ * @since 3.3
+ */
+ public static final int SHORT = 1 << 15;
+
+ /**
+ * Style constant for medium date/time format (value is 1<<16).
+ * DateTime
Note that this is a HINT.
+ *
+ *
+ *
+ * @since 3.3
+ */
+ public static final int MEDIUM = 1 << 16;
+
+ /**
+ * Style constant for long date/time format (value is 1<<28).
+ * DateTime
Note that this is a HINT.
+ *
+ *
+ *
+ * @since 3.3
+ */
+ public static final int LONG = 1 << 28;
+
+ /**
+ * Style constant specifying that a Browser should use a Mozilla GRE
+ * for rendering its content (value is 1<<15).
+ * DateTime
+ *
+ *
+ * @since 3.3
+ * @deprecated This style is deprecated and will be removed in the future.
+ * XULRunner as a browser renderer is no longer supported. Use
+ * Browser
SWT.WEBKIT
or SWT.NONE
instead.
+ */
+ @Deprecated
+ public static final int MOZILLA = 1 << 15;
+
+ /**
+ * Style constant specifying that a Browser should use WebKit
+ * for rendering its content (value is 1<<16).
+ *
+ *
+ *
+ * @since 3.7
+ */
+ public static final int WEBKIT = 1 << 16;
+
+ /**
+ * Style constant for balloon behavior (value is 1<<12).
+ * Browser
+ *
+ *
+ * @since 3.2
+ */
+ public static final int BALLOON = 1 << 12;
+
+ /**
+ * Style constant for vertical alignment or orientation behavior (value is 1).
+ * ToolTip
+ *
+ */
+ public static final int BEGINNING = 1;
+
+ /**
+ * Style constant for vertical alignment or orientation behavior (value is 4).
+ * GridLayout
type
+ *
+ */
+ public static final int FILL = 4;
+
+ /**
+ * Input Method Editor style constant for double byte
+ * input behavior (value is 1<<1).
+ */
+ public static final int DBCS = 1 << 1;
+
+ /**
+ * Input Method Editor style constant for alpha
+ * input behavior (value is 1<<2).
+ */
+ public static final int ALPHA = 1 << 2;
+
+ /**
+ * Input Method Editor style constant for native
+ * input behavior (value is 1<<3).
+ */
+ public static final int NATIVE = 1 << 3;
+
+ /**
+ * Input Method Editor style constant for phonetic
+ * input behavior (value is 1<<4).
+ */
+ public static final int PHONETIC = 1 << 4;
+
+ /**
+ * Input Method Editor style constant for romanicized
+ * input behavior (value is 1<<5).
+ */
+ public static final int ROMAN = 1 << 5;
+
+ /**
+ * ASCII character convenience constant for the backspace character
+ * (value is the GridLayout
typechar
'\b').
+ */
+ public static final char BS = '\b';
+
+ /**
+ * ASCII character convenience constant for the carriage return character
+ * (value is the char
'\r').
+ */
+ public static final char CR = '\r';
+
+ /**
+ * ASCII character convenience constant for the delete character
+ * (value is the char
with value 127).
+ */
+ public static final char DEL = 0x7F;
+
+ /**
+ * ASCII character convenience constant for the escape character
+ * (value is the char
with value 27).
+ */
+ public static final char ESC = 0x1B;
+
+ /**
+ * ASCII character convenience constant for the line feed character
+ * (value is the char
'\n').
+ */
+ public static final char LF = '\n';
+
+ /**
+ * ASCII character convenience constant for the tab character
+ * (value is the char
'\t').
+ *
+ * @since 2.1
+ */
+ public static final char TAB = '\t';
+
+ /**
+ * ASCII character convenience constant for the space character
+ * (value is the char
' ').
+ *
+ * @since 3.7
+ */
+ public static final char SPACE = ' ';
+
+ /**
+ * Keyboard and/or mouse event mask indicating that the ALT_GR key
+ * was pushed on the keyboard when the event was generated
+ * (value is 1 << 15).
+ *
+ * @since 3.108
+ */
+ public static final int ALT_GR = 1 << 15;
+
+ /**
+ * keyboard and/or mouse event mask indicating that the ALT key
+ * was pushed on the keyboard when the event was generated
+ * (value is 1<<16).
+ */
+ public static final int ALT = 1 << 16;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that the SHIFT key
+ * was pushed on the keyboard when the event was generated
+ * (value is 1<<17).
+ */
+ public static final int SHIFT = 1 << 17;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that the CTRL key
+ * was pushed on the keyboard when the event was generated
+ * (value is 1<<18).
+ */
+ public static final int CTRL = 1 << 18;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that the CTRL key
+ * was pushed on the keyboard when the event was generated. This
+ * is a synonym for CTRL (value is 1<<18).
+ */
+ public static final int CONTROL = CTRL;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that the COMMAND key
+ * was pushed on the keyboard when the event was generated
+ * (value is 1<<22).
+ *
+ * @since 2.1
+ */
+ public static final int COMMAND = 1 << 22;
+
+ /**
+ * Keyboard and/or mouse event mask indicating all possible
+ * keyboard modifiers.
+ *
+ * To allow for the future, this mask is intended to be used in
+ * place of code that references each individual keyboard mask.
+ * For example, the following expression will determine whether
+ * any modifier is pressed and will continue to work as new modifier
+ * masks are added.
+ *
+ * (stateMask & SWT.MODIFIER_MASK) != 0
.
+ *
+ * @since 2.1
+ */
+ public static final int MODIFIER_MASK;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that mouse button one (usually 'left')
+ * was pushed when the event was generated. (value is 1<<19).
+ */
+ public static final int BUTTON1 = 1 << 19;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that mouse button two (usually 'middle')
+ * was pushed when the event was generated. (value is 1<<20).
+ */
+ public static final int BUTTON2 = 1 << 20;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that mouse button three (usually 'right')
+ * was pushed when the event was generated. (value is 1<<21).
+ */
+ public static final int BUTTON3 = 1 << 21;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that mouse button four
+ * was pushed when the event was generated. (value is 1<<23).
+ *
+ * @since 3.1
+ */
+ public static final int BUTTON4 = 1 << 23;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that mouse button five
+ * was pushed when the event was generated. (value is 1<<25).
+ *
+ * @since 3.1
+ */
+ public static final int BUTTON5 = 1 << 25;
+
+ /**
+ * Keyboard and/or mouse event mask indicating all possible
+ * mouse buttons.
+ *
+ * To allow for the future, this mask is intended to be used
+ * in place of code that references each individual button mask.
+ * For example, the following expression will determine whether
+ * any button is pressed and will continue to work as new button
+ * masks are added.
+ *
+ * (stateMask & SWT.BUTTON_MASK) != 0
.
+ *
+ * @since 2.1
+ */
+ public static final int BUTTON_MASK;
+
+ /**
+ * Keyboard and/or mouse event mask indicating that the MOD1 key
+ * was pushed on the keyboard when the event was generated.
+ *
+ * This is the primary keyboard modifier for the platform.
+ *
+ *
+ *
+ * @since 3.1
+ */
+ public static final int SCROLL_LINE = 1;
+
+ /**
+ * Constants to indicate page scrolling (value is 2).
+ * Control
+ *
+ *
+ * @since 3.1
+ */
+ public static final int SCROLL_PAGE = 2;
+
+ /**
+ * Accelerator constant used to differentiate a key code from a
+ * unicode character.
+ *
+ * If this bit is set, then the key stroke
+ * portion of an accelerator represents a key code. If this bit
+ * is not set, then the key stroke portion of an accelerator is
+ * a unicode character.
+ *
+ * The following expression is false:
+ *
+ * Control
((SWT.MOD1 | SWT.MOD2 | 'T') & SWT.KEYCODE_BIT) != 0
.
+ *
+ * The following expression is true:
+ *
+ * ((SWT.MOD3 | SWT.F2) & SWT.KEYCODE_BIT) != 0
.
+ *
+ * (value is (1<<24))
+ *
+ * @since 2.1
+ */
+ public static final int KEYCODE_BIT = (1 << 24);
+
+ /**
+ * Accelerator constant used to extract the key stroke portion of
+ * an accelerator.
+ *
+ * The key stroke may be a key code or a unicode
+ * value. If the key stroke is a key code KEYCODE_BIT
+ * will be set.
+ *
+ * @since 2.1
+ */
+ public static final int KEY_MASK = KEYCODE_BIT + 0xFFFF;
+
+ /**
+ * Keyboard event constant representing the UP ARROW key
+ * (value is (1<<24)+1).
+ */
+ public static final int ARROW_UP = KEYCODE_BIT + 1;
+
+ /**
+ * Keyboard event constant representing the DOWN ARROW key
+ * (value is (1<<24)+2).
+ */
+ public static final int ARROW_DOWN = KEYCODE_BIT + 2;
+
+ /**
+ * Keyboard event constant representing the LEFT ARROW key
+ * (value is (1<<24)+3).
+ */
+ public static final int ARROW_LEFT = KEYCODE_BIT + 3;
+
+ /**
+ * Keyboard event constant representing the RIGHT ARROW key
+ * (value is (1<<24)+4).
+ */
+ public static final int ARROW_RIGHT = KEYCODE_BIT + 4;
+
+ /**
+ * Keyboard event constant representing the PAGE UP key
+ * (value is (1<<24)+5).
+ */
+ public static final int PAGE_UP = KEYCODE_BIT + 5;
+
+ /**
+ * Keyboard event constant representing the PAGE DOWN key
+ * (value is (1<<24)+6).
+ */
+ public static final int PAGE_DOWN = KEYCODE_BIT + 6;
+
+ /**
+ * Keyboard event constant representing the HOME key
+ * (value is (1<<24)+7).
+ */
+ public static final int HOME = KEYCODE_BIT + 7;
+
+ /**
+ * Keyboard event constant representing the END key
+ * (value is (1<<24)+8).
+ */
+ public static final int END = KEYCODE_BIT + 8;
+
+ /**
+ * Keyboard event constant representing the INSERT key
+ * (value is (1<<24)+9).
+ */
+ public static final int INSERT = KEYCODE_BIT + 9;
+
+ /**
+ * Keyboard event constant representing the F1 key
+ * (value is (1<<24)+10).
+ */
+ public static final int F1 = KEYCODE_BIT + 10;
+
+ /**
+ * Keyboard event constant representing the F2 key
+ * (value is (1<<24)+11).
+ */
+ public static final int F2 = KEYCODE_BIT + 11;
+
+ /**
+ * Keyboard event constant representing the F3 key
+ * (value is (1<<24)+12).
+ */
+ public static final int F3 = KEYCODE_BIT + 12;
+
+ /**
+ * Keyboard event constant representing the F4 key
+ * (value is (1<<24)+13).
+ */
+ public static final int F4 = KEYCODE_BIT + 13;
+
+ /**
+ * Keyboard event constant representing the F5 key
+ * (value is (1<<24)+14).
+ */
+ public static final int F5 = KEYCODE_BIT + 14;
+
+ /**
+ * Keyboard event constant representing the F6 key
+ * (value is (1<<24)+15).
+ */
+ public static final int F6 = KEYCODE_BIT + 15;
+
+ /**
+ * Keyboard event constant representing the F7 key
+ * (value is (1<<24)+16).
+ */
+ public static final int F7 = KEYCODE_BIT + 16;
+
+ /**
+ * Keyboard event constant representing the F8 key
+ * (value is (1<<24)+17).
+ */
+ public static final int F8 = KEYCODE_BIT + 17;
+
+ /**
+ * Keyboard event constant representing the F9 key
+ * (value is (1<<24)+18).
+ */
+ public static final int F9 = KEYCODE_BIT + 18;
+
+ /**
+ * Keyboard event constant representing the F10 key
+ * (value is (1<<24)+19).
+ */
+ public static final int F10 = KEYCODE_BIT + 19;
+
+ /**
+ * Keyboard event constant representing the F11 key
+ * (value is (1<<24)+20).
+ */
+ public static final int F11 = KEYCODE_BIT + 20;
+
+ /**
+ * Keyboard event constant representing the F12 key
+ * (value is (1<<24)+21).
+ */
+ public static final int F12 = KEYCODE_BIT + 21;
+
+ /**
+ * Keyboard event constant representing the F13 key
+ * (value is (1<<24)+22).
+ *
+ * @since 3.0
+ */
+ public static final int F13 = KEYCODE_BIT + 22;
+
+ /**
+ * Keyboard event constant representing the F14 key
+ * (value is (1<<24)+23).
+ *
+ * @since 3.0
+ */
+ public static final int F14 = KEYCODE_BIT + 23;
+
+ /**
+ * Keyboard event constant representing the F15 key
+ * (value is (1<<24)+24).
+ *
+ * @since 3.0
+ */
+ public static final int F15 = KEYCODE_BIT + 24;
+
+ /**
+ * Keyboard event constant representing the F16 key
+ * (value is (1<<25)+25).
+ *
+ * @since 3.6
+ */
+ public static final int F16 = KEYCODE_BIT + 25;
+
+
+ /**
+ * Keyboard event constant representing the F17 key
+ * (value is (1<<26)+26).
+ *
+ * @since 3.6
+ */
+ public static final int F17 = KEYCODE_BIT + 26;
+
+
+ /**
+ * Keyboard event constant representing the F18 key
+ * (value is (1<<27)+27).
+ *
+ * @since 3.6
+ */
+ public static final int F18 = KEYCODE_BIT + 27;
+
+
+ /**
+ * Keyboard event constant representing the F19 key
+ * (value is (1<<28)+28).
+ *
+ * @since 3.6
+ */
+ public static final int F19 = KEYCODE_BIT + 28;
+
+ /**
+ * Keyboard event constant representing the F20 key
+ * (value is (1<<29)+29).
+ *
+ * @since 3.6
+ */
+ public static final int F20 = KEYCODE_BIT + 29;
+
+ /**
+ * Keyboard event constant representing the keypad location.
+ * (value is 1<<1).
+ *
+ * @since 3.6
+ */
+ public static final int KEYPAD = 1 << 1;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad multiply key (value is (1<<24)+42).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_MULTIPLY = KEYCODE_BIT + 42;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad add key (value is (1<<24)+43).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_ADD = KEYCODE_BIT + 43;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad subtract key (value is (1<<24)+45).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_SUBTRACT = KEYCODE_BIT + 45;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad decimal key (value is (1<<24)+46).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_DECIMAL = KEYCODE_BIT + 46;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad divide key (value is (1<<24)+47).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_DIVIDE = KEYCODE_BIT + 47;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad zero key (value is (1<<24)+48).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_0 = KEYCODE_BIT + 48;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad one key (value is (1<<24)+49).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_1 = KEYCODE_BIT + 49;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad two key (value is (1<<24)+50).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_2 = KEYCODE_BIT + 50;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad three key (value is (1<<24)+51).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_3 = KEYCODE_BIT + 51;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad four key (value is (1<<24)+52).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_4 = KEYCODE_BIT + 52;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad five key (value is (1<<24)+53).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_5 = KEYCODE_BIT + 53;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad six key (value is (1<<24)+54).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_6 = KEYCODE_BIT + 54;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad seven key (value is (1<<24)+55).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_7 = KEYCODE_BIT + 55;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad eight key (value is (1<<24)+56).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_8 = KEYCODE_BIT + 56;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad nine key (value is (1<<24)+57).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_9 = KEYCODE_BIT + 57;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad equal key (value is (1<<24)+61).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_EQUAL = KEYCODE_BIT + 61;
+
+ /**
+ * Keyboard event constant representing the numeric key
+ * pad enter key (value is (1<<24)+80).
+ *
+ * @since 3.0
+ */
+ public static final int KEYPAD_CR = KEYCODE_BIT + 80;
+
+ /**
+ * Keyboard event constant representing the help
+ * key (value is (1<<24)+81).
+ *
+ * NOTE: The HELP key maps to the key labeled "help",
+ * not "F1". If your keyboard does not have a HELP key,
+ * you will never see this key press. To listen for
+ * help on a control, use SWT.Help.
+ *
+ * @since 3.0
+ *
+ * @see SWT#Help
+ */
+ public static final int HELP = KEYCODE_BIT + 81;
+
+ /**
+ * Keyboard event constant representing the caps
+ * lock key (value is (1<<24)+82).
+ *
+ * @since 3.0
+ */
+ public static final int CAPS_LOCK = KEYCODE_BIT + 82;
+
+ /**
+ * Keyboard event constant representing the num
+ * lock key (value is (1<<24)+83).
+ *
+ * @since 3.0
+ */
+ public static final int NUM_LOCK = KEYCODE_BIT + 83;
+
+ /**
+ * Keyboard event constant representing the scroll
+ * lock key (value is (1<<24)+84).
+ *
+ * @since 3.0
+ */
+ public static final int SCROLL_LOCK = KEYCODE_BIT + 84;
+
+ /**
+ * Keyboard event constant representing the pause
+ * key (value is (1<<24)+85).
+ *
+ * @since 3.0
+ */
+ public static final int PAUSE = KEYCODE_BIT + 85;
+
+ /**
+ * Keyboard event constant representing the break
+ * key (value is (1<<24)+86).
+ *
+ * @since 3.0
+ */
+ public static final int BREAK = KEYCODE_BIT + 86;
+
+ /**
+ * Keyboard event constant representing the print screen
+ * key (value is (1<<24)+87).
+ *
+ * @since 3.0
+ */
+ public static final int PRINT_SCREEN = KEYCODE_BIT + 87;
+
+ /**
+ * The MessageBox
style constant for error icon
+ * behavior (value is 1).
+ */
+ public static final int ICON_ERROR = 1;
+
+ /**
+ * The MessageBox
style constant for information icon
+ * behavior (value is 1<<1).
+ */
+ public static final int ICON_INFORMATION = 1 << 1;
+
+ /**
+ * The MessageBox
style constant for question icon
+ * behavior (value is 1<<2).
+ */
+ public static final int ICON_QUESTION = 1 << 2;
+
+ /**
+ * The MessageBox
style constant for warning icon
+ * behavior (value is 1<<3).
+ */
+ public static final int ICON_WARNING = 1 << 3;
+
+ /**
+ * The MessageBox
style constant for "working" icon
+ * behavior (value is 1<<4).
+ */
+ public static final int ICON_WORKING = 1 << 4;
+
+ /**
+ * The style constant for "search" icon. This style constant is
+ * used with Text
in combination with SWT.SEARCH
+ *
(value is 1<<9).
+ *
+ *
+ *
+ *
+ * @see #SEARCH
+ * @see #ICON_CANCEL
+ *
+ * @since 3.5
+ */
+ public static final int ICON_SEARCH = 1 << 9;
+
+ /**
+ * The style constant for "cancel" icon. This style constant is
+ * used with Text
Text
in combination with SWT.SEARCH
+ *
(value is 1<<8).
+ *
+ *
+ *
+ *
+ * @see #SEARCH
+ * @see #ICON_SEARCH
+ *
+ * @since 3.5
+ */
+ public static final int ICON_CANCEL = 1 << 8;
+
+
+ /**
+ * The Text
MessageBox
style constant for an OK button;
+ * valid combinations are OK, OK|CANCEL
+ * (value is 1<<5).
+ */
+ public static final int OK = 1 << 5;
+
+ /**
+ * The MessageBox
style constant for YES button;
+ * valid combinations are YES|NO, YES|NO|CANCEL
+ * (value is 1<<6).
+ */
+ public static final int YES = 1 << 6;
+
+ /**
+ * The MessageBox
style constant for NO button;
+ * valid combinations are YES|NO, YES|NO|CANCEL
+ * (value is 1<<7).
+ */
+ public static final int NO = 1 << 7;
+
+ /**
+ * The MessageBox
style constant for a CANCEL button;
+ * valid combinations are OK|CANCEL, YES|NO|CANCEL, RETRY|CANCEL
+ * (value is 1<<8).
+ *
+ *
+ *
+ */
+ public static final int CANCEL = 1 << 8;
+
+ /**
+ * The MessageBox
MessageBox
style constant for an ABORT button;
+ * the only valid combination is ABORT|RETRY|IGNORE
+ * (value is 1<<9).
+ */
+ public static final int ABORT = 1 << 9;
+
+ /**
+ * The MessageBox
style constant for a RETRY button;
+ * valid combinations are ABORT|RETRY|IGNORE, RETRY|CANCEL
+ * (value is 1<<10).
+ */
+ public static final int RETRY = 1 << 10;
+
+ /**
+ * The MessageBox
style constant for an IGNORE button;
+ * the only valid combination is ABORT|RETRY|IGNORE
+ * (value is 1<<11).
+ */
+ public static final int IGNORE = 1 << 11;
+
+ /**
+ * The FileDialog
style constant for open file dialog behavior
+ * (value is 1<<12).
+ */
+ public static final int OPEN = 1 << 12;
+
+ /**
+ * The FileDialog
style constant for save file dialog behavior
+ * (value is 1<<13).
+ */
+ public static final int SAVE = 1 << 13;
+
+ /**
+ * The Composite
constant to indicate that
+ * an attribute (such as background) is not inherited
+ * by the children (value is 0).
+ *
+ * @since 3.2
+ */
+ public static final int INHERIT_NONE = 0;
+
+ /**
+ * The Composite
constant to indicate that
+ * an attribute (such as background) is inherited by
+ * children who choose this value as their "default"
+ * (value is 1). For example, a label child will
+ * typically choose to inherit the background color
+ * of a composite while a list or table will not.
+ *
+ * @since 3.2
+ */
+ public static final int INHERIT_DEFAULT = 1;
+
+ /**
+ * The Composite
constant to indicate that
+ * an attribute (such as background) is inherited by
+ * all children.
+ *
+ * @since 3.2
+ */
+ public static final int INHERIT_FORCE = 2;
+
+ /**
+ * Default color white (value is 1).
+ */
+ public static final int COLOR_WHITE = 1;
+
+ /**
+ * Default color black (value is 2).
+ */
+ public static final int COLOR_BLACK = 2;
+
+ /**
+ * Default color red (value is 3).
+ */
+ public static final int COLOR_RED = 3;
+
+ /**
+ * Default color dark red (value is 4).
+ */
+ public static final int COLOR_DARK_RED = 4;
+
+ /**
+ * Default color green (value is 5).
+ */
+ public static final int COLOR_GREEN = 5;
+
+ /**
+ * Default color dark green (value is 6).
+ */
+ public static final int COLOR_DARK_GREEN = 6;
+
+ /**
+ * Default color yellow (value is 7).
+ */
+ public static final int COLOR_YELLOW = 7;
+
+ /**
+ * Default color dark yellow (value is 8).
+ */
+ public static final int COLOR_DARK_YELLOW = 8;
+
+ /**
+ * Default color blue (value is 9).
+ */
+ public static final int COLOR_BLUE = 9;
+
+ /**
+ * Default color dark blue (value is 10).
+ */
+ public static final int COLOR_DARK_BLUE = 10;
+
+ /**
+ * Default color magenta (value is 11).
+ */
+ public static final int COLOR_MAGENTA = 11;
+
+ /**
+ * Default color dark magenta (value is 12).
+ */
+ public static final int COLOR_DARK_MAGENTA = 12;
+
+ /**
+ * Default color cyan (value is 13).
+ */
+ public static final int COLOR_CYAN = 13;
+
+ /**
+ * Default color dark cyan (value is 14).
+ */
+ public static final int COLOR_DARK_CYAN = 14;
+
+ /**
+ * Default color gray (value is 15).
+ */
+ public static final int COLOR_GRAY = 15;
+
+ /**
+ * Default color dark gray (value is 16).
+ */
+ public static final int COLOR_DARK_GRAY = 16;
+
+ /*
+ * System Colors
+ *
+ * Dealing with system colors is an area where there are
+ * many platform differences. On some platforms, system
+ * colors can change dynamically while the program is
+ * running. On other platforms, system colors can be
+ * changed for all instances of a particular widget.
+ * Therefore, the only truly portable method to obtain
+ * a widget color query is to query the color from an
+ * instance of the widget.
+ *
+ * It is expected that the list of supported colors
+ * will grow over time.
+ */
+
+ /**
+ * System color used to paint dark shadow areas (value is 17).
+ */
+ public static final int COLOR_WIDGET_DARK_SHADOW = 17;
+
+ /**
+ * System color used to paint normal shadow areas (value is 18).
+ */
+ public static final int COLOR_WIDGET_NORMAL_SHADOW = 18;
+
+ /**
+ * System color used to paint light shadow areas (value is 19).
+ */
+ public static final int COLOR_WIDGET_LIGHT_SHADOW = 19;
+
+ /**
+ * System color used to paint highlight shadow areas (value is 20).
+ */
+ public static final int COLOR_WIDGET_HIGHLIGHT_SHADOW = 20;
+
+ /**
+ * System color used to paint foreground areas (value is 21).
+ */
+ public static final int COLOR_WIDGET_FOREGROUND = 21;
+
+ /**
+ * System color used to paint background areas (value is 22).
+ */
+ public static final int COLOR_WIDGET_BACKGROUND = 22;
+
+ /**
+ * System color used to paint border areas (value is 23).
+ */
+ public static final int COLOR_WIDGET_BORDER = 23;
+
+ /**
+ * System color used to paint list foreground areas (value is 24).
+ */
+ public static final int COLOR_LIST_FOREGROUND = 24;
+
+ /**
+ * System color used to paint list background areas (value is 25).
+ */
+ public static final int COLOR_LIST_BACKGROUND = 25;
+
+ /**
+ * System color used to paint list selection background areas (value is 26).
+ */
+ public static final int COLOR_LIST_SELECTION = 26;
+
+ /**
+ * System color used to paint list selected text (value is 27).
+ */
+ public static final int COLOR_LIST_SELECTION_TEXT = 27;
+
+ /**
+ * System color used to paint tooltip text (value is 28).
+ */
+ public static final int COLOR_INFO_FOREGROUND = 28;
+
+ /**
+ * System color used to paint tooltip background areas (value is 29).
+ */
+ public static final int COLOR_INFO_BACKGROUND = 29;
+
+ /**
+ * System color used to paint title text (value is 30).
+ */
+ public static final int COLOR_TITLE_FOREGROUND = 30;
+
+ /**
+ * System color used to paint title background areas (value is 31).
+ */
+ public static final int COLOR_TITLE_BACKGROUND = 31;
+
+ /**
+ * System color used to paint title background gradient (value is 32).
+ */
+ public static final int COLOR_TITLE_BACKGROUND_GRADIENT = 32;
+
+ /**
+ * System color used to paint inactive title text (value is 33).
+ */
+ public static final int COLOR_TITLE_INACTIVE_FOREGROUND = 33;
+
+ /**
+ * System color used to paint inactive title background areas (value is 34).
+ */
+ public static final int COLOR_TITLE_INACTIVE_BACKGROUND = 34;
+
+ /**
+ * System color used to paint inactive title background gradient (value is 35).
+ */
+ public static final int COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT = 35;
+
+ /**
+ * System color used to paint link text (value is 36).
+ *
+ * @since 3.102
+ */
+ public static final int COLOR_LINK_FOREGROUND = 36;
+
+ /**
+ * System color used to paint with alpha 0 (value is 37).
+ *
+ * Note that this is a HINT and may be overridden by the platform.
+ * For example:
+ *
+ *
+ *
+ * @since 3.104
+ */
+ public static final int COLOR_TRANSPARENT = 37;
+
+ /**
+ * System color used to paint disabled text background areas (value is 38).
+ *
+ * @since 3.112
+ */
+ public static final int COLOR_TEXT_DISABLED_BACKGROUND = 38;
+
+ /**
+ * System color used to paint disabled foreground areas (value is 39).
+ *
+ * @since 3.112
+ */
+ public static final int COLOR_WIDGET_DISABLED_FOREGROUND = 39;
+
+ /**
+ * Draw constant indicating whether the drawing operation
+ * should fill the background (value is 1<<0).
+ */
+ public static final int DRAW_TRANSPARENT = 1 << 0;
+
+ /**
+ * Draw constant indicating whether the string drawing operation
+ * should handle line-delimiters (value is 1<<1).
+ */
+ public static final int DRAW_DELIMITER = 1 << 1;
+
+ /**
+ * Draw constant indicating whether the string drawing operation
+ * should expand TAB characters (value is 1<<2).
+ */
+ public static final int DRAW_TAB = 1 << 2;
+
+ /**
+ * Draw constant indicating whether the string drawing operation
+ * should handle mnemonics (value is 1<<3).
+ */
+ public static final int DRAW_MNEMONIC = 1 << 3;
+
+
+ /**
+ * Selection constant indicating that a line delimiter should be
+ * drawn (value is 1<<17).
+ *
+ *
+ *
+ *
+ * @see #FULL_SELECTION
+ * @see #LAST_LINE_SELECTION
+ *
+ * @since 3.3
+ */
+ public static final int DELIMITER_SELECTION = 1 << 17;
+
+ /**
+ * Selection constant indicating that the last line is selected
+ * to the end and should be drawn using either a line delimiter
+ * or full line selection (value is 1<<20).
+ *
+ * TextLayout
+ *
+ *
+ * @see #DELIMITER_SELECTION
+ * @see #FULL_SELECTION
+ *
+ * @since 3.3
+ */
+ public static final int LAST_LINE_SELECTION = 1 << 20;
+
+ /**
+ * SWT error constant indicating that no error number was specified
+ * (value is 1).
+ */
+ public static final int ERROR_UNSPECIFIED = 1;
+
+ /**
+ * SWT error constant indicating that no more handles for an
+ * operating system resource are available
+ * (value is 2).
+ */
+ public static final int ERROR_NO_HANDLES = 2;
+
+ /**
+ * SWT error constant indicating that no more callback resources are available
+ * (value is 3).
+ */
+ public static final int ERROR_NO_MORE_CALLBACKS = 3;
+
+ /**
+ * SWT error constant indicating that a null argument was passed in
+ * (value is 4).
+ */
+ public static final int ERROR_NULL_ARGUMENT = 4;
+
+ /**
+ * SWT error constant indicating that an invalid argument was passed in
+ * (value is 5).
+ */
+ public static final int ERROR_INVALID_ARGUMENT = 5;
+
+ /**
+ * SWT error constant indicating that a value was found to be
+ * outside the allowable range
+ * (value is 6).
+ */
+ public static final int ERROR_INVALID_RANGE = 6;
+
+ /**
+ * SWT error constant indicating that a value which can not be
+ * zero was found to be
+ * (value is 7).
+ */
+ public static final int ERROR_CANNOT_BE_ZERO = 7;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to provide the value of an item
+ * (value is 8).
+ */
+ public static final int ERROR_CANNOT_GET_ITEM = 8;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to provide the selection
+ * (value is 9).
+ */
+ public static final int ERROR_CANNOT_GET_SELECTION = 9;
+
+ /**
+ * SWT error constant indicating that the matrix is not invertible
+ * (value is 10).
+ *
+ * @since 3.1
+ */
+ public static final int ERROR_CANNOT_INVERT_MATRIX = 10;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to provide the height of an item
+ * (value is 11).
+ */
+ public static final int ERROR_CANNOT_GET_ITEM_HEIGHT = 11;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to provide the text of a widget
+ * (value is 12).
+ */
+ public static final int ERROR_CANNOT_GET_TEXT = 12;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to set the text of a widget
+ * (value is 13).
+ */
+ public static final int ERROR_CANNOT_SET_TEXT = 13;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to add an item
+ * (value is 14).
+ */
+ public static final int ERROR_ITEM_NOT_ADDED = 14;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to remove an item
+ * (value is 15).
+ */
+ public static final int ERROR_ITEM_NOT_REMOVED = 15;
+
+ /**
+ * SWT error constant indicating that the graphics library
+ * is not available
+ * (value is 16).
+ */
+ public static final int ERROR_NO_GRAPHICS_LIBRARY = 16;
+
+ /**
+ * SWT error constant indicating that a particular feature has
+ * not been implemented on this platform
+ * (value is 20).
+ */
+ public static final int ERROR_NOT_IMPLEMENTED = 20;
+
+ /**
+ * SWT error constant indicating that a menu which needed
+ * to have the drop down style had some other style instead
+ * (value is 21).
+ */
+ public static final int ERROR_MENU_NOT_DROP_DOWN = 21;
+
+ /**
+ * SWT error constant indicating that an attempt was made to
+ * invoke an SWT operation which can only be executed by the
+ * user-interface thread from some other thread
+ * (value is 22).
+ */
+ public static final int ERROR_THREAD_INVALID_ACCESS = 22;
+
+ /**
+ * SWT error constant indicating that an attempt was made to
+ * invoke an SWT operation using a widget which had already
+ * been disposed
+ * (value is 24).
+ */
+ public static final int ERROR_WIDGET_DISPOSED = 24;
+
+ /**
+ * SWT error constant indicating that a menu item which needed
+ * to have the cascade style had some other style instead
+ * (value is 27).
+ */
+ public static final int ERROR_MENUITEM_NOT_CASCADE = 27;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to set the selection of a widget
+ * (value is 28).
+ */
+ public static final int ERROR_CANNOT_SET_SELECTION = 28;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to set the menu
+ * (value is 29).
+ */
+ public static final int ERROR_CANNOT_SET_MENU = 29;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to set the enabled state
+ * (value is 30).
+ */
+ public static final int ERROR_CANNOT_SET_ENABLED = 30;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to provide enabled/disabled state information
+ * (value is 31).
+ */
+ public static final int ERROR_CANNOT_GET_ENABLED = 31;
+
+ /**
+ * SWT error constant indicating that a provided widget can
+ * not be used as a parent in the current operation
+ * (value is 32).
+ */
+ public static final int ERROR_INVALID_PARENT = 32;
+
+ /**
+ * SWT error constant indicating that a menu which needed
+ * to have the menu bar style had some other style instead
+ * (value is 33).
+ */
+ public static final int ERROR_MENU_NOT_BAR = 33;
+
+ /**
+ * SWT error constant indicating that the underlying operating
+ * system was unable to provide count information
+ * (value is 36).
+ */
+ public static final int ERROR_CANNOT_GET_COUNT = 36;
+
+ /**
+ * SWT error constant indicating that a menu which needed
+ * to have the pop up menu style had some other style instead
+ * (value is 37).
+ */
+ public static final int ERROR_MENU_NOT_POP_UP = 37;
+
+ /**
+ * SWT error constant indicating that a graphics operation
+ * was attempted with an image of an unsupported depth
+ * (value is 38).
+ */
+ public static final int ERROR_UNSUPPORTED_DEPTH = 38;
+
+ /**
+ * SWT error constant indicating that an input/output operation
+ * failed during the execution of an SWT operation
+ * (value is 39).
+ */
+ public static final int ERROR_IO = 39;
+
+ /**
+ * SWT error constant indicating that a graphics operation
+ * was attempted with an image having an invalid format
+ * (value is 40).
+ */
+ public static final int ERROR_INVALID_IMAGE = 40;
+
+ /**
+ * SWT error constant indicating that a graphics operation
+ * was attempted with an image having a valid but unsupported
+ * format
+ * (value is 42).
+ */
+ public static final int ERROR_UNSUPPORTED_FORMAT = 42;
+
+ /**
+ * SWT error constant indicating that an attempt was made
+ * to subclass an SWT widget class without implementing the
+ * TextLayout
checkSubclass()
method
+ * (value is 43).
+ *
+ * For additional information see the comment in
+ * Widget.checkSubclass()
.
+ *
+ * @see org.eclipse.swt.widgets.Widget#checkSubclass
+ */
+ public static final int ERROR_INVALID_SUBCLASS = 43;
+
+ /**
+ * SWT error constant indicating that an attempt was made to
+ * invoke an SWT operation using a graphics object which had
+ * already been disposed
+ * (value is 44).
+ */
+ public static final int ERROR_GRAPHIC_DISPOSED = 44;
+
+ /**
+ * SWT error constant indicating that an attempt was made to
+ * invoke an SWT operation using a device which had already
+ * been disposed
+ * (value is 45).
+ */
+ public static final int ERROR_DEVICE_DISPOSED = 45;
+
+ /**
+ * SWT error constant indicating that an exception happened
+ * when executing a runnable
+ * (value is 46).
+ */
+ public static final int ERROR_FAILED_EXEC = 46;
+
+ /**
+ * SWT error constant indicating that an unsatisfied link
+ * error occurred while attempting to load a library
+ * (value is 47).
+ *
+ * @since 3.1
+ */
+ public static final int ERROR_FAILED_LOAD_LIBRARY = 47;
+
+ /**
+ * SWT error constant indicating that a font is not valid
+ * (value is 48).
+ *
+ * @since 3.1
+ */
+ public static final int ERROR_INVALID_FONT = 48;
+
+ /**
+ * SWT error constant indicating that an attempt was made to
+ * use an BrowserFunction object which had already been disposed
+ * (value is 49).
+ *
+ * @since 3.5
+ */
+ public static final int ERROR_FUNCTION_DISPOSED = 49;
+
+ /**
+ * SWT error constant indicating that an exception happened
+ * when evaluating a javascript expression
+ * (value is 50).
+ *
+ * @since 3.5
+ */
+ public static final int ERROR_FAILED_EVALUATE = 50;
+
+ /**
+ * SWT error constant indicating that an invalid value was returned
+ * (value is 51).
+ *
+ * @since 3.5
+ */
+ public static final int ERROR_INVALID_RETURN_VALUE = 51;
+
+ /**
+ * Constant indicating that an image or operation is of type bitmap (value is 0).
+ */
+ public static final int BITMAP = 0;
+
+ /**
+ * Constant indicating that an image or operation is of type icon (value is 1).
+ */
+ public static final int ICON = 1;
+
+ /**
+ * The Image
constructor argument indicating that
+ * the new image should be a copy of the image provided as
+ * an argument (value is 0).
+ */
+ public static final int IMAGE_COPY = 0;
+
+ /**
+ * The Image
constructor argument indicating that
+ * the new image should have the appearance of a "disabled"
+ * (using the platform's rules for how this should look)
+ * copy of the image provided as an argument (value is 1).
+ */
+ public static final int IMAGE_DISABLE = 1;
+
+ /**
+ * The Image
constructor argument indicating that
+ * the new image should have the appearance of a "gray scaled"
+ * copy of the image provided as an argument (value is 2).
+ */
+ public static final int IMAGE_GRAY = 2;
+
+ /**
+ * Constant to indicate an error state (value is 1).
+ *
+ *
+ *
+ * @since 3.4
+ */
+ public static final int ERROR = 1;
+
+ /**
+ * Constant to a indicate a paused state (value is 4).
+ * ProgressBar
+ *
+ *
+ * @since 3.4
+ */
+ public static final int PAUSED = 1 << 2;
+
+ /**
+ * The font style constant indicating a normal weight, non-italic font
+ * (value is 0). This constant is also used with ProgressBar
ProgressBar
+ * to indicate a normal state.
+ *
+ *
+ */
+ public static final int NORMAL = 0;
+
+ /**
+ * The font style constant indicating a bold weight font
+ * (value is 1<<0).
+ */
+ public static final int BOLD = 1 << 0;
+
+ /**
+ * The font style constant indicating an italic font
+ * (value is 1<<1).
+ */
+ public static final int ITALIC = 1 << 1;
+
+ /**
+ * System arrow cursor (value is 0).
+ */
+ public static final int CURSOR_ARROW = 0;
+
+ /**
+ * System wait cursor (value is 1).
+ */
+ public static final int CURSOR_WAIT = 1;
+
+ /**
+ * System cross hair cursor (value is 2).
+ */
+ public static final int CURSOR_CROSS = 2;
+
+ /**
+ * System app startup cursor (value is 3).
+ */
+ public static final int CURSOR_APPSTARTING = 3;
+
+ /**
+ * System help cursor (value is 4).
+ */
+ public static final int CURSOR_HELP = 4;
+
+ /**
+ * System resize all directions cursor (value is 5).
+ */
+ public static final int CURSOR_SIZEALL = 5;
+
+ /**
+ * System resize north-east-south-west cursor (value is 6).
+ */
+ public static final int CURSOR_SIZENESW = 6;
+
+ /**
+ * System resize north-south cursor (value is 7).
+ */
+ public static final int CURSOR_SIZENS = 7;
+
+ /**
+ * System resize north-west-south-east cursor (value is 8).
+ */
+ public static final int CURSOR_SIZENWSE = 8;
+
+ /**
+ * System resize west-east cursor (value is 9).
+ */
+ public static final int CURSOR_SIZEWE = 9;
+
+ /**
+ * System resize north cursor (value is 10).
+ */
+ public static final int CURSOR_SIZEN = 10;
+
+ /**
+ * System resize south cursor (value is 11).
+ */
+ public static final int CURSOR_SIZES = 11;
+
+ /**
+ * System resize east cursor (value is 12).
+ */
+ public static final int CURSOR_SIZEE = 12;
+
+ /**
+ * System resize west cursor (value is 13).
+ */
+ public static final int CURSOR_SIZEW = 13;
+
+ /**
+ * System resize north-east cursor (value is 14).
+ */
+ public static final int CURSOR_SIZENE = 14;
+
+ /**
+ * System resize south-east cursor (value is 15).
+ */
+ public static final int CURSOR_SIZESE = 15;
+
+ /**
+ * System resize south-west cursor (value is 16).
+ */
+ public static final int CURSOR_SIZESW = 16;
+
+ /**
+ * System resize north-west cursor (value is 17).
+ */
+ public static final int CURSOR_SIZENW = 17;
+
+ /**
+ * System up arrow cursor (value is 18).
+ */
+ public static final int CURSOR_UPARROW = 18;
+
+ /**
+ * System i-beam cursor (value is 19).
+ */
+ public static final int CURSOR_IBEAM = 19;
+
+ /**
+ * System "not allowed" cursor (value is 20).
+ */
+ public static final int CURSOR_NO = 20;
+
+ /**
+ * System hand cursor (value is 21).
+ */
+ public static final int CURSOR_HAND = 21;
+
+ /**
+ * Line drawing style for flat end caps (value is 1).
+ *
+ * @see org.eclipse.swt.graphics.GC#setLineCap(int)
+ * @see org.eclipse.swt.graphics.GC#getLineCap()
+ *
+ * @since 3.1
+ */
+ public static final int CAP_FLAT = 1;
+
+ /**
+ * Line drawing style for rounded end caps (value is 2).
+ *
+ * @see org.eclipse.swt.graphics.GC#setLineCap(int)
+ * @see org.eclipse.swt.graphics.GC#getLineCap()
+ *
+ * @since 3.1
+ */
+ public static final int CAP_ROUND = 2;
+
+ /**
+ * Line drawing style for square end caps (value is 3).
+ *
+ * @see org.eclipse.swt.graphics.GC#setLineCap(int)
+ * @see org.eclipse.swt.graphics.GC#getLineCap()
+ *
+ * @since 3.1
+ */
+ public static final int CAP_SQUARE = 3;
+
+ /**
+ * Line drawing style for miter joins (value is 1).
+ *
+ * @see org.eclipse.swt.graphics.GC#setLineJoin(int)
+ * @see org.eclipse.swt.graphics.GC#getLineJoin()
+ *
+ * @since 3.1
+ */
+ public static final int JOIN_MITER = 1;
+
+ /**
+ * Line drawing style for rounded joins (value is 2).
+ *
+ * @see org.eclipse.swt.graphics.GC#setLineJoin(int)
+ * @see org.eclipse.swt.graphics.GC#getLineJoin()
+ *
+ * @since 3.1
+ */
+ public static final int JOIN_ROUND = 2;
+
+ /**
+ * Line drawing style for bevel joins (value is 3).
+ *
+ * @see org.eclipse.swt.graphics.GC#setLineJoin(int)
+ * @see org.eclipse.swt.graphics.GC#getLineJoin()
+ *
+ * @since 3.1
+ */
+ public static final int JOIN_BEVEL = 3;
+
+ /**
+ * Line drawing style for solid lines (value is 1).
+ */
+ public static final int LINE_SOLID = 1;
+
+ /**
+ * Line drawing style for dashed lines (value is 2).
+ */
+ public static final int LINE_DASH = 2;
+
+ /**
+ * Line drawing style for dotted lines (value is 3).
+ */
+ public static final int LINE_DOT = 3;
+
+ /**
+ * Line drawing style for alternating dash-dot lines (value is 4).
+ */
+ public static final int LINE_DASHDOT = 4;
+
+ /**
+ * Line drawing style for dash-dot-dot lines (value is 5).
+ */
+ public static final int LINE_DASHDOTDOT = 5;
+
+ /**
+ * Line drawing style for custom dashed lines (value is 6).
+ *
+ * @see org.eclipse.swt.graphics.GC#setLineDash(int[])
+ * @see org.eclipse.swt.graphics.GC#getLineDash()
+ *
+ * @since 3.1
+ */
+ public static final int LINE_CUSTOM = 6;
+
+ /**
+ * Path constant that represents a "move to" operation (value is 1).
+ *
+ * @since 3.1
+ */
+ public static final int PATH_MOVE_TO = 1;
+
+ /**
+ * Path constant that represents a "line to" operation (value is 2).
+ *
+ * @since 3.1
+ */
+ public static final int PATH_LINE_TO = 2;
+
+ /**
+ * Path constant that represents a "quadratic curve to" operation (value is 3).
+ *
+ * @since 3.1
+ */
+ public static final int PATH_QUAD_TO = 3;
+
+ /**
+ * Path constant that represents a "cubic curve to" operation (value is 4).
+ *
+ * @since 3.1
+ */
+ public static final int PATH_CUBIC_TO = 4;
+
+ /**
+ * Path constant that represents a "close" operation (value is 5).
+ *
+ * @since 3.1
+ */
+ public static final int PATH_CLOSE = 5;
+
+ /**
+ * Even odd rule for filling operations (value is 1).
+ *
+ * @since 3.1
+ */
+ public static final int FILL_EVEN_ODD = 1;
+
+ /**
+ * Winding rule for filling operations (value is 2).
+ *
+ * @since 3.1
+ */
+ public static final int FILL_WINDING = 2;
+
+ /**
+ * Image format constant indicating an unknown image type (value is -1).
+ */
+ public static final int IMAGE_UNDEFINED = -1;
+
+ /**
+ * Image format constant indicating a Windows BMP format image (value is 0).
+ */
+ public static final int IMAGE_BMP = 0;
+
+ /**
+ * Image format constant indicating a run-length encoded
+ * Windows BMP format image (value is 1).
+ */
+ public static final int IMAGE_BMP_RLE = 1;
+
+ /**
+ * Image format constant indicating a GIF format image (value is 2).
+ */
+ public static final int IMAGE_GIF = 2;
+
+ /**
+ * Image format constant indicating a ICO format image (value is 3).
+ */
+ public static final int IMAGE_ICO = 3;
+
+ /**
+ * Image format constant indicating a JPEG format image (value is 4).
+ */
+ public static final int IMAGE_JPEG = 4;
+
+ /**
+ * Image format constant indicating a PNG format image (value is 5).
+ */
+ public static final int IMAGE_PNG = 5;
+
+ /**
+ * Image format constant indicating a TIFF format image (value is 6).
+ */
+ public static final int IMAGE_TIFF = 6;
+
+ /**
+ * Image format constant indicating an OS/2 BMP format image (value is 7).
+ */
+ public static final int IMAGE_OS2_BMP = 7;
+
+ /**
+ * Image format constant indicating a SVG format image (value is 8).
+ * ProgressBar
Note that this is a HINT and is currently only supported on GTK.
+ *
+ * @since 3.113
+ */
+ public static final int IMAGE_SVG = 8;
+
+ /**
+ * GIF image disposal method constants indicating that the
+ * disposal method is unspecified (value is 0).
+ */
+ public static final int DM_UNSPECIFIED = 0x0;
+
+ /**
+ * GIF image disposal method constants indicating that the
+ * disposal method is to do nothing; that is, to leave the
+ * previous image in place (value is 1).
+ */
+ public static final int DM_FILL_NONE = 0x1;
+
+ /**
+ * GIF image disposal method constants indicating that the
+ * the previous images should be covered with the background
+ * color before displaying the next image (value is 2).
+ */
+ public static final int DM_FILL_BACKGROUND = 0x2;
+
+ /**
+ * GIF image disposal method constants indicating that the
+ * disposal method is to restore the previous picture
+ * (value is 3).
+ */
+ public static final int DM_FILL_PREVIOUS = 0x3;
+
+ /**
+ * Image transparency constant indicating that the image
+ * contains no transparency information (value is 0).
+ */
+ public static final int TRANSPARENCY_NONE = 0x0;
+
+ /**
+ * Image transparency constant indicating that the image
+ * contains alpha transparency information (value is 1<<0).
+ */
+ public static final int TRANSPARENCY_ALPHA = 1 << 0;
+
+ /**
+ * Image transparency constant indicating that the image
+ * contains a transparency mask (value is 1<<1).
+ */
+ public static final int TRANSPARENCY_MASK = 1 << 1;
+
+ /**
+ * Image transparency constant indicating that the image
+ * contains a transparent pixel (value is 1<<2).
+ */
+ public static final int TRANSPARENCY_PIXEL = 1 << 2;
+
+ /**
+ * The character movement type (value is 1<<0).
+ * This constant is used to move a text offset over a character.
+ *
+ * @see org.eclipse.swt.graphics.TextLayout#getNextOffset(int, int)
+ * @see org.eclipse.swt.graphics.TextLayout#getPreviousOffset(int, int)
+ *
+ * @since 3.0
+ */
+ public static final int MOVEMENT_CHAR = 1 << 0;
+
+ /**
+ * The cluster movement type (value is 1<<1).
+ * This constant is used to move a text offset over a cluster.
+ * A cluster groups one or more characters. A cluster is
+ * undivisible, this means that a caret offset can not be placed in the
+ * middle of a cluster.
+ *
+ * @see org.eclipse.swt.graphics.TextLayout#getNextOffset(int, int)
+ * @see org.eclipse.swt.graphics.TextLayout#getPreviousOffset(int, int)
+ *
+ * @since 3.0
+ */
+ public static final int MOVEMENT_CLUSTER = 1 << 1;
+
+ /**
+ * The word movement type (value is 1<<2).
+ * This constant is used to move a text offset over a word.
+ * The behavior of this constant depends on the platform and on the
+ * direction of the movement. For example, on Windows the stop is
+ * always at the start of the word. On GTK and Mac the stop is at the end
+ * of the word if the direction is next and at the start of the word if the
+ * direction is previous.
+ *
+ * @see org.eclipse.swt.graphics.TextLayout#getNextOffset(int, int)
+ * @see org.eclipse.swt.graphics.TextLayout#getPreviousOffset(int, int)
+ *
+ * @since 3.0
+ */
+ public static final int MOVEMENT_WORD = 1 << 2;
+
+ /**
+ * The word end movement type (value is 1<<3).
+ * This constant is used to move a text offset to the next or previous
+ * word end. The behavior of this constant does not depend on the platform.
+ *
+ *
+ * @see org.eclipse.swt.graphics.TextLayout#getNextOffset(int, int)
+ * @see org.eclipse.swt.graphics.TextLayout#getPreviousOffset(int, int)
+ *
+ * @since 3.3
+ */
+ public static final int MOVEMENT_WORD_END = 1 << 3;
+
+ /**
+ * The word start movement type (value is 1<<4).
+ * This constant is used to move a text offset to the next or previous
+ * word start. The behavior of this constant does not depend on the platform.
+ *
+ * @see org.eclipse.swt.graphics.TextLayout#getNextOffset(int, int)
+ * @see org.eclipse.swt.graphics.TextLayout#getPreviousOffset(int, int)
+ *
+ * @since 3.3
+ */
+ public static final int MOVEMENT_WORD_START = 1 << 4;
+
+ /**
+ * A constant indicating that a given operation should be performed on
+ * all widgets (value is 1<<0).
+ *
+ *
+ *
+ *
+ * @see org.eclipse.swt.widgets.Composite#layout(org.eclipse.swt.widgets.Control[], int)
+ *
+ * @since 3.6
+ */
+ public static final int ALL = 1 << 0;
+
+ /**
+ * ID for the About menu item (value is -1).
+ *
+ * @see org.eclipse.swt.widgets.MenuItem#setID(int)
+ * @see org.eclipse.swt.widgets.MenuItem#getID()
+ *
+ * @since 3.7
+ */
+ public static final int ID_ABOUT = -1;
+
+ /**
+ * ID for the Preferences menu item (value is -2).
+ *
+ * @see org.eclipse.swt.widgets.MenuItem#setID(int)
+ * @see org.eclipse.swt.widgets.MenuItem#getID()
+ *
+ * @since 3.7
+ */
+ public static final int ID_PREFERENCES = -2;
+
+ /**
+ * ID for the Hide menu item (value is -3).
+ *
+ * @see org.eclipse.swt.widgets.MenuItem#setID(int)
+ * @see org.eclipse.swt.widgets.MenuItem#getID()
+ *
+ * @since 3.7
+ */
+ public static final int ID_HIDE = -3;
+
+ /**
+ * ID for the Hide Others menu item (value is -4).
+ *
+ * @see org.eclipse.swt.widgets.MenuItem#setID(int)
+ * @see org.eclipse.swt.widgets.MenuItem#getID()
+ *
+ * @since 3.7
+ */
+ public static final int ID_HIDE_OTHERS = -4;
+
+ /**
+ * ID for the Show All menu item (value is -5).
+ *
+ * @see org.eclipse.swt.widgets.MenuItem#setID(int)
+ * @see org.eclipse.swt.widgets.MenuItem#getID()
+ *
+ * @since 3.7
+ */
+ public static final int ID_SHOW_ALL = -5;
+
+ /**
+ * ID for the Quit menu item (value is -6).
+ *
+ * @see org.eclipse.swt.widgets.MenuItem#setID(int)
+ * @see org.eclipse.swt.widgets.MenuItem#getID()
+ *
+ * @since 3.7
+ */
+ public static final int ID_QUIT = -6;
+
+ /**
+ * Key name for setting and getting the skin class of a widget.
+ * Composite
layoutScrollable
constant to indicate that
+ * the receiver is using overlay scrollbars. (value is 1)
+ *
+ * @since 3.8
+ */
+ public static final int SCROLLBAR_OVERLAY = 1 << 1;
+
+
+/**
+ * Returns a boolean indicating whether this SWT implementation can
+ * be loaded. Examples of criteria that may be used to determine this
+ * include the OS and architecture of the JRE that is being used.
+ *
+ * @return true
if this SWT implementation can be loaded
+ * and false
otherwise
+ *
+ * @since 3.8
+ */
+public static boolean isLoadable () {
+ return Platform.isLoadable ();
+}
+
+/**
+ * Answers a concise, human readable description of the error code.
+ *
+ * @param code the SWT error code.
+ * @return a description of the error code.
+ *
+ * @see SWT
+ */
+static String findErrorText (int code) {
+ switch (code) {
+ case ERROR_UNSPECIFIED: return "Unspecified error"; //$NON-NLS-1$
+ case ERROR_NO_HANDLES: return "No more handles"; //$NON-NLS-1$
+ case ERROR_NO_MORE_CALLBACKS: return "No more callbacks"; //$NON-NLS-1$
+ case ERROR_NULL_ARGUMENT: return "Argument cannot be null"; //$NON-NLS-1$
+ case ERROR_INVALID_ARGUMENT: return "Argument not valid"; //$NON-NLS-1$
+ case ERROR_INVALID_RETURN_VALUE: return "Return value not valid"; //$NON-NLS-1$
+ case ERROR_INVALID_RANGE: return "Index out of bounds"; //$NON-NLS-1$
+ case ERROR_CANNOT_BE_ZERO: return "Argument cannot be zero"; //$NON-NLS-1$
+ case ERROR_CANNOT_GET_ITEM: return "Cannot get item"; //$NON-NLS-1$
+ case ERROR_CANNOT_GET_SELECTION: return "Cannot get selection"; //$NON-NLS-1$
+ case ERROR_CANNOT_GET_ITEM_HEIGHT: return "Cannot get item height"; //$NON-NLS-1$
+ case ERROR_CANNOT_GET_TEXT: return "Cannot get text"; //$NON-NLS-1$
+ case ERROR_CANNOT_SET_TEXT: return "Cannot set text"; //$NON-NLS-1$
+ case ERROR_ITEM_NOT_ADDED: return "Item not added"; //$NON-NLS-1$
+ case ERROR_ITEM_NOT_REMOVED: return "Item not removed"; //$NON-NLS-1$
+ case ERROR_NOT_IMPLEMENTED: return "Not implemented"; //$NON-NLS-1$
+ case ERROR_MENU_NOT_DROP_DOWN: return "Menu must be a drop down"; //$NON-NLS-1$
+ case ERROR_THREAD_INVALID_ACCESS: return "Invalid thread access"; //$NON-NLS-1$
+ case ERROR_WIDGET_DISPOSED: return "Widget is disposed"; //$NON-NLS-1$
+ case ERROR_MENUITEM_NOT_CASCADE: return "Menu item is not a CASCADE"; //$NON-NLS-1$
+ case ERROR_CANNOT_SET_SELECTION: return "Cannot set selection"; //$NON-NLS-1$
+ case ERROR_CANNOT_SET_MENU: return "Cannot set menu"; //$NON-NLS-1$
+ case ERROR_CANNOT_SET_ENABLED: return "Cannot set the enabled state"; //$NON-NLS-1$
+ case ERROR_CANNOT_GET_ENABLED: return "Cannot get the enabled state"; //$NON-NLS-1$
+ case ERROR_INVALID_PARENT: return "Widget has the wrong parent"; //$NON-NLS-1$
+ case ERROR_MENU_NOT_BAR: return "Menu is not a BAR"; //$NON-NLS-1$
+ case ERROR_CANNOT_GET_COUNT: return "Cannot get count"; //$NON-NLS-1$
+ case ERROR_MENU_NOT_POP_UP: return "Menu is not a POP_UP"; //$NON-NLS-1$
+ case ERROR_UNSUPPORTED_DEPTH: return "Unsupported color depth"; //$NON-NLS-1$
+ case ERROR_IO: return "i/o error"; //$NON-NLS-1$
+ case ERROR_INVALID_IMAGE: return "Invalid image"; //$NON-NLS-1$
+ case ERROR_UNSUPPORTED_FORMAT: return "Unsupported or unrecognized format"; //$NON-NLS-1$
+ case ERROR_INVALID_SUBCLASS: return "Subclassing not allowed"; //$NON-NLS-1$
+ case ERROR_GRAPHIC_DISPOSED: return "Graphic is disposed"; //$NON-NLS-1$
+ case ERROR_DEVICE_DISPOSED: return "Device is disposed"; //$NON-NLS-1$
+ case ERROR_FUNCTION_DISPOSED: return "BrowserFunction is disposed"; //$NON-NLS-1$
+ case ERROR_FAILED_EXEC: return "Failed to execute runnable"; //$NON-NLS-1$
+ case ERROR_FAILED_EVALUATE: return "Failed to evaluate javascript expression"; //$NON-NLS-1$
+ case ERROR_FAILED_LOAD_LIBRARY: return "Unable to load library"; //$NON-NLS-1$
+ case ERROR_CANNOT_INVERT_MATRIX: return "Cannot invert matrix"; //$NON-NLS-1$
+ case ERROR_NO_GRAPHICS_LIBRARY: return "Unable to load graphics library"; //$NON-NLS-1$
+ case ERROR_INVALID_FONT: return "Font not valid"; //$NON-NLS-1$
+ }
+ return "Unknown error"; //$NON-NLS-1$
+}
+
+/**
+ * Returns the NLS'ed message for the given argument.
+ *
+ * @param key the key to look up
+ * @return the message for the given key
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public static String getMessage(String key) {
+ return Compatibility.getMessage(key);
+}
+
+/**
+ * Returns the NLS'ed message for the given arguments.
+ *
+ * @param key the key to look up
+ * @param args the parameters to insert into the message
+ * @return the message for the given parameterized key
+ *
+ * @exception IllegalArgumentException
+ *
+ *
+ * @since 3.8
+ */
+public static String getMessage(String key, Object[] args) {
+ return Compatibility.getMessage(key, args);
+}
+
+/**
+ * Returns the SWT platform name.
+ * Examples: "win32", "gtk", "cocoa"
+ *
+ * @return the SWT platform name
+ */
+public static String getPlatform () {
+ return Platform.PLATFORM;
+}
+
+/**
+ * Returns the SWT version number as an integer.
+ * Example: "SWT051" == 51
+ *
+ * @return the SWT version number
+ */
+public static int getVersion () {
+ return Library.SWT_VERSION;
+}
+
+/**
+ * Throws an appropriate exception based on the passed in error code.
+ *
+ * @param code the SWT error code
+ */
+public static void error (int code) {
+ error (code, null);
+}
+
+/**
+ * Throws an appropriate exception based on the passed in error code.
+ * The throwable
argument should be either null, or the
+ * throwable which caused SWT to throw an exception.
+ *
+ *
+ * This method provides the logic which maps between error codes
+ * and one of the above exceptions.
+ *
+ * @param code the SWT error code.
+ * @param throwable the exception which caused the error to occur.
+ *
+ * @see SWTError
+ * @see SWTException
+ * @see IllegalArgumentException
+ */
+public static void error (int code, Throwable throwable) {
+ error (code, throwable, null);
+}
+
+/**
+ * Throws an appropriate exception based on the passed in error code.
+ * The throwable
argument should be either null, or the
+ * throwable which caused SWT to throw an exception.
+ *
+ *
+ * This method provides the logic which maps between error codes
+ * and one of the above exceptions.
+ *
+ * @param code the SWT error code.
+ * @param throwable the exception which caused the error to occur.
+ * @param detail more information about error.
+ *
+ * @see SWTError
+ * @see SWTException
+ * @see IllegalArgumentException
+ *
+ * @since 3.0
+ */
+public static void error (int code, Throwable throwable, String detail) {
+
+ /*
+ * This code prevents the creation of "chains" of SWTErrors and
+ * SWTExceptions which in turn contain other SWTErrors and
+ * SWTExceptions as their throwable. This can occur when low level
+ * code throws an exception past a point where a higher layer is
+ * being "safe" and catching all exceptions. (Note that, this is
+ * _a_bad_thing_ which we always try to avoid.)
+ *
+ * On the theory that the low level code is closest to the
+ * original problem, we simply re-throw the original exception here.
+ *
+ * NOTE: Exceptions thrown in syncExec and asyncExec must be
+ * wrapped.
+ */
+ if (code != SWT.ERROR_FAILED_EXEC) {
+ if (throwable instanceof SWTError) throw (SWTError) throwable;
+ if (throwable instanceof SWTException) throw (SWTException) throwable;
+ }
+
+ String message = findErrorText (code);
+ if (detail != null) message += detail;
+ switch (code) {
+
+ /* Illegal Arguments (non-fatal) */
+ case ERROR_NULL_ARGUMENT:
+ case ERROR_CANNOT_BE_ZERO:
+ case ERROR_INVALID_ARGUMENT:
+ case ERROR_MENU_NOT_BAR:
+ case ERROR_MENU_NOT_DROP_DOWN:
+ case ERROR_MENU_NOT_POP_UP:
+ case ERROR_MENUITEM_NOT_CASCADE:
+ case ERROR_INVALID_PARENT:
+ case ERROR_INVALID_RANGE: {
+ throw new IllegalArgumentException (message);
+ }
+
+ /* SWT Exceptions (non-fatal) */
+ case ERROR_INVALID_SUBCLASS:
+ case ERROR_THREAD_INVALID_ACCESS:
+ case ERROR_WIDGET_DISPOSED:
+ case ERROR_GRAPHIC_DISPOSED:
+ case ERROR_DEVICE_DISPOSED:
+ case ERROR_FUNCTION_DISPOSED:
+ case ERROR_INVALID_IMAGE:
+ case ERROR_UNSUPPORTED_DEPTH:
+ case ERROR_UNSUPPORTED_FORMAT:
+ case ERROR_FAILED_EXEC:
+ case ERROR_FAILED_EVALUATE:
+ case ERROR_CANNOT_INVERT_MATRIX:
+ case ERROR_NO_GRAPHICS_LIBRARY:
+ case ERROR_INVALID_RETURN_VALUE:
+ case ERROR_IO: {
+ SWTException exception = new SWTException (code, message);
+ exception.throwable = throwable;
+ throw exception;
+ }
+
+ /* Operation System Errors (fatal, may occur only on some platforms) */
+ case ERROR_CANNOT_GET_COUNT:
+ case ERROR_CANNOT_GET_ENABLED:
+ case ERROR_CANNOT_GET_ITEM:
+ case ERROR_CANNOT_GET_ITEM_HEIGHT:
+ case ERROR_CANNOT_GET_SELECTION:
+ case ERROR_CANNOT_GET_TEXT:
+ case ERROR_CANNOT_SET_ENABLED:
+ case ERROR_CANNOT_SET_MENU:
+ case ERROR_CANNOT_SET_SELECTION:
+ case ERROR_CANNOT_SET_TEXT:
+ case ERROR_ITEM_NOT_ADDED:
+ case ERROR_ITEM_NOT_REMOVED:
+ case ERROR_NO_HANDLES:
+ //FALL THROUGH
+
+ /* SWT Errors (fatal, may occur only on some platforms) */
+ case ERROR_FAILED_LOAD_LIBRARY:
+ case ERROR_NO_MORE_CALLBACKS:
+ case ERROR_NOT_IMPLEMENTED:
+ case ERROR_UNSPECIFIED: {
+ SWTError error = new SWTError (code, message);
+ error.throwable = throwable;
+ throw error;
+ }
+ }
+
+ /* Unknown/Undefined Error */
+ SWTError error = new SWTError (code, message);
+ error.throwable = throwable;
+ throw error;
+}
+
+static {
+ /*
+ * These values represent bit masks that may need to
+ * expand in the future. Therefore they are not initialized
+ * in the declaration to stop the compiler from inlining.
+ */
+ BUTTON_MASK = BUTTON1 | BUTTON2 | BUTTON3 | BUTTON4 | BUTTON5;
+ MODIFIER_MASK = ALT | SHIFT | CTRL | COMMAND | ALT_GR;
+
+ /*
+ * These values can be different on different platforms.
+ * Therefore they are not initialized in the declaration
+ * to stop the compiler from inlining.
+ */
+ String platform = getPlatform ();
+ if ("cocoa".equals (platform)) { //$NON-NLS-1$
+ MOD1 = COMMAND;
+ MOD2 = SHIFT;
+ MOD3 = ALT;
+ MOD4 = CONTROL;
+ } else {
+ MOD1 = CONTROL;
+ MOD2 = SHIFT;
+ MOD3 = ALT;
+ MOD4 = 0;
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/SWTError.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/SWTError.java
new file mode 100644
index 000000000..03fc35342
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/SWTError.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt;
+
+/**
+ * This error is thrown whenever an unrecoverable error
+ * occurs internally in SWT. The message text and error code
+ * provide a further description of the problem. The exception
+ * has a throwable
field which holds the underlying
+ * throwable that caused the problem (if this information is
+ * available (i.e. it may be null)).
+ * null
+ * as the message is equivalent to specifying an empty string.
+ *
+ * @param message the detail message for the exception
+ */
+public SWTError (String message) {
+ this (SWT.ERROR_UNSPECIFIED, message);
+}
+
+/**
+ * Constructs a new instance of this class with its
+ * stack trace and error code filled in.
+ *
+ * @param code the SWT error code
+ */
+public SWTError (int code) {
+ this (code, SWT.findErrorText (code));
+}
+
+/**
+ * Constructs a new instance of this class with its
+ * stack trace, error code and message filled in.
+ * Specifying null
as the message is
+ * equivalent to specifying an empty string.
+ *
+ * @param code the SWT error code
+ * @param message the detail message for the exception
+ */
+public SWTError (int code, String message) {
+ super (message);
+ this.code = code;
+}
+
+/**
+ * Returns the underlying throwable that caused the problem,
+ * or null if this information is not available.
+ * throwable
field which holds the underlying
+ * exception that caused the problem (if this information is
+ * available (i.e. it may be null)).
+ * null
+ * as the message is equivalent to specifying an empty string.
+ *
+ * @param message the detail message for the exception
+ */
+public SWTException (String message) {
+ this (SWT.ERROR_UNSPECIFIED, message);
+}
+
+/**
+ * Constructs a new instance of this class with its
+ * stack trace and error code filled in.
+ *
+ * @param code the SWT error code
+ */
+public SWTException (int code) {
+ this (code, SWT.findErrorText (code));
+}
+
+/**
+ * Constructs a new instance of this class with its
+ * stack trace, error code and message filled in.
+ * Specifying null
as the message is
+ * equivalent to specifying an empty string.
+ *
+ * @param code the SWT error code
+ * @param message the detail message for the exception
+ */
+public SWTException (int code, String message) {
+ super (message);
+ this.code = code;
+}
+
+/**
+ * Returns the underlying throwable that caused the problem,
+ * or null if this information is not available.
+ *
+ *
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_STATE_CHANGED = 0x800A;
+
+ /**
+ * Send when an object has moved.
+ *
+ *
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_VALUE_CHANGED = 0x800E;
+
+ /**
+ * Send when the loading of a document has completed.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_DOCUMENT_LOAD_COMPLETE = 0x105;
+
+ /**
+ * Send when the loading of a document was interrupted.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_DOCUMENT_LOAD_STOPPED = 0x106;
+
+ /**
+ * Send when the document contents are being reloaded.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_DOCUMENT_RELOAD = 0x107;
+
+ /**
+ * Send when a slide changed in a presentation document
+ * or a page boundary was crossed in a word processing document.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_PAGE_CHANGED = 0x111;
+
+ /**
+ * Send when the caret moved from one section to the next.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_SECTION_CHANGED = 0x112;
+
+ /**
+ * Send when the count or attributes of an accessible object's actions have changed.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_ACTION_CHANGED = 0x100;
+
+ /**
+ * Send when the starting index of this link within the containing string has changed.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_HYPERLINK_START_INDEX_CHANGED = 0x10d;
+
+ /**
+ * Send when the ending index of this link within the containing string has changed.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_HYPERLINK_END_INDEX_CHANGED = 0x108;
+
+ /**
+ * Send when the number of anchors associated with this hyperlink object has changed.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_HYPERLINK_ANCHOR_COUNT_CHANGED = 0x109;
+
+ /**
+ * Send when the hyperlink selected state changed from selected to unselected
+ * or from unselected to selected.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_HYPERLINK_SELECTED_LINK_CHANGED = 0x10a;
+
+ /**
+ * Send when the hyperlink has been activated.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_HYPERLINK_ACTIVATED = 0x10b;
+
+ /**
+ * Send when one of the links associated with the hypertext object has been selected.
+ *
+ *
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_TABLE_CHANGED = 0x206;
+
+ /**
+ * Send when a table's row description has changed.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_TABLE_ROW_DESCRIPTION_CHANGED = 0x207;
+
+ /**
+ * Send when a table's row header has changed.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_TABLE_ROW_HEADER_CHANGED = 0x208;
+
+ /**
+ * Send when a table's summary has changed.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_TABLE_SUMMARY_CHANGED = 0x209;
+
+ /**
+ * Send when a text object's attributes have changed.
+ *
+ * @see #EVENT_ATTRIBUTE_CHANGED
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_TEXT_ATTRIBUTE_CHANGED = 0x20a;
+
+ /**
+ * Send when the caret has moved to a new position.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_TEXT_CARET_MOVED = 0x11b;
+
+ /**
+ * Send when the caret has moved from one column to the next.
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_TEXT_COLUMN_CHANGED = 0x11d;
+
+ /**
+ * Send when text was inserted or deleted.
+ *
+ *
+ *
+ * @since 3.6
+ */
+ public static final int EVENT_TEXT_CHANGED = 0x20c;
+
+ /**
+ * Some attribute of this object is affected by a target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_CONTROLLED_BY = 0;
+
+ /**
+ * This object is interactive and controls some attribute of a target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_CONTROLLER_FOR = 1;
+
+ /**
+ * This object is described by the target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_DESCRIBED_BY = 2;
+
+ /**
+ * This object is describes the target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_DESCRIPTION_FOR = 3;
+
+ /**
+ * This object is embedded by a target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_EMBEDDED_BY = 4;
+
+ /**
+ * This object embeds a target object. This relation can be used on a
+ * control's accessible to show where the content areas are.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_EMBEDS = 5;
+
+ /**
+ * Content flows to this object from a target object.
+ * This relation and RELATION_FLOWS_TO are useful to tie text and non-text
+ * objects together in order to allow assistive technology to follow the
+ * intended reading order.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_FLOWS_FROM = 6;
+
+ /**
+ * Content flows from this object to a target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_FLOWS_TO = 7;
+
+ /**
+ * This object is label for a target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_LABEL_FOR = 8;
+
+ /**
+ * This object is labelled by a target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_LABELLED_BY = 9;
+
+ /**
+ * This object is a member of a group of one or more objects. When
+ * there is more than one object in the group each member may have one and the
+ * same target, e.g. a grouping object. It is also possible that each member has
+ * multiple additional targets, e.g. one for every other member in the group.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_MEMBER_OF = 10;
+
+ /**
+ * This object is a child of a target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_NODE_CHILD_OF = 11;
+
+ /**
+ * This object is a parent window of the target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_PARENT_WINDOW_OF = 12;
+
+ /**
+ * This object is a transient component related to the target object.
+ * When this object is activated the target object doesn't lose focus.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_POPUP_FOR = 13;
+
+ /**
+ * This object is a sub window of a target object.
+ *
+ * @since 3.6
+ */
+ public static final int RELATION_SUBWINDOW_OF = 14;
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/Accessible.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/Accessible.java
new file mode 100644
index 000000000..05f69309b
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/Accessible.java
@@ -0,0 +1,5556 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.accessibility;
+
+import java.util.*;
+import java.util.List;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.ole.win32.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Instances of this class provide a bridge between application
+ * code and assistive technology clients. Many platforms provide
+ * default accessible behavior for most widgets, and this class
+ * allows that default behavior to be overridden. Applications
+ * can get the default Accessible object for a control by sending
+ * it getAccessible
, and then add an accessible listener
+ * to override simple items like the name and help string, or they
+ * can add an accessible control listener to override complex items.
+ * As a rule of thumb, an application would only want to use the
+ * accessible control listener to implement accessibility for a
+ * custom control.
+ *
+ * @see Control#getAccessible
+ * @see AccessibleListener
+ * @see AccessibleEvent
+ * @see AccessibleControlListener
+ * @see AccessibleControlEvent
+ * @see Accessibility snippets
+ * @see Sample code and further information
+ *
+ * @since 2.0
+ */
+public class Accessible {
+ static final int MAX_RELATION_TYPES = 15;
+ static final int TABLE_MODEL_CHANGE_SIZE = 5;
+ static final int TEXT_CHANGE_SIZE = 4;
+ static final int SCROLL_RATE = 100;
+ static final boolean DEBUG = false;
+ static final String PROPERTY_USEIA2 = "org.eclipse.swt.accessibility.UseIA2"; //$NON-NLS-1$
+ static boolean UseIA2 = true;
+ static int UniqueID = -0x10;
+ int refCount = 0, enumIndex = 0;
+ Runnable timer;
+ COMObject objIAccessible, objIEnumVARIANT, objIServiceProvider,
+ objIAccessibleApplication, /*objIAccessibleComponent,*/ objIAccessibleEditableText, objIAccessibleHyperlink,
+ objIAccessibleHypertext, /*objIAccessibleImage,*/ objIAccessibleTable2, objIAccessibleTableCell,
+ objIAccessibleValue; /* objIAccessibleRelation is defined in Relation class */
+ IAccessible iaccessible;
+ List
+ *
+ *
+ * @see #dispose
+ * @see Control#getAccessible
+ *
+ * @since 3.6
+ */
+ public Accessible(Accessible parent) {
+ this.parent = checkNull(parent);
+ this.control = parent.control;
+ parent.children.add(this);
+ AddRef();
+ }
+
+ /**
+ * @since 3.5
+ * @deprecated
+ */
+ @Deprecated
+ protected Accessible() {
+ }
+
+ Accessible(Control control) {
+ this.control = control;
+ long[] ppvObject = new long[1];
+ /* CreateStdAccessibleObject([in] hwnd, [in] idObject, [in] riidInterface, [out] ppvObject).
+ * AddRef has already been called on ppvObject by the callee and must be released by the caller.
+ */
+ int result = (int)COM.CreateStdAccessibleObject(control.handle, OS.OBJID_CLIENT, COM.IIDIAccessible, ppvObject);
+ /* The object needs to be checked, because if the CreateStdAccessibleObject()
+ * symbol is not found, the return value is S_OK.
+ */
+ if (ppvObject[0] == 0) return;
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
+ iaccessible = new IAccessible(ppvObject[0]);
+ createIAccessible();
+ AddRef();
+ }
+
+ Accessible(Accessible parent, long iaccessible_address) {
+ this(parent);
+ iaccessible = new IAccessible(iaccessible_address);
+ }
+
+ static Accessible checkNull (Accessible parent) {
+ if (parent == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return parent;
+ }
+
+ void createIAccessible() {
+ objIAccessible = new COMObject(new int[] {2,0,0,/*IA>>*/1,3,5,8,1,1,2,2,2,2,2,2,2,3,2,1,1,2,2,5,3,3,1,2,2,/*<Accessible
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
AccessibleListener
interface.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for a name, description, help, or keyboard shortcut string
+ *
+ * @exception IllegalArgumentException AccessibleControlListener
+ * interface.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for custom control specific information
+ *
+ * @exception IllegalArgumentException AccessibleTextListener
+ * and AccessibleTextExtendedListener
interfaces.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for custom text control specific information
+ *
+ * @exception IllegalArgumentException AccessibleActionListener
interface.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for AccessibleActionListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleEditableTextListener
interface.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for AccessibleEditableTextListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleHyperlinkListener
interface.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for AccessibleHyperlinkListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleTableListener
interface.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for AccessibleTableListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleTableCellListener
interface.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for AccessibleTableCellListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleValueListener
interface.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for AccessibleValueListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleAttributeListener
interface.
+ *
+ * @param listener the listener that should be notified when the receiver
+ * is asked for AccessibleAttributeListener
interface properties
+ *
+ * @exception IllegalArgumentException ACC
constant beginning with RELATION_* indicating the type of relation
+ * @param target the accessible that is the target for this relation
+ * @exception IllegalArgumentException ERROR_NULL_ARGUMENT - if the Accessible target is null
+ * @since 3.6
+ */
+ public void addRelation(int type, Accessible target) {
+ checkWidget();
+ if (target == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (relations[type] == null) {
+ relations[type] = new Relation(this, type);
+ }
+ relations[type].addTarget(target);
+ }
+
+ /**
+ * Disposes of the operating system resources associated with
+ * the receiver, and removes the receiver from its parent's
+ * list of children.
+ *
+ * This method should be called when an accessible that was created
+ * with the public constructor Accessible(Accessible parent)
+ * is no longer needed. You do not need to call this when the receiver's
+ * control is disposed, because all Accessible
instances
+ * associated with a control are released when the control is disposed.
+ * It is also not necessary to call this for instances of Accessible
+ * that were retrieved with Control.getAccessible()
.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for Accessible
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for Accessible
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
AccessibleActionListener
interface.
+ *
+ * @param listener the listener that should no longer be notified when the receiver
+ * is asked for AccessibleActionListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleEditableTextListener
interface.
+ *
+ * @param listener the listener that should no longer be notified when the receiver
+ * is asked for AccessibleEditableTextListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleHyperlinkListener
interface.
+ *
+ * @param listener the listener that should no longer be notified when the receiver
+ * is asked for AccessibleHyperlinkListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleTableListener
interface.
+ *
+ * @param listener the listener that should no longer be notified when the receiver
+ * is asked for AccessibleTableListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleTableCellListener
interface.
+ *
+ * @param listener the listener that should no longer be notified when the receiver
+ * is asked for AccessibleTableCellListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleValueListener
interface.
+ *
+ * @param listener the listener that should no longer be notified when the receiver
+ * is asked for AccessibleValueListener
interface properties
+ *
+ * @exception IllegalArgumentException AccessibleAttributeListener
interface.
+ *
+ * @param listener the listener that should no longer be notified when the receiver
+ * is asked for AccessibleAttributeListener
interface properties
+ *
+ * @exception IllegalArgumentException ACC
constant beginning with RELATION_* indicating the type of relation
+ * @param target the accessible that is the target for this relation
+ * @exception IllegalArgumentException ERROR_NULL_ARGUMENT - if the Accessible target is null
+ * @since 3.6
+ */
+ public void removeRelation(int type, Accessible target) {
+ checkWidget();
+ if (target == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ Relation relation = relations[type];
+ if (relation != null) {
+ relation.removeTarget(target);
+ if (!relation.hasTargets()) {
+ relations[type].Release();
+ relations[type] = null;
+ }
+ }
+ }
+
+ /**
+ * Sends a message with event-specific data to accessible clients
+ * indicating that something has changed within a custom control.
+ *
+ * @param event an ACC
constant beginning with EVENT_* indicating the message to send
+ * @param eventData an object containing event-specific data, or null if there is no event-specific data
+ * (eventData is specified in the documentation for individual ACC.EVENT_* constants)
+ *
+ * @exception SWTException ACC
constant beginning with EVENT_* indicating the message to send
+ * @param eventData an object containing event-specific data, or null if there is no event-specific data
+ * (eventData is specified in the documentation for individual ACC.EVENT_* constants)
+ * @param childID an identifier specifying a child of the control
+ *
+ * @exception SWTException ACC.TEXT_INSERT
+ * or ACC.TEXT_DELETE
+ * @param startIndex the text index within the control where the insertion or deletion begins
+ * @param length the non-negative length in characters of the insertion or deletion
+ *
+ * @exception SWTException AccessibleActionListener
interface.
+ *
+ * Classes that wish to deal with AccessibleAction
events can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
+ * If there are more than one, the first one (index 0) is considered the + * "default" action of the object. + *
+ * + * @param e an event object containing the following fields:+ * The returned string is of the following form: mnemonic;accelerator + * for example: "C;CTRL+C" for the Copy item in a typical Edit menu. + *
+ * + * @param e an event object containing the following fields:+ * There is no need to implement this method for single action controls + * since that would be redundant with AccessibleControlListener.getDefaultAction. + *
+ * + * @param e an event object containing the following fields:
+ * After creating an instance of a class that implements
+ * this interface it can be added to an accessible using the
+ * addAccessibleActionListener
method and removed using
+ * the removeAccessibleActionListener
method.
+ *
+ * If there are more than one, the first one (index 0) is considered the + * "default" action of the object. + *
+ * + * @param e an event object containing the following fields:+ * The returned string is of the following form: mnemonic;accelerator + * for example: "C;CTRL+C" for the Copy item in a typical Edit menu. + *
+ * + * @param e an event object containing the following fields:+ * There is no need to implement this method for single action controls + * since that would be redundant with AccessibleControlListener.getDefaultAction. + *
+ * + * @param e an event object containing the following fields:AccessibleListener
interface.
+ *
+ * Classes that wish to deal with AccessibleEvent
s can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
+ * Note: Accessibility clients use child identifiers to specify + * whether they want information about a control or one of its children. + * Child identifiers are increasing integers beginning with 0. + * The identifier CHILDID_SELF represents the control itself. + *
+ * + * @see AccessibleListener + * @see AccessibleEvent + * @see Sample code and further information + * + * @since 2.0 + */ +public abstract class AccessibleAdapter implements AccessibleListener { + + /** + * Sent when an accessibility client requests the name + * of the control, or the name of a child of the control. + * The default behavior is to do nothing. + *
+ * Return the name of the control or specified child in the
+ * result
field of the event object. Returning
+ * an empty string tells the client that the control or child
+ * does not have a name, and returning null tells the client
+ * to use the platform name.
+ *
+ * The information in this property should be similar to the help + * provided by toolTipText. It describes what the control or child + * does or how to use it, as opposed to getDescription, which + * describes appearance. + *
+ * Return the help string of the control or specified child in
+ * the result
field of the event object. Returning
+ * an empty string tells the client that the control or child
+ * does not have a help string, and returning null tells the
+ * client to use the platform help string.
+ *
+ * A keyboard shortcut can either be a mnemonic, or an accelerator. + * As a general rule, if the control or child can receive keyboard focus, + * then you should expose its mnemonic, and if it cannot receive keyboard + * focus, then you should expose its accelerator. + *
+ * Return the keyboard shortcut string of the control or specified child
+ * in the result
field of the event object. Returning an
+ * empty string tells the client that the control or child does not
+ * have a keyboard shortcut string, and returning null tells the client
+ * to use the platform keyboard shortcut string.
+ *
+ * This is a textual description of the control or child's visual + * appearance, which is typically only necessary if it cannot be + * determined from other properties such as role. + *
+ * Return the description of the control or specified child in
+ * the result
field of the event object. Returning
+ * an empty string tells the client that the control or child
+ * does not have a description, and returning null tells the
+ * client to use the platform description.
+ *
AccessibleAttributeListener
interface.
+ *
+ * Classes that wish to deal with AccessibleAttribute
events can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
SWT#LEFT
, SWT#RIGHT
or SWT#CENTER
+ * After creating an instance of a class that implements
+ * this interface it can be added to an accessible using the
+ * addAccessibleAttributeListener
method and removed using
+ * the removeAccessibleAttributeListener
method.
+ *
SWT#LEFT
, SWT#RIGHT
or SWT#CENTER
AccessibleControlListener
interface.
+ *
+ * Classes that wish to deal with AccessibleControlEvent
s can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
+ * Note: Accessibility clients use child identifiers to specify + * whether they want information about a control or one of its children. + * Child identifiers are increasing integers beginning with 0. + * The identifier CHILDID_SELF represents the control itself. + * When returning a child identifier to a client, you may use CHILDID_NONE + * to indicate that no child or control has the required information. + *
+ * Note: This adapter is typically used by implementors of + * a custom control to provide very detailed information about + * the control instance to accessibility clients. + *
+ * + * @see AccessibleControlListener + * @see AccessibleControlEvent + * @see Sample code and further information + * + * @since 2.0 + */ +public abstract class AccessibleControlAdapter implements AccessibleControlListener { + + /** + * Sent when an accessibility client requests the identifier + * of the control child at the specified display coordinates. + * The default behavior is to do nothing. + *
+ * Return the identifier of the child at display point (x, y)
+ * in the childID
field of the event object.
+ * Return CHILDID_SELF if point (x, y) is in the control itself
+ * and not in any child. Return CHILDID_NONE if point (x, y)
+ * is not contained in either the control or any of its children.
+ *
+ * Return a rectangle describing the location of the specified
+ * control or child in the x, y, width, and height
+ * fields of the event object.
+ *
+ * The childID field in the event object can be one of the following:
+ *
+ * Return the number of child items in the detail
+ * field of the event object.
+ *
+ * This string is typically a verb describing what the user does to it. + * For example, a Push Button's default action is "Press", a Check Button's + * is "Check" or "UnCheck", and List items have the default action "Double Click". + *
+ * Return a string describing the default action of the specified
+ * control or child in the result
field of the event object.
+ * Returning null tells the client to use the platform default action string.
+ *
+ * Return the identifier of the child that has focus in the
+ * childID
field of the event object.
+ * Return CHILDID_SELF if the control itself has keyboard focus.
+ * Return CHILDID_NONE if neither the control nor any of its children has focus.
+ *
+ * Return a role constant (constant defined in ACC beginning with ROLE_)
+ * that describes the role of the specified control or child in the
+ * detail
field of the event object.
+ *
+ * Return the identifier of the selected child in the
+ * childID
field of the event object.
+ * Return CHILDID_SELF if the control itself is selected.
+ * Return CHILDID_MULTIPLE if multiple children are selected, and return an array of childIDs in the children
field.
+ * Return CHILDID_NONE if neither the control nor any of its children are selected.
+ *
+ * Return a state mask (mask bit constants defined in ACC beginning with STATE_)
+ * that describes the current state of the specified control or child in the
+ * detail
field of the event object.
+ *
+ * Many controls do not return a value. Examples of controls + * that do are: Combo returns the text string, Text returns + * its contents, ProgressBar returns a string representing a + * percentage, and Tree items return a string representing + * their level in the tree. + *
+ * Return a string describing the value of the specified control
+ * or child in the result
field of the event object.
+ * Returning null tells the client to use the platform value string.
+ *
+ * Return the children as an array of childIDs or accessibles in the
+ * children
field of the event object.
+ *
+ * Note: The meaning of each field depends on the + * message that was sent. + *
+ * + * @see AccessibleControlListener + * @see AccessibleControlAdapter + * @see Sample code and further information + * + * @since 2.0 + */ +public class AccessibleControlEvent extends EventObject { + public int childID; // IN/OUT + public Accessible accessible; // OUT + public int x, y; // IN/OUT + public int width, height; // OUT + public int detail; // IN/OUT + public String result; // OUT + public Object children[]; // [OUT] + + static final long serialVersionUID = 3257281444169529141L; + +/** + * Constructs a new instance of this class. + * + * @param source the object that fired the event + */ +public AccessibleControlEvent(Object source) { + super(source); +} + +/** + * Returns a string containing a concise, human-readable + * description of the receiver. + * + * @return a string representation of the event + */ +@Override +public String toString () { + return "AccessibleControlEvent {childID=" + childID + //$NON-NLS-1$ + " accessible=" + accessible + //$NON-NLS-1$ + " x=" + x + //$NON-NLS-1$ + " y=" + y + //$NON-NLS-1$ + " width=" + width + //$NON-NLS-1$ + " height=" + height + //$NON-NLS-1$ + " detail=" + detail + //$NON-NLS-1$ + " result=" + result + //$NON-NLS-1$ + "}"; //$NON-NLS-1$ +} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleControlListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleControlListener.java new file mode 100644 index 000000000..e938a35ad --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleControlListener.java @@ -0,0 +1,248 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.accessibility; + + +import org.eclipse.swt.internal.*; + +/** + * Classes that implement this interface provide methods + * that deal with the events that are generated when an + * accessibility client sends a message to a control. + *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ * addAccessibleControlListener
method and removed
+ * using the removeAccessibleControlListener
method.
+ * When a client requests information the appropriate method
+ * will be invoked.
+ *
+ * Note: Accessibility clients use child identifiers to specify + * whether they want information about a control or one of its children. + * Child identifiers are increasing integers beginning with 0. + * The identifier CHILDID_SELF represents the control itself. + *
+ * Note: This interface is typically used by implementors of + * a custom control to provide very detailed information about + * the control instance to accessibility clients. + *
+ * + * @see AccessibleControlAdapter + * @see AccessibleControlEvent + * + * @since 2.0 + */ +public interface AccessibleControlListener extends SWTEventListener { + + /** + * Sent when an accessibility client requests the identifier + * of the control child at the specified display coordinates. + *
+ * Return the identifier of the child at display point (x, y)
+ * in the childID
field of the event object.
+ * Return CHILDID_SELF if point (x, y) is in the control itself
+ * and not in any child. Return CHILDID_NONE if point (x, y)
+ * is not contained in either the control or any of its children.
+ *
+ * Return a rectangle describing the location of the specified
+ * control or child in the x, y, width, and height
+ * fields of the event object.
+ *
+ * The childID field in the event object can be one of the following:
+ *
+ * Return the number of child items in the detail
+ * field of the event object.
+ *
+ * This string is typically a verb describing what the user does to it. + * For example, a Push Button's default action is "Press", a Check Button's + * is "Check" or "UnCheck", and List items have the default action "Double Click". + *
+ * Return a string describing the default action of the specified
+ * control or child in the result
field of the event object.
+ * Returning null tells the client to use the platform default action string.
+ *
+ * Return the identifier of the child that has focus in the
+ * childID
field of the event object.
+ * Return CHILDID_SELF if the control itself has keyboard focus.
+ * Return CHILDID_NONE if neither the control nor any of its children has focus.
+ *
+ * Return a role constant (constant defined in ACC beginning with ROLE_)
+ * that describes the role of the specified control or child in the
+ * detail
field of the event object.
+ *
+ * Return the identifier of the selected child in the
+ * childID
field of the event object.
+ * Return CHILDID_SELF if the control itself is selected.
+ * Return CHILDID_MULTIPLE if multiple children are selected, and return an array of childIDs in the children
field.
+ * Return CHILDID_NONE if neither the control nor any of its children are selected.
+ *
+ * Return a state mask (mask bit constants defined in ACC beginning with STATE_)
+ * that describes the current state of the specified control or child in the
+ * detail
field of the event object.
+ *
+ * Many controls do not return a value. Examples of controls + * that do are: Combo returns the text string, Text returns + * its contents, ProgressBar returns a string representing a + * percentage, and Tree items return a string representing + * their level in the tree. + *
+ * Return a string describing the value of the specified control
+ * or child in the result
field of the event object.
+ * Returning null tells the client to use the platform value string.
+ *
+ * Return the children as an array of childIDs or accessibles in the
+ * children
field of the event object.
+ *
AccessibleEditableTextListener
interface.
+ *
+ * Classes that wish to deal with AccessibleEditableText
events can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
start
offset
+ * and extending to the character at offset end - 1
to the clipboard.
+ *
+ * @param e an event object containing the following information:start
offset
+ * and extending to the character at offset end - 1
to the clipboard.
+ *
+ * @param e an event object containing the following information:start
offset.
+ *
+ * @param e an event object containing the following information:start
offset
+ * and extending to the character at offset end - 1
by the specified string.
+ *
+ * This event notification is also used to delete text if string
is an empty string,
+ * or to insert text at the leading edge of the specified offset if start
and end
are equal.
+ *
start
and extending to end - 1
start
offset
+ * and extending to the character at offset end - 1
by the specified set of attributes.
+ *
+ * @param e an event object containing the following information:null
otherwise.
+ *
+ * @see AccessibleEditableTextListener#copyText
+ * @see AccessibleEditableTextListener#cutText
+ * @see AccessibleEditableTextListener#pasteText
+ * @see AccessibleEditableTextListener#replaceText
+ */
+ public String result;
+
+ static final long serialVersionUID = -5045447704486894646L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param source the object that fired the event
+ */
+public AccessibleEditableTextEvent(Object source) {
+ super(source);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString () {
+ return "AccessibleEditableTextEvent {" //$NON-NLS-1$
+ + "start=" + start //$NON-NLS-1$
+ + " end=" + end //$NON-NLS-1$
+ + " string=" + string //$NON-NLS-1$
+ + " result=" + result //$NON-NLS-1$
+ + "}"; //$NON-NLS-1$
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleEditableTextListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleEditableTextListener.java
new file mode 100644
index 000000000..c7a930bc0
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleEditableTextListener.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.accessibility;
+
+import org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * Classes which implement this interface provide methods
+ * that handle AccessibleEditableText events.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to an accessible using the
+ * addAccessibleEditableTextListener
method and removed using
+ * the removeAccessibleEditableTextListener
method.
+ *
start
offset
+ * and extending to the character at offset end - 1
to the clipboard.
+ *
+ * @param e an event object containing the following information:start
offset
+ * and extending to the character at offset end - 1
to the clipboard.
+ *
+ * @param e an event object containing the following information:start
offset.
+ *
+ * @param e an event object containing the following information:start
offset
+ * and extending to the character at offset end - 1
by the specified string.
+ *
+ * This event notification is also used to delete text if string
is an empty string,
+ * or to insert text at the leading edge of the specified offset if start
and end
are equal.
+ *
start
and extending to end - 1
start
offset
+ * and extending to the character at offset end - 1
by the specified set of attributes.
+ *
+ * @param e an event object containing the following information:+ * Note: The meaning of the result field depends + * on the message that was sent. + *
+ * + * @see AccessibleListener + * @see AccessibleAdapter + * @see Sample code and further information + * + * @since 2.0 + */ +public class AccessibleEvent extends EventObject { + /** + * The value of this field is set by an accessibility client + * before the accessible listener method is called. + * ChildID can be CHILDID_SELF, representing the control itself, + * or a 0-based integer representing a specific child of the control. + */ + public int childID; + + /** + * The value of this field must be set in the accessible listener + * method before returning. + * What to set it to depends on the listener method called, and + * the childID specified by the client. + */ + public String result; + + static final long serialVersionUID = 3257567304224026934L; + +/** + * Constructs a new instance of this class. + * + * @param source the object that fired the event + */ +public AccessibleEvent(Object source) { + super(source); +} + +/** + * Returns a string containing a concise, human-readable + * description of the receiver. + * + * @return a string representation of the event + */ +@Override +public String toString () { + return "AccessibleEvent {childID=" + childID + " result=" + result + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ +} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleHyperlinkAdapter.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleHyperlinkAdapter.java new file mode 100644 index 000000000..18254f70e --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleHyperlinkAdapter.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.accessibility; + +/** + * This adapter class provides default implementations for the + * methods in theAccessibleHyperlinkListener
interface.
+ *
+ * Classes that wish to deal with AccessibleHyperlink
events can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
+ * The returned value is related to the AccessibleTextExtended interface of the object that + * owns this hyperlink. + *
+ * + * @param e an event object containing the following fields:+ * The returned value is related to the AccessibleTextExtended interface of the object that + * owns this hyperlink. The character at the index is not part of the hypertext. + *
+ * + * @param e an event object containing the following fields:
+ * After creating an instance of a class that implements
+ * this interface it can be added to an accessible using the
+ * addAccessibleHyperlinkListener
method and removed using
+ * the removeAccessibleHyperlinkListener
method.
+ *
+ * The returned value is related to the AccessibleTextExtended interface of the object that + * owns this hyperlink. + *
+ * + * @param e an event object containing the following fields:+ * The returned value is related to the AccessibleTextExtended interface of the object that + * owns this hyperlink. The character at the index is not part of the hypertext. + *
+ * + * @param e an event object containing the following fields:
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ * addAccessibleListener
method and removed
+ * using the removeAccessibleListener
method.
+ * When a client requests information, the appropriate method
+ * will be invoked.
+ *
+ * Note: Accessibility clients use child identifiers to specify + * whether they want information about a control or one of its children. + * Child identifiers are increasing integers beginning with 0. + * The identifier CHILDID_SELF represents the control itself. + *
+ * + * @see AccessibleAdapter + * @see AccessibleEvent + * + * @since 2.0 + */ +public interface AccessibleListener extends SWTEventListener { + + /** + * Sent when an accessibility client requests the name + * of the control, or the name of a child of the control. + *
+ * Return the name of the control or specified child in the
+ * result
field of the event object. Returning
+ * an empty string tells the client that the control or child
+ * does not have a name, and returning null tells the client
+ * to use the platform name.
+ *
+ * The information in this property should be similar to the help + * provided by toolTipText. It describes what the control or child + * does or how to use it, as opposed to getDescription, which + * describes appearance. + *
+ * Return the help string of the control or specified child in
+ * the result
field of the event object. Returning
+ * an empty string tells the client that the control or child
+ * does not have a help string, and returning null tells the
+ * client to use the platform help string.
+ *
+ * A keyboard shortcut can either be a mnemonic, or an accelerator. + * As a general rule, if the control or child can receive keyboard focus, + * then you should expose its mnemonic, and if it cannot receive keyboard + * focus, then you should expose its accelerator. + *
+ * Return the keyboard shortcut string of the control or specified child
+ * in the result
field of the event object. Returning an
+ * empty string tells the client that the control or child does not
+ * have a keyboard shortcut string, and returning null tells the client
+ * to use the platform keyboard shortcut string.
+ *
+ * This is a textual description of the control or child's visual + * appearance, which is typically only necessary if it cannot be + * determined from other properties such as role. + *
+ * Return the description of the control or specified child in
+ * the result
field of the event object. Returning
+ * an empty string tells the client that the control or child
+ * does not have a description, and returning null tells the
+ * client to use the platform description.
+ *
AccessibleListener
for the
+ * {@link #getName(AccessibleEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return AccessibleListener
+ * @since 3.106
+ */
+ public static AccessibleListener getNameAdapter(ConsumerAccessibleListener
for the
+ * {@link #getHelp(AccessibleEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return AccessibleListener
+ * @since 3.106
+ */
+ public static AccessibleListener getHelpAdapter(ConsumerAccessibleListener
for the
+ * {@link #getKeyboardShortcut(AccessibleEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return AccessibleListener
+ * @since 3.106
+ */
+ public static AccessibleListener getKeyboardShortcutAdapter(ConsumerAccessibleListener
for the
+ * {@link #getDescription(AccessibleEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return AccessibleListener
+ * @since 3.106
+ */
+ public static AccessibleListener getDescriptionAdapter(ConsumerAccessibleTableListener
interface.
+ *
+ * Classes that wish to deal with AccessibleTable
events can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
+ * Many methods in this adapter return cell accessible objects,
+ * which should implement AccessibleTableCellListener
.
+ *
AccessibleTableCellListener
interface.
+ *
+ * Classes that wish to deal with AccessibleTableCell
events can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
+ * This is 1 if the specified cell is only in one column, or + * more than 1 if the specified cell spans multiple columns. + *
+ * + * @param e an event object containing the following fields:+ * This is 1 if the specified cell is only in one row, or + * more than 1 if the specified cell spans multiple rows. + *
+ * + * @param e an event object containing the following fields:
+ * After creating an instance of a class that implements
+ * this interface it can be added to an accessible using the
+ * addAccessibleTableCellListener
method and removed using
+ * the removeAccessibleTableCellListener
method.
+ *
+ * This is 1 if the specified cell is only in one column, or + * more than 1 if the specified cell spans multiple columns. + *
+ * + * @param e an event object containing the following fields:+ * This is 1 if the specified cell is only in one row, or + * more than 1 if the specified cell spans multiple rows. + *
+ * + * @param e an event object containing the following fields:
+ * After creating an instance of a class that implements
+ * this interface it can be added to an accessible using the
+ * addAccessibleTableListener
method and removed using
+ * the removeAccessibleTableListener
method.
+ *
+ * Many methods in this listener return cell accessible objects,
+ * which should implement AccessibleTableCellListener
.
+ *
AccessibleTextListener
interface.
+ *
+ * Classes that wish to deal with AccessibleTextEvent
s can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
+ * Note: Accessibility clients use child identifiers to specify + * whether they want information about a control or one of its children. + * Child identifiers are increasing integers beginning with 0. + * The identifier CHILDID_SELF represents the control itself. + * When returning a child identifier to a client, you may use CHILDID_NONE + * to indicate that no child or control has the required information. + *
+ * Note: This adapter is typically used by implementors of + * a custom control to provide very detailed information about + * the control instance to accessibility clients. + *
+ * + * @see AccessibleTextListener + * @see AccessibleTextEvent + * @see Sample code and further information + * + * @since 3.0 + */ +public abstract class AccessibleTextAdapter implements AccessibleTextListener { + + /** + * Sent when an accessibility client requests the current character offset + * of the text caret. + * The default behavior is to do nothing. + *
+ * Return the caret offset in the offset
+ * field of the event object.
+ *
+ * Return the selection start offset and non-negative length in the
+ * offset
and length
fields of the event object.
+ *
+ * Note: The meaning of each field depends on the + * message that was sent. + *
+ * + * @see AccessibleTextListener + * @see AccessibleTextAdapter + * @see Sample code and further information + * + * @since 3.0 + */ +public class AccessibleTextEvent extends EventObject { + public int childID; // IN + public int offset, length; // OUT + /** @since 3.6 */ + public Accessible accessible; + + /** + * The value of this field must be set in the accessible text extended listener method + * before returning. What to set it to depends on the listener method called. + * @since 3.6 + */ + public String result; + + /** @since 3.6 */ + public int count; + /** @since 3.6 */ + public int index; + /** @since 3.6 */ + public int start, end; + /** @since 3.6 */ + public int type; + /** @since 3.6 */ + public int x, y, width, height; + /** @since 3.6 */ + public int [] ranges; + /** @since 3.6 */ + public Rectangle [] rectangles; + + static final long serialVersionUID = 3977019530868308275L; + +/** + * Constructs a new instance of this class. + * + * @param source the object that fired the event + */ +public AccessibleTextEvent (Object source) { + super (source); +} + +/** + * Returns a string containing a concise, human-readable + * description of the receiver. + * + * @return a string representation of the event + */ +@Override +public String toString () { + return "AccessibleTextEvent {childID=" + childID + //$NON-NLS-1$ + " offset=" + offset + //$NON-NLS-1$ + " length=" + length + //$NON-NLS-1$ + "}"; //$NON-NLS-1$ +} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleTextExtendedAdapter.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleTextExtendedAdapter.java new file mode 100644 index 000000000..94abb1c1b --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/accessibility/AccessibleTextExtendedAdapter.java @@ -0,0 +1,311 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.accessibility; + +/** + * This adapter class provides default implementations for the + * methods in theAccessibleTextExtendedListener
interface.
+ *
+ * Classes that wish to deal with AccessibleTextExtended
events can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
+ * This is the case when a link spans the given character index. + *
+ * @param e an event object containing the following fields:+ * Partially visible characters are included in the returned ranges. + *
+ * + * @param e an event object containing the following fields:+ * Returns the substring of the specified boundary type that is located count + * positions from the given character range. Also returns the start and end + * offsets of the returned substring. + *
+ * For example, if the boundary type is TEXT_BOUNDARY_WORD, then the complete + * word that is located count words from the specified range is returned. + * If count is negative, then return the word that is count words before start. + * If count is positive, then return the word that is count words after end. + * If count is zero, start and end are the same, so return the word at start. + *
+ * The whole text can be requested by passing start == 0 and end == getCharacterCount, + * TEXT_BOUNDARY_ALL, and 0 for count. Alternatively the whole text can be requested + * by calling AccessibleControlListener.getValue(). + *
+ * If start and end are valid, but no suitable word (or other boundary type) is found, + * the returned string is null and the returned range is degenerate (start == end). + *
+ * + * @param e an event object containing the following fields:+ * Typically, the text range will represent a single character, i.e. end - start = 1, + * therefore providers should optimize for this case. + *
+ * Note: The virtual character after the last character of the represented text, + * i.e. the one at offset getCharacterCount, is a special case. It represents the + * current input position and will therefore typically be queried by AT more + * often than other positions. Because it does not represent an existing character + * its bounding box is defined in relation to preceding characters. It should be + * roughly equivalent to the bounding box of some character when inserted at the + * end of the text; its height typically being the maximal height of all the + * characters in the text or the height of the preceding character, its width + * being at least one pixel so that the bounding box is not degenerate. + *
+ * + * @param e an event object containing the following fields:+ * Partially visible characters are included in the returned ranges. + *
+ * + * @param e an event object containing the following fields:+ * The caret position is that of the character logically following it, + * e.g. to the right of it in a left to right language. + * The caret is actually placed to the leading side of the character with + * that offset. An offset of 0 places the caret so that the next insertion + * goes before the first character. An offset of getCharacterCount places + * the caret so that the next insertion goes after the last character. + *
+ * Setting the caret position may or may not alter the current selection. A + * change of the selection is notified to the accessibility event listeners with + * an EVENT_TEXT_SELECTION_CHANGED event. + *
+ * When the new caret position differs from the old one, this is notified to the + * accessibility event listeners with an EVENT_TEXT_CARET_MOVED event. + *
+ * + * @param e an event object containing the following fields:
+ * After creating an instance of a class that implements
+ * this interface it can be added to an accessible using the
+ * addAccessibleTextListener
method and removed using
+ * the removeAccessibleTextListener
method.
+ *
+ * This is the case when a link spans the given character index. + *
+ * @param e an event object containing the following fields:+ * Partially visible characters are included in the returned ranges. + *
+ * + * @param e an event object containing the following fields:+ * Returns the substring of the specified boundary type that is located count + * positions from the given character range. Also returns the start and end + * offsets of the returned substring. + *
+ * For example, if the boundary type is TEXT_BOUNDARY_WORD, then the complete + * word that is located count words from the specified range is returned. + * If count is negative, then return the word that is count words before start. + * If count is positive, then return the word that is count words after end. + * If count is zero, start and end are the same, so return the word at start. + *
+ * The whole text can be requested by passing start == 0 and end == getCharacterCount, + * TEXT_BOUNDARY_ALL, and 0 for count. Alternatively the whole text can be requested + * by calling AccessibleControlListener.getValue(). + *
+ * If start and end are valid, but no suitable word (or other boundary type) is found, + * the returned string is null and the returned range is degenerate (start == end). + *
+ * + * @param e an event object containing the following fields:+ * Typically, the text range will represent a single character, i.e. end - start = 1, + * therefore providers should optimize for this case. + *
+ * Note: The virtual character after the last character of the represented text, + * i.e. the one at offset getCharacterCount, is a special case. It represents the + * current input position and will therefore typically be queried by AT more + * often than other positions. Because it does not represent an existing character + * its bounding box is defined in relation to preceding characters. It should be + * roughly equivalent to the bounding box of some character when inserted at the + * end of the text; its height typically being the maximal height of all the + * characters in the text or the height of the preceding character, its width + * being at least one pixel so that the bounding box is not degenerate. + *
+ * + * @param e an event object containing the following fields:+ * Partially visible characters are included in the returned ranges. + *
+ * + * @param e an event object containing the following fields:+ * The caret position is that of the character logically following it, + * e.g. to the right of it in a left to right language. + * The caret is actually placed to the leading side of the character with + * that offset. An offset of 0 places the caret so that the next insertion + * goes before the first character. An offset of getCharacterCount places + * the caret so that the next insertion goes after the last character. + *
+ * Setting the caret position may or may not alter the current selection. A + * change of the selection is notified to the accessibility event listeners with + * an EVENT_TEXT_SELECTION_CHANGED event. + *
+ * When the new caret position differs from the old one, this is notified to the + * accessibility event listeners with an EVENT_TEXT_CARET_MOVED event. + *
+ * + * @param e an event object containing the following fields:
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ * addAccessibleTextListener
method and removed
+ * using the removeAccessibleTextListener
method.
+ * When a client requests information the appropriate method
+ * will be invoked.
+ *
+ * Note: Accessibility clients use child identifiers to specify + * whether they want information about a control or one of its children. + * Child identifiers are increasing integers beginning with 0. + * The identifier CHILDID_SELF represents the control itself. + *
+ * Note: This interface is typically used by implementors of + * a custom control to provide very detailed information about + * the control instance to accessibility clients. + *
+ * + * @see AccessibleTextAdapter + * @see AccessibleTextEvent + * + * @since 3.0 + */ +public interface AccessibleTextListener extends SWTEventListener { + + /** + * Sent when an accessibility client requests the current character offset + * of the text caret. + *
+ * Return the caret offset in the offset
+ * field of the event object.
+ *
+ * Return the selection start offset and non-negative length in the
+ * offset
and length
fields of the event object.
+ *
AccessibleValueListener
interface.
+ *
+ * Classes that wish to deal with AccessibleValue
events can
+ * extend this class and override only the methods that they are
+ * interested in.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to an accessible using the
+ * addAccessibleValueListener
method and removed using
+ * the removeAccessibleValueListener
method.
+ *
null
.
+ */
+ public static String embeddedFrameClass;
+
+ /**
+ * Key for looking up the embedded frame for a Composite using
+ * getData().
+ */
+ static String EMBEDDED_FRAME_KEY = "org.eclipse.swt.awt.SWT_AWT.embeddedFrame";
+
+static boolean loaded, swingInitialized;
+
+static native final long getAWTHandle (Canvas canvas);
+static native final Object initFrame (long handle, String className);
+static native final void synthesizeWindowActivation (Frame frame, boolean doActivate);
+
+static synchronized void loadLibrary () {
+ if (loaded) return;
+ loaded = true;
+ Toolkit.getDefaultToolkit();
+ /*
+ * Note that the jawt library is loaded explicitly
+ * because it cannot be found by the library loader.
+ * All exceptions are caught because the library may
+ * have been loaded already.
+ */
+ try {
+ System.loadLibrary("jawt");
+ } catch (Throwable e) {}
+ Library.loadLibrary("swt-awt");
+}
+
+static synchronized void initializeSwing() {
+ if (swingInitialized) return;
+ swingInitialized = true;
+ try {
+ /* Initialize the default focus traversal policy */
+ Class> clazz = Class.forName("javax.swing.UIManager");
+ Method method = clazz.getMethod("getDefaults");
+ if (method != null) method.invoke(clazz);
+ } catch (Throwable e) {}
+}
+
+/**
+ * Returns a java.awt.Frame
which is the embedded frame
+ * associated with the specified composite.
+ *
+ * @param parent the parent Composite
of the java.awt.Frame
+ * @return a java.awt.Frame
the embedded frame or null
.
+ *
+ * @exception IllegalArgumentException java.awt.Frame
. This frame is the root for
+ * the AWT components that will be embedded within the composite. In order
+ * for the embedding to succeed, the composite must have been created
+ * with the SWT.EMBEDDED style.
+ *
+ * IMPORTANT: As of JDK1.5, the embedded frame does not receive mouse events.
+ * When a lightweight component is added as a child of the embedded frame,
+ * the cursor does not change. In order to work around both these problems, it is
+ * strongly recommended that a heavyweight component such as java.awt.Panel
+ * be added to the frame as the root of all components.
+ *
Composite
of the new java.awt.Frame
+ * @return a java.awt.Frame
to be the parent of the embedded AWT components
+ *
+ * @exception IllegalArgumentException Shell
. This Shell is the root for
+ * the SWT widgets that will be embedded within the AWT canvas.
+ *
+ * @param display the display for the new Shell
+ * @param parent the parent java.awt.Canvas
of the new Shell
+ * @return a Shell
to be the parent of the embedded SWT widgets
+ *
+ * @exception IllegalArgumentException SWT_AWT
which
+provides support for embedding AWT widgets within SWT composites.
+This package requires JDK 1.5 or higher.
+It works on Windows and GTK.
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/AuthenticationEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/AuthenticationEvent.java
new file mode 100644
index 000000000..44d0046b7
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/AuthenticationEvent.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import org.eclipse.swt.widgets.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * An AuthenticationEvent
is sent by a {@link Browser}
+ * to {@link AuthenticationListener}'s when the Browser
+ * navigates to a page that requires authentication. This event allows
+ * a client to either supply authentication credentials, cancel the
+ * authentication, or do nothing (which causes an authentication prompter
+ * to be shown to the user).
+ *
+ * @since 3.5
+ */
+public class AuthenticationEvent extends TypedEvent {
+ /** The location that triggered the authentication challenge */
+ public String location;
+
+ /** The user name to authenticate with */
+ public String user;
+
+ /** The password to authenticate with */
+ public String password;
+
+ /**
+ * A flag indicating whether the authentication should proceed.
+ * Setting this field to false
will cancel the operation.
+ */
+ public boolean doit = true;
+
+ static final long serialVersionUID = -8322331206780057921L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public AuthenticationEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " name=" + user
+ + " password=" + password
+ + " location=" + location
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/AuthenticationListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/AuthenticationListener.java
new file mode 100644
index 000000000..1e855def6
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/AuthenticationListener.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * an {@link AuthenticationEvent} notification when the {@link Browser}
+ * encounters a page that requires authentication.
+ *
+ * @see Browser#addAuthenticationListener(AuthenticationListener)
+ * @see Browser#removeAuthenticationListener(AuthenticationListener)
+ *
+ * @since 3.5
+ */
+@FunctionalInterface
+public interface AuthenticationListener extends SWTEventListener {
+
+/**
+ * This method is called when a page is navigated to that requires
+ * authentication.
+ *
+ * Setting both the event's user
and password
+ * fields causes these values to be used as credentials for authentication.
+ * Leaving one or both of these fields as null
indicates
+ * that credentials are not known, so an authentication prompter should
+ * be shown to the user. Otherwise, setting the event's doit
+ * field to false
cancels the authentication challenge, and
+ * the page will not be loaded.
+ *
The following fields in the AuthenticationEvent
apply:
Browser
that is attempting to show the
+ * page that requires authentication
+ * false
to cancel the
+ * authentication challenge
+ * AuthenticationEvent
that can be used to
+ * either supply authentication credentials, defer credential input to
+ * an authentication prompter, or cancel an authentication challenge.
+ */
+public void authenticate(AuthenticationEvent event);
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/Browser.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/Browser.java
new file mode 100644
index 000000000..d344a7081
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/Browser.java
@@ -0,0 +1,1223 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Instances of this class implement the browser user interface
+ * metaphor. It allows the user to visualize and navigate through
+ * HTML documents.
+ *
+ * Note that although this class is a subclass of Composite
,
+ * it does not make sense to set a layout on it.
+ *
+ * Note: MOZILLA is deprecated and is no longer supported. + *
+ *+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Browser snippets + * @see SWT Examples: ControlExample, BrowserExample + * @see Sample code and further information + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + */ + +public class Browser extends Composite { + WebBrowser webBrowser; + int userStyle; + boolean isClosing; + + static int DefaultType = SWT.DEFAULT; + + static final String NO_INPUT_METHOD = "org.eclipse.swt.internal.gtk.noInputMethod"; //$NON-NLS-1$ + static final String PACKAGE_PREFIX = "org.eclipse.swt.browser."; //$NON-NLS-1$ + static final String PROPERTY_DEFAULTTYPE = "org.eclipse.swt.browser.DefaultType"; //$NON-NLS-1$ + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
null
if no such cookie exists
+ *
+ * @exception IllegalArgumentException value
parameter must be a cookie header string that
+ * complies with RFC 2109.
+ * The value is passed through to the native browser unchanged.
+ *
+ * Example value strings:
+ * foo=bar
(basic session cookie)
+ * foo=bar; path=/; domain=.eclipse.org
(session cookie)
+ * foo=bar; expires=Thu, 01-Jan-2030 00:00:01 GMT
(persistent cookie)
+ * foo=; expires=Thu, 01-Jan-1970 00:00:01 GMT
(deletes cookie foo
)
+ *
+ * @param value the cookie value
+ * @param url the URL to associate the cookie with
+ * @return true
if the cookie was successfully set and false
otherwise
+ *
+ * @exception IllegalArgumentException
+ * This notification occurs when a page requiring authentication is + * encountered. + *
+ * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException
+ * This notification occurs when a javascript command such as
+ * window.close
gets executed by a Browser
.
+ *
+ * This notification typically occurs when the application navigates + * to a new location with {@link #setUrl(String)} or when the user + * activates a hyperlink. + *
+ * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException
+ * This notification occurs when a javascript command such as
+ * window.open
gets executed by a Browser
.
+ *
+ * The status text is typically displayed in the status bar of + * a browser application. + *
+ * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentExceptiontrue
if the operation was successful and false
otherwise
+ *
+ * @exception SWTException
+ * Executes a script containing javascript commands in the context of the current document.
+ * If document-defined functions or properties are accessed by the script then this method
+ * should not be invoked until the document has finished loading (ProgressListener.completed()
+ * gives notification of this).
+ *
+ * @param script the script with javascript commands
+ *
+ * @return true
if the operation was successful and false
otherwise
+ *
+ * @exception IllegalArgumentException
onbeforeunload
listener
+ * in the Browser's current page.
+ *
+ * @return true
if the receiver was disposed, and false
otherwise
+ *
+ * @exception SWTException
+ * Evaluates a script containing javascript commands in the context of
+ * the current document. If document-defined functions or properties
+ * are accessed by the script then this method should not be invoked
+ * until the document has finished loading (ProgressListener.completed()
+ * gives notification of this).
+ *
+ * If the script returns a value with a supported type then a java + * representation of the value is returned. The supported + * javascript -> java mappings are: + *
null
java.lang.Double
java.lang.String
java.lang.Boolean
java.lang.Object[]
SWTException
is thrown if the return value has an
+ * unsupported type, or if evaluating the script causes a javascript
+ * error to be thrown.
+ *
+ * @param script the script with javascript commands
+ *
+ * @return the return value, if any, of executing the script
+ *
+ * @exception IllegalArgumentException
+ * Evaluates a script containing javascript commands.
+ * When trusted
is true
script is executed in the context of Chrome
+ * with Chrome security privileges.
+ * When trusted
is false
script is executed in the context of the
+ * current document with normal privileges.
+ *
+ * If document-defined functions or properties are accessed by the script then
+ * this method should not be invoked until the document has finished loading
+ * (ProgressListener.completed()
gives notification of this).
+ *
+ * If the script returns a value with a supported type then a java + * representation of the value is returned. The supported + * javascript -> java mappings are: + *
null
java.lang.Double
java.lang.String
java.lang.Boolean
java.lang.Object[]
SWTException
is thrown if the return value has an
+ * unsupported type, or if evaluating the script causes a javascript
+ * error to be thrown.
+ *
+ * Note: Chrome security context is applicable only to Browsers with style SWT.Mozilla
.
+ *
true
or false
depending on the security context to be used
+ *
+ * @return the return value, if any, of executing the script
+ *
+ * @exception IllegalArgumentException true
if the operation was successful and false
otherwise
+ *
+ * @exception SWTException true
if javascript will be allowed to run in pages
+ * subsequently viewed in the receiver, and false
otherwise.
+ * Note that this may not reflect the javascript enablement on the currently-
+ * viewed page if setJavascriptEnabled()
has been invoked during
+ * its lifetime.
+ *
+ * @return the receiver's javascript enabled state
+ *
+ * @exception SWTException String
+ * if this is empty.Note, the exact return value is platform dependent. + * For example on Windows, the returned string is the proccessed webpage + * with javascript executed and missing html tags added. + * On Linux and OS X, this returns the original HTML before the browser has + * processed it.
+ * + * @exception SWTExceptionString
if there is no current URL
+ *
+ * @exception SWTException nsIWebBrowser
for the receiver, or null
+ * if it is not available. In order for an nsIWebBrowser
to be returned all
+ * of the following must be true: SWT.MOZILLA
nsIWebBrowser
or null
+ *
+ * @since 3.3
+ * @deprecated SWT.MOZILLA is deprecated and XULRunner as a browser renderer is no longer supported.
+ */
+@Deprecated
+public Object getWebBrowser () {
+ checkWidget();
+ return webBrowser.getWebBrowser ();
+}
+
+/**
+ * Returns true
if the receiver can navigate to the
+ * previous session history item, and false
otherwise.
+ *
+ * @return the receiver's back command enabled state
+ *
+ * @exception SWTException true
if the receiver can navigate to the
+ * next session history item, and false
otherwise.
+ *
+ * @return the receiver's forward command enabled state
+ *
+ * @exception SWTException setText(String html, boolean trusted)
instead.
+ *
+ * The html parameter is Unicode-encoded since it is a java String
.
+ * As a result, the HTML meta tag charset should not be set. The charset is implied
+ * by the String
itself.
+ *
+ * @param html the HTML content to be rendered
+ *
+ * @return true if the operation was successful and false otherwise.
+ *
+ * @exception IllegalArgumentException
+ * The html
parameter is Unicode-encoded since it is a java String
.
+ * As a result, the HTML meta tag charset should not be set. The charset is implied
+ * by the String
itself.
+ *
+ * The trusted
parameter affects the permissions that will be granted to the rendered
+ * page. Specifying true
for trusted gives the page permissions equivalent
+ * to a page on the local file system, while specifying false
for trusted
+ * gives the page permissions equivalent to a page from the internet. Page content should
+ * be specified as trusted if the invoker created it or trusts its source, since this would
+ * allow (for instance) style sheets on the local file system to be referenced. Page
+ * content should be specified as untrusted if its source is not trusted or is not known.
+ *
+ * @param html the HTML content to be rendered
+ * @param trusted false
if the rendered page should be granted restricted
+ * permissions and true
otherwise
+ *
+ * @return true
if the operation was successful and false
otherwise.
+ *
+ * @exception IllegalArgumentException
+ * If the URL causes an HTTP request to be initiated then the provided
+ * postData
and header
arguments, if any, are
+ * sent with the request. A value in the headers
argument
+ * must be a name-value pair with a colon separator in order to be sent
+ * (for example: "user-agent: custom
").
+ *
+ * @param url the URL to be loaded
+ * @param postData post data to be sent with the request, or null
+ * @param headers header lines to be sent with the request, or null
+ *
+ * @return true
if the operation was successful and false
otherwise.
+ *
+ * @exception IllegalArgumentException
BrowserFunction
and
+ * overriding its function(Object[])
method. This
+ * method will be invoked whenever javascript running in the
+ * Browser makes a call with the function's name.
+ *
+ *
+ * Application code must explicitly invoke the
+ * BrowserFunction.dispose()
method to release the
+ * resources managed by each instance when those instances are no
+ * longer required. Since there is usually a correlation between
+ * the registering of BrowserFunction(s) in a Browser and the
+ * loading of a page in the Browser that is aware of these
+ * functions, the LocationListener.changed()
listener
+ * is often a good place to do this.
+ *
+ * Note that disposing a Browser automatically disposes all + * BrowserFunctions associated with it. + *
+ * + * @see #dispose() + * @see #function(Object[]) + * @see org.eclipse.swt.browser.LocationListener#changed(LocationEvent) + * + * @since 3.5 + */ +public class BrowserFunction { + Browser browser; + String name; + String functionString; + int index; + boolean isEvaluate, top; + String token; + String[] frameNames; + +/** + * Constructs a new instance of this class, which will be invokable + * by javascript running in the specified Browser. The function will + * be accessible in the top-level window and all child frames. To + * create a function with a reduced scope of accessibility use the + *BrowserFunction
constructor that accepts frame names
+ * instead.
+ *
+ * You must dispose the BrowserFunction when it is no longer required.
+ * A common place to do this is in a LocationListener.changed()
+ * listener.
+ *
top
and frameNames
+ * arguments. To create a function that is globally accessible to
+ * the top-level window and all child frames use the
+ * BrowserFunction
constructor that does not accept frame
+ * names instead.
+ *
+ * You must dispose the BrowserFunction when it is no longer required.
+ * A common place to do this is in a LocationListener.changed()
+ * listener.
+ *
true
if the function should be accessible to the
+ * top-level window and false
otherwise
+ * @param frameNames the names of the child frames that the function should
+ * be accessible in
+ *
+ * @exception IllegalArgumentException + * Note that disposing a Browser automatically disposes all + * BrowserFunctions associated with it. + *
+ */ +public void dispose () { + dispose (true); +} + +void dispose (boolean remove) { + if (index < 0) return; + if (remove) browser.webBrowser.destroyFunction (this); + browser = null; + name = functionString = null; + index = -1; +} + +/** + * Subclasses should override this method. This method is invoked when + * the receiver's function is called from javascript. If all of the + * arguments that are passed to the javascript function call are of + * supported types then this method is invoked with the argument values + * converted as follows: + * + * javascript null or undefined ->null
+ * javascript number -> java.lang.Double
+ * javascript string -> java.lang.String
+ * javascript boolean -> java.lang.Boolean
+ * javascript array whose elements are all of supported types -> java.lang.Object[]
+ *
+ * If any of the javascript arguments are of unsupported types then the
+ * function invocation will fail and this method will not be called.
+ *
+ * This method must return a value with one of these supported java types to
+ * the javascript caller. Note that null
values are converted
+ * to javascript's null
value (not undefined
), and
+ * instances of any java.lang.Number
subclass will be converted
+ * to a javascript number.
+ *
+ * @param arguments the javascript arguments converted to java equivalents
+ * @return the value to return to the javascript caller
+ *
+ * @exception SWTException true
if this BrowserFunction has been disposed
+ * and false
otherwise.
+ * + * This method gets the dispose state for the BrowserFunction. + * When a BrowserFunction has been disposed it is an error to + * invoke any of its methods. + *
+ * Note that disposing a Browser automatically disposes all + * BrowserFunctions associated with it. + *
+ * @returntrue
if this BrowserFunction has been disposed
+ * and false
otherwise
+ */
+public boolean isDisposed () {
+ return index < 0;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/CloseWindowListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/CloseWindowListener.java
new file mode 100644
index 000000000..a35b08c0c
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/CloseWindowListener.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link WindowEvent} notification when a {@link Browser} is
+ * about to be closed and when its host window should be closed
+ * by the application.
+ *
+ * @see Browser#addCloseWindowListener(CloseWindowListener)
+ * @see Browser#removeCloseWindowListener(CloseWindowListener)
+ * @see OpenWindowListener
+ * @see VisibilityWindowListener
+ *
+ * @since 3.0
+ */
+@FunctionalInterface
+public interface CloseWindowListener extends SWTEventListener {
+
+/**
+ * This method is called when the window hosting a {@link Browser} should be closed.
+ * Application would typically close the {@link org.eclipse.swt.widgets.Shell} that
+ * hosts the Browser
. The Browser
is disposed after this
+ * notification.
+ *
+ * The following fields in the WindowEvent
apply:
Browser
that is going to be disposed
+ * WindowEvent
that specifies the Browser
+ * that is going to be disposed
+ *
+ * @see org.eclipse.swt.widgets.Shell#close()
+ *
+ * @since 3.0
+ */
+public void close(WindowEvent event);
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/IE.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/IE.java
new file mode 100644
index 000000000..49272066a
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/IE.java
@@ -0,0 +1,2042 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.ole.win32.*;
+import org.eclipse.swt.widgets.*;
+
+class IE extends WebBrowser {
+
+ OleFrame frame;
+ WebSite site;
+ OleAutomation auto;
+ OleListener domListener;
+ OleAutomation[] documents = new OleAutomation[0];
+
+ boolean back, forward, delaySetText, ignoreDispose, ignoreTraverse, performingInitialNavigate;
+ boolean installFunctionsOnDocumentComplete, untrustedText, isRefresh, isAboutBlank;
+ Point location;
+ Point size;
+ boolean addressBar = true, menuBar = true, statusBar = true, toolBar = true;
+ long globalDispatch;
+ String html, lastNavigateURL, uncRedirect;
+ Object[] pendingText, pendingUrl;
+ int style, lastKeyCode, lastCharCode;
+ int lastMouseMoveX, lastMouseMoveY;
+
+ static boolean Initialized;
+ static int IEVersion, PDFCount;
+ static String ProgId = "Shell.Explorer"; //$NON-NLS-1$
+
+ static final int BeforeNavigate2 = 0xfa;
+ static final int CommandStateChange = 0x69;
+ static final int DocumentComplete = 0x103;
+ static final int DownloadComplete = 0x68;
+ static final int NavigateComplete2 = 0xfc;
+ static final int NewWindow2 = 0xfb;
+ static final int OnMenuBar = 0x100;
+ static final int OnStatusBar = 0x101;
+ static final int OnToolBar = 0xff;
+ static final int OnVisible = 0xfe;
+ static final int ProgressChange = 0x6c;
+ static final int RegisterAsBrowser = 0x228;
+ static final int StatusTextChange = 0x66;
+ static final int TitleChange = 0x71;
+ static final int WindowClosing = 0x107;
+ static final int WindowSetHeight = 0x10b;
+ static final int WindowSetLeft = 0x108;
+ static final int WindowSetResizable = 0x106;
+ static final int WindowSetTop = 0x109;
+ static final int WindowSetWidth = 0x10a;
+ static final int NavigateError = 0x10f;
+
+ static final short CSC_NAVIGATEFORWARD = 1;
+ static final short CSC_NAVIGATEBACK = 2;
+ static final int INET_E_DEFAULT_ACTION = 0x800C0011;
+ static final int INET_E_RESOURCE_NOT_FOUND = 0x800C0005;
+ static final int READYSTATE_COMPLETE = 4;
+ static final int URLPOLICY_ALLOW = 0x00;
+ static final int URLPOLICY_DISALLOW = 0x03;
+ static final int URLPOLICY_JAVA_PROHIBIT = 0x0;
+ static final int URLPOLICY_JAVA_LOW = 0x00030000;
+ static final int URLZONE_LOCAL_MACHINE = 0;
+ static final int URLZONE_INTRANET = 1;
+ static final int URLACTION_ACTIVEX_MIN = 0x00001200;
+ static final int URLACTION_ACTIVEX_MAX = 0x000013ff;
+ static final int URLACTION_ACTIVEX_RUN = 0x00001200;
+ static final int URLACTION_FEATURE_ZONE_ELEVATION = 0x00002101;
+ static final int URLACTION_JAVA_MIN = 0x00001C00;
+ static final int URLACTION_JAVA_MAX = 0x00001Cff;
+ static final int URLACTION_SCRIPT_RUN = 0x00001400;
+
+ static final int DISPID_AMBIENT_DLCONTROL = -5512;
+ static final int DLCTL_DLIMAGES = 0x00000010;
+ static final int DLCTL_VIDEOS = 0x00000020;
+ static final int DLCTL_BGSOUNDS = 0x00000040;
+ static final int DLCTL_NO_SCRIPTS = 0x00000080;
+ static final int DLCTL_NO_JAVA = 0x00000100;
+ static final int DLCTL_NO_RUNACTIVEXCTLS = 0x00000200;
+ static final int DLCTL_NO_DLACTIVEXCTLS = 0x00000400;
+ static final int DLCTL_DOWNLOADONLY = 0x00000800;
+ static final int DLCTL_NO_FRAMEDOWNLOAD = 0x00001000;
+ static final int DLCTL_RESYNCHRONIZE = 0x00002000;
+ static final int DLCTL_PRAGMA_NO_CACHE = 0x00004000;
+ static final int DLCTL_FORCEOFFLINE = 0x10000000;
+ static final int DLCTL_NO_CLIENTPULL = 0x20000000;
+ static final int DLCTL_SILENT = 0x40000000;
+ static final int DOCHOSTUIFLAG_THEME = 0x00040000;
+ static final int DOCHOSTUIFLAG_NO3DBORDER = 0x0000004;
+ static final int DOCHOSTUIFLAG_NO3DOUTERBORDER = 0x00200000;
+ static final int DOCHOSTUIFLAG_ENABLE_REDIRECT_NOTIFICATION = 0x04000000;
+ static final int DOCHOSTUIFLAG_DPI_AWARE = 0x40000000;
+
+ static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
+ static final String CLSID_SHELLEXPLORER1 = "{EAB22AC3-30C1-11CF-A7EB-0000C05BAE0B}"; //$NON-NLS-1$
+ static final int DEFAULT_IE_VERSION = 9999;
+ static final String EXTENSION_PDF = ".pdf"; //$NON-NLS-1$
+ static final String HTML_DOCUMENT = "HTML Document"; //$NON-NLS-1$
+ static final int MAX_PDF = 20;
+ static final char SEPARATOR_OS = File.separatorChar;
+ static final String PROPERTY_IEVERSION = "org.eclipse.swt.browser.IEVersion"; //$NON-NLS-1$
+ static final String VALUE_DEFAULT = "default"; //$NON-NLS-1$
+
+ static final String EVENT_DOUBLECLICK = "dblclick"; //$NON-NLS-1$
+ static final String EVENT_DRAGEND = "dragend"; //$NON-NLS-1$
+ static final String EVENT_DRAGSTART = "dragstart"; //$NON-NLS-1$
+ static final String EVENT_KEYDOWN = "keydown"; //$NON-NLS-1$
+ static final String EVENT_KEYPRESS = "keypress"; //$NON-NLS-1$
+ static final String EVENT_KEYUP = "keyup"; //$NON-NLS-1$
+ static final String EVENT_MOUSEMOVE = "mousemove"; //$NON-NLS-1$
+ static final String EVENT_MOUSEWHEEL = "mousewheel"; //$NON-NLS-1$
+ static final String EVENT_MOUSEUP = "mouseup"; //$NON-NLS-1$
+ static final String EVENT_MOUSEDOWN = "mousedown"; //$NON-NLS-1$
+ static final String EVENT_MOUSEOUT = "mouseout"; //$NON-NLS-1$
+ static final String EVENT_MOUSEOVER = "mouseover"; //$NON-NLS-1$
+ static final String PROTOCOL_FILE = "file://"; //$NON-NLS-1$
+ static final String PROPERTY_ALTKEY = "altKey"; //$NON-NLS-1$
+ static final String PROPERTY_BUTTON = "button"; //$NON-NLS-1$
+ static final String PROPERTY_CTRLKEY = "ctrlKey"; //$NON-NLS-1$
+ static final String PROPERTY_DOCUMENT = "Document"; //$NON-NLS-1$
+ static final String PROPERTY_FROMELEMENT = "fromElement"; //$NON-NLS-1$
+ static final String PROPERTY_KEYCODE = "keyCode"; //$NON-NLS-1$
+ static final String PROPERTY_REPEAT = "repeat"; //$NON-NLS-1$
+ static final String PROPERTY_RETURNVALUE = "returnValue"; //$NON-NLS-1$
+ static final String PROPERTY_SCREENX = "screenX"; //$NON-NLS-1$
+ static final String PROPERTY_SCREENY = "screenY"; //$NON-NLS-1$
+ static final String PROPERTY_SHIFTKEY = "shiftKey"; //$NON-NLS-1$
+ static final String PROPERTY_TOELEMENT = "toElement"; //$NON-NLS-1$
+ static final String PROPERTY_TYPE = "type"; //$NON-NLS-1$
+ static final String PROPERTY_WHEELDELTA = "wheelDelta"; //$NON-NLS-1$
+
+ static {
+ NativeClearSessions = () -> {
+ OS.InternetSetOption (0, OS.INTERNET_OPTION_END_BROWSER_SESSION, 0, 0);
+ };
+
+ NativeGetCookie = () -> {
+ TCHAR url = new TCHAR (0, CookieUrl, true);
+ TCHAR cookieData = new TCHAR (0, 8192);
+ int[] size = new int[] {cookieData.length ()};
+ if (!OS.InternetGetCookie (url, null, cookieData, size)) {
+ /* original cookieData size was not large enough */
+ size[0] /= TCHAR.sizeof;
+ cookieData = new TCHAR (0, size[0]);
+ if (!OS.InternetGetCookie (url, null, cookieData, size)) return;
+ }
+ String allCookies = cookieData.toString (0, size[0]);
+ StringTokenizer tokenizer = new StringTokenizer (allCookies, ";"); //$NON-NLS-1$
+ while (tokenizer.hasMoreTokens ()) {
+ String cookie = tokenizer.nextToken ();
+ int index = cookie.indexOf ('=');
+ if (index != -1) {
+ String name = cookie.substring (0, index).trim ();
+ if (name.equals (CookieName)) {
+ CookieValue = cookie.substring (index + 1).trim ();
+ return;
+ }
+ }
+ }
+ };
+
+ NativeSetCookie = () -> {
+ TCHAR url = new TCHAR (0, CookieUrl, true);
+ TCHAR value = new TCHAR (0, CookieValue, true);
+ CookieResult = OS.InternetSetCookie (url, null, value);
+ };
+
+ /*
+ * The installed version of IE can be determined by looking at registry entry
+ * HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\svcVersion, or
+ * HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Version (for
+ * IE releases prior to IE10). Check this value in order to determine
+ * version-specific features that can be enabled.
+ */
+ TCHAR key = new TCHAR (0, "Software\\Microsoft\\Internet Explorer", true); //$NON-NLS-1$
+ long [] phkResult = new long [1];
+ if (OS.RegOpenKeyEx (OS.HKEY_LOCAL_MACHINE, key, 0, OS.KEY_READ, phkResult) == 0) {
+ int [] lpcbData = new int [1];
+ TCHAR buffer = new TCHAR (0, "svcVersion", true); //$NON-NLS-1$
+ int result = OS.RegQueryValueEx (phkResult [0], buffer, 0, null, (TCHAR) null, lpcbData);
+ if (result != 0) {
+ buffer = new TCHAR (0, "Version", true); //$NON-NLS-1$
+ result = OS.RegQueryValueEx (phkResult [0], buffer, 0, null, (TCHAR) null, lpcbData);
+ }
+ if (result == 0) {
+ TCHAR lpData = new TCHAR (0, lpcbData [0] / TCHAR.sizeof);
+ result = OS.RegQueryValueEx (phkResult [0], buffer, 0, null, lpData, lpcbData);
+ if (result == 0) {
+ String versionString = lpData.toString (0, lpData.strlen ());
+ int index = versionString.indexOf ("."); //$NON-NLS-1$
+ if (index != -1) {
+ String majorString = versionString.substring (0, index);
+ try {
+ IEVersion = Integer.valueOf (majorString).intValue ();
+ } catch (NumberFormatException e) {
+ /* just continue, version-specific features will not be enabled */
+ }
+ }
+ }
+ }
+ OS.RegCloseKey (phkResult [0]);
+ }
+
+ /*
+ * Registry entry HKEY_CLASSES_ROOT\Shell.Explorer\CLSID indicates which version of
+ * Shell.Explorer to use by default. We usually want to use this value because it
+ * typically points at the newest one that is available. However it is possible for
+ * this registry entry to be changed by another application to point at some other
+ * Shell.Explorer version.
+ *
+ * The Browser depends on the Shell.Explorer version being at least Shell.Explorer.2.
+ * If it is detected in the registry to be Shell.Explorer.1 then change the progId that
+ * will be embedded to explicitly specify Shell.Explorer.2.
+ */
+ key = new TCHAR (0, "Shell.Explorer\\CLSID", true); //$NON-NLS-1$
+ phkResult = new long [1];
+ if (OS.RegOpenKeyEx (OS.HKEY_CLASSES_ROOT, key, 0, OS.KEY_READ, phkResult) == 0) {
+ int [] lpcbData = new int [1];
+ int result = OS.RegQueryValueEx (phkResult [0], null, 0, null, (TCHAR) null, lpcbData);
+ if (result == 0) {
+ TCHAR lpData = new TCHAR (0, lpcbData [0] / TCHAR.sizeof);
+ result = OS.RegQueryValueEx (phkResult [0], null, 0, null, lpData, lpcbData);
+ if (result == 0) {
+ String clsid = lpData.toString (0, lpData.strlen ());
+ if (clsid.equals (CLSID_SHELLEXPLORER1)) {
+ /* Shell.Explorer.1 is the default, ensure that Shell.Explorer.2 is available */
+ key = new TCHAR (0, "Shell.Explorer.2", true); //$NON-NLS-1$
+ long [] phkResult2 = new long [1];
+ if (OS.RegOpenKeyEx (OS.HKEY_CLASSES_ROOT, key, 0, OS.KEY_READ, phkResult2) == 0) {
+ /* specify that Shell.Explorer.2 is to be used */
+ OS.RegCloseKey (phkResult2 [0]);
+ ProgId = "Shell.Explorer.2"; //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ OS.RegCloseKey (phkResult [0]);
+ }
+
+ if (NativePendingCookies != null) {
+ SetPendingCookies (NativePendingCookies);
+ }
+ NativePendingCookies = null;
+ }
+
+@Override
+public void create(Composite parent, int style) {
+ this.style = style;
+ frame = new OleFrame(browser, SWT.NONE);
+
+ try {
+ site = new WebSite(frame, SWT.NONE, ProgId);
+ } catch (SWTException e) {
+ browser.dispose();
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+
+ if (!Initialized) {
+ Initialized = true;
+ int version = 0;
+ String versionProperty = System.getProperty(PROPERTY_IEVERSION);
+ if (versionProperty != null) {
+ if (versionProperty.equalsIgnoreCase(VALUE_DEFAULT)) {
+ version = -1;
+ } else {
+ try {
+ version = Integer.valueOf(versionProperty).intValue();
+ } catch (NumberFormatException e) {
+ /*
+ * An invalid value was specified for the IEVersion java property. Ignore it
+ * and continue with the usual steps for determining the version to specify.
+ */
+ }
+ }
+ }
+ if (version == 0) {
+ if (IEVersion != 0) {
+ /*
+ * By default in Embedded IE the docuemntMode is Quirks(5)
+ * mode unless !DOCTYPE directives is defined in the HTML.
+ * As per MSDN IE8 and onwards, there is a way we could hint
+ * embedded IE to use current documentMode via appropriate
+ * version value in the registry. Refer bug 342145.
+ *
+ * Complete list of IE emulation modes is listed on MSDN:
+ * http://msdn.microsoft
+ * .com/en-us/library/ie/ee330730%28v=vs
+ * .85%29.aspx#browser_emulation
+ */
+ if (IEVersion >= 10) {
+ version = IEVersion * 1000 + 1;
+ }
+ else if (IEVersion >= 8) {
+ version = IEVersion * 1111;
+ }
+ else {
+ version = IEVersion * 1000;
+ }
+ } else {
+ version = DEFAULT_IE_VERSION;
+ }
+ }
+
+ if (version != -1) {
+ long[] key = new long[1];
+ final TCHAR subkey = new TCHAR(0, "Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", true); //$NON-NLS-1$
+ if (OS.RegCreateKeyEx(OS.HKEY_CURRENT_USER, subkey, 0, null, OS.REG_OPTION_VOLATILE, OS.KEY_WRITE | OS.KEY_QUERY_VALUE, 0, key, null) == 0) {
+ TCHAR lpszFile = new TCHAR(0, OS.MAX_PATH);
+ OS.GetModuleFileName(0, lpszFile, lpszFile.length());
+ String path = lpszFile.toString(0, lpszFile.strlen());
+ int index = path.lastIndexOf(SEPARATOR_OS);
+ String executable = index != -1 ? path.substring(index + 1) : path;
+ final TCHAR lpValueName = new TCHAR(0, executable, true);
+ /*
+ * Program name & IE version entry is added to the Windows
+ * registry and same gets deleted during the dispose cycle.
+ * There is a possibility if the SWT application crashes or
+ * is exited forcefully, which leaves the registry entry
+ * as-is and hence if entry exists, updating it next time
+ * the SWT application creates embedded IE, refer bug 440300
+ */
+ int result = OS.RegQueryValueEx(key[0], lpValueName, 0, null, (int[])null, null);
+ if (result == 0 || result == OS.ERROR_FILE_NOT_FOUND) {
+ if (OS.RegSetValueEx(key[0], lpValueName, 0, OS.REG_DWORD, new int[] {version}, 4) == 0) {
+ parent.getDisplay().addListener(SWT.Dispose, event -> {
+ long[] key1 = new long[1];
+ if (OS.RegOpenKeyEx(OS.HKEY_CURRENT_USER, subkey, 0, OS.KEY_WRITE, key1) == 0) {
+ OS.RegDeleteValue(key1[0], lpValueName);
+ }
+ });
+ }
+ }
+ OS.RegCloseKey(key[0]);
+ }
+ }
+ }
+
+ site.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);
+ auto = new OleAutomation(site);
+
+ domListener = e -> handleDOMEvent(e);
+
+ Listener listener = e -> {
+ switch (e.type) {
+ case SWT.Dispose: {
+ /* make this handler run after other dispose listeners */
+ if (ignoreDispose) {
+ ignoreDispose = false;
+ break;
+ }
+ ignoreDispose = true;
+ browser.notifyListeners (e.type, e);
+ e.type = SWT.NONE;
+
+ /* invoke onbeforeunload handlers */
+ if (!browser.isClosing) {
+ LocationListener[] oldLocationListeners = locationListeners;
+ locationListeners = new LocationListener[0];
+ site.ignoreAllMessages = true;
+ execute ("window.location.href='about:blank'"); //$NON-NLS-1$
+ site.ignoreAllMessages = false;
+ locationListeners = oldLocationListeners;
+ }
+
+ /*
+ * It is possible for the Browser's OLE frame to have been disposed
+ * by a Dispose listener that was invoked by notifyListeners above,
+ * so check for this before unhooking its DOM listeners.
+ */
+ if (!frame.isDisposed ()) unhookDOMListeners(documents);
+
+ for (int i = 0; i < documents.length; i++) {
+ documents[i].dispose();
+ }
+ documents = null;
+
+ Iterator+ * Classes that wish to deal with {@link LocationEvent}'s can + * extend this class and override only the methods which they are + * interested in. + *
+ *+ * An alternative to this class are the static helper methods in + * {@link LocationListener}, + * which accept a lambda expression or a method reference that implements the event consumer. + *
+ * + * @see Sample code and further information + * + * @since 3.0 + */ +public abstract class LocationAdapter implements LocationListener { + +@Override +public void changing(LocationEvent event) { +} + +@Override +public void changed(LocationEvent event) { +} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/LocationEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/LocationEvent.java new file mode 100644 index 000000000..068f1398f --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/LocationEvent.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2003, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.browser; + +import org.eclipse.swt.events.*; +import org.eclipse.swt.widgets.*; + +/** + * ALocationEvent
is sent by a {@link Browser} to
+ * {@link LocationListener}'s when the Browser
+ * navigates to a different URL. This notification typically
+ * occurs when the application navigates to a new location with
+ * {@link Browser#setUrl(String)} or when the user activates a
+ * hyperlink.
+ *
+ * @see Sample code and further information
+ *
+ * @since 3.0
+ */
+public class LocationEvent extends TypedEvent {
+ /**
+ * The URL of this event, escaped and encoded for consumption by
+ * {@link java.net.URI#URI(String)}.
+ */
+ public String location;
+
+ /**
+ * A flag indicating whether the location opens in the top frame
+ * or not.
+ */
+ public boolean top;
+
+ /**
+ * A flag indicating whether the location loading should be allowed.
+ * Setting this field to false
will cancel the operation.
+ */
+ public boolean doit;
+
+ static final long serialVersionUID = 3906644198244299574L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public LocationEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " location=" + location
+ + " top=" + top
+ + " doit=" + doit
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/LocationListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/LocationListener.java
new file mode 100644
index 000000000..5a37109e0
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/LocationListener.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import java.util.function.*;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link LocationEvent} notification when a {@link Browser}
+ * navigates to a different URL.
+ *
+ * @see Browser#addLocationListener(LocationListener)
+ * @see Browser#removeLocationListener(LocationListener)
+ * @see LocationAdapter
+ *
+ * @since 3.0
+ */
+public interface LocationListener extends SWTEventListener {
+
+/**
+ * This method is called when the current location is about to be changed.
+ *
+ * The following fields in the LocationEvent
apply:
Browser
whose location is changing
+ * false
to prevent the location
+ * from being loaded
+ * LocationEvent
that specifies the location
+ * to be loaded by a Browser
+ *
+ * @since 3.0
+ */
+public void changing(LocationEvent event);
+
+/**
+ * This method is called when the current location is changed.
+ *
+ * The following fields in the LocationEvent
apply:
true
if the location opens in the top frame or
+ * false
otherwise
+ * Browser
whose location has changed
+ * LocationEvent
that specifies the new
+ * location of a Browser
+ *
+ * @since 3.0
+ */
+public void changed(LocationEvent event);
+
+/**
+ * Static helper method to create a LocationListener
for the
+ * {@link #changing(LocationEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return LocationListener
+ * @since 3.107
+ */
+public static LocationListener changingAdapter(ConsumerLocationListener
for the
+ * {@link #changed(LocationEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return LocationListener
+ * @since 3.107
+ */
+public static LocationListener changedAdapter(Consumer
+ * A particular Browser
can be passed to the event.browser
+ * field to host the content of a new window.
+ *
+ * A standalone system browser is used to host the new window
+ * if the event.required field value is false
and if the event.browser
+ * field is left null
. The event.required field
+ * is true
on platforms that don't support a standalone system browser for
+ * new window requests.
+ *
+ * The navigation is cancelled if the event.required field is set to
+ * true
and the event.browser field is left null
.
The following fields in the WindowEvent
apply:
Browser
to handle the new window or false otherwise.
+ * Browser
that will host the
+ * content of the new window.
+ * Browser
that is requesting to open a
+ * new window
+ * WindowEvent
that needs to be passed a new
+ * Browser
to handle the new window request
+ *
+ * @since 3.0
+ */
+public void open(WindowEvent event);
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/ProgressAdapter.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/ProgressAdapter.java
new file mode 100644
index 000000000..9a31a08ae
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/ProgressAdapter.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the {@link ProgressListener} interface.
+ * + * Classes that wish to deal with {@link ProgressEvent}'s can + * extend this class and override only the methods which they are + * interested in. + *
+ *+ * An alternative to this class are the static helper methods in + * {@link ProgressListener}, + * which accept a lambda expression or a method reference that implements the event consumer. + *
+ * + * @see Sample code and further information + * + * @since 3.0 + */ +public abstract class ProgressAdapter implements ProgressListener { + +@Override +public void changed(ProgressEvent event) { +} + +@Override +public void completed(ProgressEvent event) { +} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/ProgressEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/ProgressEvent.java new file mode 100644 index 000000000..a07f9e058 --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/ProgressEvent.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2003, 2009 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.browser; + +import org.eclipse.swt.widgets.*; +import org.eclipse.swt.events.*; + +/** + * AProgressEvent
is sent by a {@link Browser} to
+ * {@link ProgressListener}'s when a progress is made during the
+ * loading of the current URL or when the loading of the current
+ * URL has been completed.
+ *
+ * @see Sample code and further information
+ *
+ * @since 3.0
+ */
+public class ProgressEvent extends TypedEvent {
+ /** current value */
+ public int current;
+ /** total value */
+ public int total;
+
+ static final long serialVersionUID = 3977018427045393972L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public ProgressEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " current=" + current
+ + " total=" + total
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/ProgressListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/ProgressListener.java
new file mode 100644
index 000000000..c24333f05
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/ProgressListener.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import java.util.function.*;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link ProgressEvent} notification when a {@link Browser}
+ * makes a progress in loading the current URL or when the
+ * current URL has been loaded.
+ *
+ * @see Browser#addProgressListener(ProgressListener)
+ * @see Browser#removeProgressListener(ProgressListener)
+ * @see Browser#getUrl()
+ *
+ * @since 3.0
+ */
+public interface ProgressListener extends SWTEventListener {
+
+/**
+ * This method is called when a progress is made during the loading of the
+ * current location.
+ *
+ *
+ * The following fields in the ProgressEvent
apply:
Browser
whose current URL is being loaded
+ * ProgressEvent
related to the loading of the
+ * current location of a Browser
+ *
+ * @since 3.0
+ */
+public void changed(ProgressEvent event);
+
+/**
+ * This method is called when the current location has been completely loaded.
+ *
+ *
+ * The following fields in the ProgressEvent
apply:
Browser
whose current URL has been loaded
+ * ProgressEvent
related to the Browser
+ * that has loaded its current URL.
+ *
+ * @since 3.0
+ */
+public void completed(ProgressEvent event);
+
+/**
+ * Static helper method to create a ProgressListener
for the
+ * {@link #changed(ProgressEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return LocationListener
+ * @since 3.107
+ */
+public static ProgressListener changedAdapter(ConsumerProgressListener
for the
+ * {@link #completed(ProgressEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return LocationListener
+ * @since 3.107
+ */
+public static ProgressListener completedAdapter(ConsumerStatusTextEvent
is sent by a {@link Browser} to
+ * {@link StatusTextListener}'s when the status text is changed.
+ * The status text is typically displayed in the status bar of
+ * a browser application.
+ *
+ * @see Sample code and further information
+ *
+ * @since 3.0
+ */
+public class StatusTextEvent extends TypedEvent {
+ /** status text */
+ public String text;
+
+ static final long serialVersionUID = 3258407348371600439L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public StatusTextEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " text=" + text
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/StatusTextListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/StatusTextListener.java
new file mode 100644
index 000000000..93786c48a
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/StatusTextListener.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link StatusTextEvent} notification when the status text for
+ * a {@link Browser} is changed.
+ *
+ * @see Browser#addStatusTextListener(StatusTextListener)
+ * @see Browser#removeStatusTextListener(StatusTextListener)
+ *
+ * @since 3.0
+ */
+@FunctionalInterface
+public interface StatusTextListener extends SWTEventListener {
+
+/**
+ * This method is called when the status text is changed. The
+ * status text is typically displayed in the status bar of a browser
+ * application.
+ *
+ * The following fields in the StatusTextEvent
apply:
Browser
whose status text is changed
+ * StatusTextEvent
that contains the updated
+ * status description of a Browser
+ *
+ * @since 3.0
+ */
+public void changed(StatusTextEvent event);
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/TitleEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/TitleEvent.java
new file mode 100644
index 000000000..13ff512c4
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/TitleEvent.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import org.eclipse.swt.widgets.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * A TitleEvent
is sent by a {@link Browser} to
+ * {@link TitleListener}'s when the title of the current document
+ * is available or when it is modified.
+ *
+ * @see Sample code and further information
+ *
+ * @since 3.0
+ */
+public class TitleEvent extends TypedEvent {
+ /** the title of the current document */
+ public String title;
+
+ static final long serialVersionUID = 4121132532906340919L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public TitleEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " title=" + title
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/TitleListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/TitleListener.java
new file mode 100644
index 000000000..3fa84cf2b
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/TitleListener.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link TitleEvent} notification when the title of the document
+ * displayed in a {@link Browser} is known or has been changed.
+ *
+ * @see Browser#addTitleListener(TitleListener)
+ * @see Browser#removeTitleListener(TitleListener)
+ *
+ * @since 3.0
+ */
+@FunctionalInterface
+public interface TitleListener extends SWTEventListener {
+
+/**
+ * This method is called when the title of the current document
+ * is available or has changed.
+ *
+ * The following fields in the TitleEvent
apply:
Browser
whose current document's
+ * title is known or modified
+ * TitleEvent
that contains the title
+ * of the document currently displayed in a Browser
+ *
+ * @since 3.0
+ */
+public void changed(TitleEvent event);
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/VisibilityWindowAdapter.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/VisibilityWindowAdapter.java
new file mode 100644
index 000000000..57e2d8cb9
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/VisibilityWindowAdapter.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the {@link VisibilityWindowListener} interface.
+ * + * Classes that wish to deal with {@link WindowEvent}'s can + * extend this class and override only the methods which they are + * interested in. + *
+ *+ * An alternative to this class are the static helper methods in + * {@link VisibilityWindowListener}, + * which accept a lambda expression or a method reference that implements the event consumer. + *
+ * + * @see Sample code and further information + * + * @since 3.0 + */ +public abstract class VisibilityWindowAdapter implements VisibilityWindowListener { + +@Override +public void hide(WindowEvent event) { +} + +@Override +public void show(WindowEvent event) { +} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/VisibilityWindowListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/VisibilityWindowListener.java new file mode 100644 index 000000000..cbb88c78b --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/VisibilityWindowListener.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2003, 2017 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.browser; + +import java.util.function.*; + +import org.eclipse.swt.internal.*; + +/** + * This listener interface may be implemented in order to receive + * a {@link WindowEvent} notification when a window hosting a + * {@link Browser} needs to be displayed or hidden. + * + * @see Browser#addVisibilityWindowListener(VisibilityWindowListener) + * @see Browser#removeVisibilityWindowListener(VisibilityWindowListener) + * @see OpenWindowListener + * @see CloseWindowListener + * + * @since 3.0 + */ +public interface VisibilityWindowListener extends SWTEventListener { + +/** + * This method is called when the window hosting aBrowser
+ * is requested to be hidden. Application would typically hide the
+ * {@link org.eclipse.swt.widgets.Shell} that hosts the Browser
.
+ *
+ * The following fields in the WindowEvent
apply:
Browser
that needs to be hidden
+ * WindowEvent
that specifies the
+ * Browser
that needs to be hidden
+ *
+ * @see org.eclipse.swt.widgets.Shell#setVisible(boolean)
+ *
+ * @since 3.0
+ */
+public void hide(WindowEvent event);
+
+/**
+ * This method is called when the window hosting a Browser
+ * is requested to be displayed. Application would typically set the
+ * location and the size of the {@link org.eclipse.swt.widgets.Shell}
+ * that hosts the Browser
, if a particular location and size
+ * are specified. The application would then open that Shell
.
+ *
+ * The following fields in the WindowEvent
apply:
Browser
to display
+ * Shell
+ * hosting the browser. It is null
if no location is set.
+ * Browser
.
+ * The client area of the Shell
hosting the
+ * Browser
should be large enough to accommodate that size.
+ * It is null
if no size is set.
+ * true
if the Shell
+ * hosting the Browser
should display an address bar or
+ * false
otherwise
+ * true
if the Shell
+ * hosting the Browser
should display a menu bar or
+ * false
otherwise
+ * true
if the Shell
+ * hosting the Browser
should display a status bar or
+ * false
otherwise
+ * true
if the Shell
+ * hosting the Browser
should display a tool bar or
+ * false
otherwise
+ * WindowEvent
that specifies the
+ * Browser
that needs to be displayed
+ *
+ * @see org.eclipse.swt.widgets.Control#setLocation(org.eclipse.swt.graphics.Point)
+ * @see org.eclipse.swt.widgets.Control#setSize(org.eclipse.swt.graphics.Point)
+ * @see org.eclipse.swt.widgets.Shell#open()
+ *
+ * @since 3.0
+ */
+public void show(WindowEvent event);
+
+/**
+ * Static helper method to create a VisibilityWindowListener
for thehide
+ * {@link #hide(WindowEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return LocationListener
+ * @since 3.107
+ */
+public static VisibilityWindowListener hideAdapter(ConsumerVisibilityWindowListener
for the
+ * {@link #show(WindowEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return LocationListener
+ * @since 3.107
+ */
+public static VisibilityWindowListener showAdapter(ConsumerWindowEvent
is sent by a {@link Browser} when
+ * a new window needs to be created or when an existing window needs to be
+ * closed. This notification occurs when a javascript command such as
+ * window.open
or window.close
gets executed by
+ * a Browser
.
+ *
+ *
+ * The following example shows how WindowEvent
's are typically
+ * handled.
+ * public static void main(String[] args) {
+ * Display display = new Display();
+ * Shell shell = new Shell(display);
+ * shell.setText("Main Window");
+ * shell.setLayout(new FillLayout());
+ * Browser browser = new Browser(shell, SWT.NONE);
+ * initialize(display, browser);
+ * shell.open();
+ * browser.setUrl("http://www.eclipse.org");
+ * while (!shell.isDisposed()) {
+ * if (!display.readAndDispatch())
+ * display.sleep();
+ * }
+ * display.dispose();
+ * }
+ *
+ * static void initialize(final Display display, Browser browser) {
+ * browser.addOpenWindowListener(new OpenWindowListener() {
+ * public void open(WindowEvent event) {
+ * // Certain platforms can provide a default full browser.
+ * // simply return in that case if the application prefers
+ * // the default full browser to the embedded one set below.
+ * if (!event.required) return;
+ *
+ * // Embed the new window
+ * Shell shell = new Shell(display);
+ * shell.setText("New Window");
+ * shell.setLayout(new FillLayout());
+ * Browser browser = new Browser(shell, SWT.NONE);
+ * initialize(display, browser);
+ * event.browser = browser;
+ * }
+ * });
+ * browser.addVisibilityWindowListener(new VisibilityWindowListener() {
+ * public void hide(WindowEvent event) {
+ * Browser browser = (Browser)event.widget;
+ * Shell shell = browser.getShell();
+ * shell.setVisible(false);
+ * }
+ * public void show(WindowEvent event) {
+ * Browser browser = (Browser)event.widget;
+ * Shell shell = browser.getShell();
+ * if (event.location != null) shell.setLocation(event.location);
+ * if (event.size != null) {
+ * Point size = event.size;
+ * shell.setSize(shell.computeSize(size.x, size.y));
+ * }
+ * if (event.addressBar || event.menuBar || event.statusBar || event.toolBar) {
+ * // Create widgets for the address bar, menu bar, status bar and/or tool bar
+ * // leave enough space in the Shell to accommodate a Browser of the size
+ * // given by event.size
+ * }
+ * shell.open();
+ * }
+ * });
+ * browser.addCloseWindowListener(new CloseWindowListener() {
+ * public void close(WindowEvent event) {
+ * Browser browser = (Browser)event.widget;
+ * Shell shell = browser.getShell();
+ * shell.close();
+ * }
+ * });
+ * }
+ *
+ *
+ * The following notifications are emitted when the user selects a hyperlink that targets a new window
+ * or as the result of a javascript that executes window.open.
+ *
+ * Main Browser
+ *Second Browser
+ *Browser
to handle the new window.
+ *
+ * @since 3.1
+ */
+ public boolean required;
+
+
+ /**
+ * Browser
provided by the application.
+ */
+ public Browser browser;
+
+ /**
+ * Requested location for the Shell
hosting the Browser
.
+ * It is null
if no location has been requested.
+ */
+ public Point location;
+
+ /**
+ * Requested Browser
size. The client area of the Shell
+ * hosting the Browser
should be large enough to accommodate that size.
+ * It is null
if no size has been requested.
+ */
+ public Point size;
+
+ /**
+ * Specifies whether the Shell
hosting the Browser
should
+ * display an address bar.
+ *
+ * @since 3.1
+ */
+ public boolean addressBar;
+
+ /**
+ * Specifies whether the Shell
hosting the Browser
should
+ * display a menu bar. Note that this is always true
on OS X.
+ *
+ * @since 3.1
+ */
+ public boolean menuBar;
+
+ /**
+ * Specifies whether the Shell
hosting the Browser
should
+ * display a status bar.
+ *
+ * @since 3.1
+ */
+ public boolean statusBar;
+
+ /**
+ * Specifies whether the Shell
hosting the Browser
should
+ * display a tool bar.
+ *
+ * @since 3.1
+ */
+ public boolean toolBar;
+
+ static final long serialVersionUID = 3617851997387174969L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public WindowEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " required=" + required
+ + " browser=" + browser
+ + " location=" + location
+ + " size=" + size
+ + " addressBar=" + addressBar
+ + " menuBar=" + menuBar
+ + " statusBar=" + statusBar
+ + " toolBar=" + toolBar
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/package.html b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/package.html
new file mode 100644
index 000000000..f64b6c484
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/package.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * The elements in the segments field specify the start offset of + * a segment relative to the start of the line. They must follow + * the following rules:
+ *+ * The segments field may be left null if the entire line should + * be reordered as is. + *
+ * A BidiSegmentListener may be used when adjacent segments of + * right-to-left text should not be reordered relative to each other. + * For example, within a Java editor, you may wish multiple + * right-to-left string literals to be reordered differently than the + * bidi algorithm specifies. + * + * Example: + *+ * stored line = "R1R2R3" + "R4R5R6" + * R1 to R6 are right-to-left characters. The quotation marks + * are part of the line text. The line is 13 characters long. + * + * segments = null: + * entire line will be reordered and thus the two R2L segments + * swapped (as per the bidi algorithm). + * visual line (rendered on screen) = "R6R5R4" + "R3R2R1" + * + * segments = [0, 5, 8] + * "R1R2R3" will be reordered, followed by [blank]+[blank] and + * "R4R5R6". + * visual line = "R3R2R1" + "R6R5R4" + *+ * + *
+ * The segments and segmentsChars fields can be used together to obtain different + * types of bidi reordering and text display. The application can use these two fields + * to insert Unicode Control Characters in specific offsets in the line, the character + * at segmentsChars[i] is inserted at the offset specified by segments[i]. When both fields + * are set, the rules for the segments field are less restrictive: + *
+ *+ * The following event fields are used:
StyledText
.
+ * + * The hashCode() method in this class uses the values of the public + * fields to compute the hash value. When storing instances of the + * class in hashed collections, do not modify these fields after the + * object has been inserted. + *
+ *
+ * Application code does not need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no dispose()
method is provided.
+ *
ST.BULLET_DOT
ST.BULLET_NUMBER
ST.BULLET_LETTER_LOWER
ST.BULLET_LETTER_UPPER
ST.BULLET_TEXT
ST.BULLET_CUSTOM
ST.BULLET_DOT
.
+ * The style must have a glyph metrics set.
+ *
+ * @param style the style
+ *
+ * @exception IllegalArgumentException Runnable
while providing
+ * busy feedback using this busy indicator.
+ *
+ * @param display the display on which the busy feedback should be
+ * displayed. If the display is null, the Display for the current
+ * thread will be used. If there is no Display for the current thread,
+ * the runnable code will be executed and no busy feedback will be displayed.
+ * @param runnable the runnable for which busy feedback is to be shown.
+ * Must not be null.
+ *
+ * @exception IllegalArgumentException
+ * Note that although this class is a subclass of Composite
,
+ * it does not make sense to set a layout on it.
+ *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Sample code and further information + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + */ + +public class CBanner extends Composite { + + Control left; + Control right; + Control bottom; + + boolean simple = true; + + int[] curve = new int[0]; + int curveStart = 0; + Rectangle curveRect = new Rectangle(0, 0, 0, 0); + int curve_width = 5; + int curve_indent = -2; + + int rightWidth = SWT.DEFAULT; + int rightMinWidth = 0; + int rightMinHeight = 0; + Cursor resizeCursor; + boolean dragging = false; + int rightDragDisplacement = 0; + Listener listener; + + static final int OFFSCREEN = -200; + static final int BORDER_BOTTOM = 2; + static final int BORDER_TOP = 3; + static final int BORDER_STRIPE = 1; + static final int CURVE_TAIL = 200; + static final int BEZIER_RIGHT = 30; + static final int BEZIER_LEFT = 30; + static final int MIN_LEFT = 10; + static int BORDER1 = SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW; + + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
true
if the CBanner is rendered
+ * with a simple, traditional shape.
+ *
+ * @return true
if the CBanner is rendered with a simple shape
+ *
+ * @since 3.0
+ */
+public boolean getSimple() {
+ checkWidget();
+ return simple;
+}
+void onDispose(Event event) {
+ removeListener(SWT.Dispose, listener);
+ notifyListeners(SWT.Dispose, event);
+ event.type = SWT.None;
+
+ resizeCursor = null;
+ left = null;
+ right = null;
+ bottom = null;
+}
+void onMouseDown (int x, int y) {
+ if (curveRect.contains(x, y)) {
+ dragging = true;
+ rightDragDisplacement = curveStart - x + curve_width - curve_indent;
+ }
+}
+void onMouseExit() {
+ if (!dragging) setCursor(null);
+}
+void onMouseMove(int x, int y) {
+ if (dragging) {
+ Point size = getSize();
+ if (!(0 < x && x < size.x)) return;
+ rightWidth = Math.max(0, size.x - x - rightDragDisplacement);
+ if (rightMinWidth == SWT.DEFAULT) {
+ Point minSize = right.computeSize(rightMinWidth, rightMinHeight);
+ rightWidth = Math.max(minSize.x, rightWidth);
+ } else {
+ rightWidth = Math.max(rightMinWidth, rightWidth);
+ }
+ layout(false);
+ return;
+ }
+ if (curveRect.contains(x, y)) {
+ setCursor(resizeCursor);
+ } else {
+ setCursor(null);
+ }
+}
+void onMouseUp () {
+ dragging = false;
+}
+void onPaint(GC gc) {
+// Useful for debugging paint problems
+// {
+// Point size = getSize();
+// gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_GREEN));
+// gc.fillRectangle(-10, -10, size.x+20, size.y+20);
+// }
+ if (left == null && right == null) return;
+ Point size = getSize();
+ Color border1 = getDisplay().getSystemColor(BORDER1);
+ if (bottom != null) {
+ int y = bottom.getBounds().y - BORDER_STRIPE - 1;
+ gc.setForeground(border1);
+ gc.drawLine(0, y, size.x, y);
+ }
+ if (left == null || right == null) return;
+ int[] line1 = new int[curve.length+6];
+ int index = 0;
+ int x = curveStart;
+ line1[index++] = x + 1;
+ line1[index++] = size.y - BORDER_STRIPE;
+ for (int i = 0; i < curve.length/2; i++) {
+ line1[index++]=x+curve[2*i];
+ line1[index++]=curve[2*i+1];
+ }
+ line1[index++] = x + curve_width;
+ line1[index++] = 0;
+ line1[index++] = size.x;
+ line1[index++] = 0;
+
+ Color background = getBackground();
+
+ if (getDisplay().getDepth() >= 15) {
+ // Anti- aliasing
+ int[] line2 = new int[line1.length];
+ index = 0;
+ for (int i = 0; i < line1.length/2; i++) {
+ line2[index] = line1[index++] - 1;
+ line2[index] = line1[index++];
+ }
+ int[] line3 = new int[line1.length];
+ index = 0;
+ for (int i = 0; i < line1.length/2; i++) {
+ line3[index] = line1[index++] + 1;
+ line3[index] = line1[index++];
+ }
+ RGB from = border1.getRGB();
+ RGB to = background.getRGB();
+ int red = from.red + 3*(to.red - from.red)/4;
+ int green = from.green + 3*(to.green - from.green)/4;
+ int blue = from.blue + 3*(to.blue - from.blue)/4;
+ Color color = new Color(getDisplay(), red, green, blue);
+ gc.setForeground(color);
+ gc.drawPolyline(line2);
+ gc.drawPolyline(line3);
+ color.dispose();
+
+ // draw tail fading to background
+ int x1 = Math.max(0, curveStart - CURVE_TAIL);
+ gc.setForeground(background);
+ gc.setBackground(border1);
+ gc.fillGradientRectangle(x1, size.y - BORDER_STRIPE, curveStart-x1+1, 1, false);
+ } else {
+ // draw solid tail
+ int x1 = Math.max(0, curveStart - CURVE_TAIL);
+ gc.setForeground(border1);
+ gc.drawLine(x1, size.y - BORDER_STRIPE, curveStart+1, size.y - BORDER_STRIPE);
+ }
+
+ // draw border
+ gc.setForeground(border1);
+ gc.drawPolyline(line1);
+}
+
+void onResize() {
+ updateCurve(getSize().y);
+}
+/**
+* Set the control that appears on the bottom side of the banner.
+* The bottom control is optional. Setting the bottom control to null will remove it from
+* the banner - however, the creator of the control must dispose of the control.
+*
+* @param control the control to be displayed on the bottom or null
+*
+* @exception SWTException + * Note: No Layout can be set on this Control because it already + * manages the size and position of its children. + *
+ * + * @param layout the receiver's new layout or null + * + * @exception SWTExceptiontrue
if the CBanner should render itself in a simple, traditional style
+ *
+ * @exception SWTException + * CCombo was written to work around certain limitations in the native + * combo box. Specifically, on win32, the height of a CCombo can be set; + * attempts to set the height of a Combo are ignored. CCombo can be used + * anywhere that having the increased flexibility is more important than + * getting native L&F, but the decision should not be taken lightly. + * There is no strict requirement that CCombo look or behave the same as + * the native combo box. + *
+ *
+ * Note that although this class is a subclass of Composite
,
+ * it does not make sense to add children to it, or set a layout on it.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * Note: To add an item at the end of the list, use the
+ * result of calling getItemCount()
as the
+ * index or use add(String)
.
+ *
+ * Also note, if control characters like '\n', '\t' etc. are used + * in the string, then the behavior is platform dependent. + *
+ * + * @param string the new item + * @param index the index for the item + * + * @exception IllegalArgumentExceptionModifyListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException SelectionListener
+ * interface.
+ *
+ * widgetSelected
is called when the combo's list selection changes.
+ * widgetDefaultSelected
is typically called when ENTER is pressed the combo's text area.
+ *
VerifyListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ * Note: To clear the selected items in the receiver's list,
+ * use deselectAll()
.
+ *
+ * The current selection is copied to the clipboard. + *
+ * + * @exception SWTException
+ * Note: To clear the selection in the receiver's text field,
+ * use clearSelection()
.
+ *
String
s which are the items
+ * in the receiver's list.
+ * + * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + *
+ * + * @return the items in the receiver's list + * + * @exception SWTExceptiontrue
if the receiver's list is visible,
+ * and false
otherwise.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, this method + * may still indicate that it is considered visible even though + * it may not actually be showing. + *
+ * + * @return the receiver's list's visibility state + * + * @exception SWTExceptionPoint
whose x coordinate is the start
+ * of the selection in the receiver's text field, and whose y
+ * coordinate is the end of the selection. The returned values
+ * are zero-relative. An "empty" selection as indicated by
+ * the the x and y coordinates having the same value.
+ *
+ * @return a point representing the selection start and end
+ *
+ * @exception SWTException setTextLimit()
, it will be the constant
+ * Combo.LIMIT
.
+ *
+ * @return the text limit
+ *
+ * @exception SWTException + * The selected text is deleted from the widget + * and new text inserted from the clipboard. + *
+ * + * @exception SWTExceptionremove
'ing the old item at the index, and then
+ * add
'ing the new item at that index.
+ *
+ * @param index the index for the item
+ * @param string the new text for the item
+ *
+ * @exception IllegalArgumentException + * Note: No Layout can be set on this Control because it already + * manages the size and position of its children. + *
+ * + * @param layout the receiver's new layout or null + * + * @exception SWTExceptiontrue
,
+ * and marks it invisible otherwise.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, marking + * it visible may not actually cause it to be displayed. + *
+ * + * @param visible the new visibility state + * + * @exception SWTException
+ * Note: The text field in a Combo
is typically
+ * only capable of displaying a single line of text. Thus,
+ * setting the text to a string containing line breaks or
+ * other special characters will probably cause it to
+ * display incorrectly.
+ *
+ * Also note, if control characters like '\n', '\t' etc. are used + * in the string, then the behavior is platform dependent. + *
+ * + * @param string the new text + * + * @exception IllegalArgumentException+ * If there is not enough space a CLabel uses the following strategy to fit the + * information into the available space: + *
+ * ignores the indent in left align mode + * ignores the image and the gap + * shortens the text by replacing the center portion of the label with an ellipsis + * shortens the text by removing the center portion of the label + *+ *
+ * This class may be subclassed for the purpose of overriding the default string
+ * shortening algorithm that is implemented in method shortenText()
.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
null
.
+ *
+ * @return the image of the label or null
+ */
+public Image getImage() {
+ /*
+ * This call is intentionally commented out, to allow this getter method to be
+ * called from a thread which is different from one that created the widget.
+ */
+ //checkWidget();
+ return image;
+}
+/**
+ * Return the CLabel's left margin.
+ *
+ * @return the left margin of the label
+ *
+ * @since 3.6
+ */
+public int getLeftMargin() {
+ /*
+ * This call is intentionally commented out, to allow this getter method to be
+ * called from a thread which is different from one that created the widget.
+ */
+ //checkWidget();
+ return leftMargin;
+}
+/**
+ * Return the CLabel's right margin.
+ *
+ * @return the right margin of the label
+ *
+ * @since 3.6
+ */
+public int getRightMargin() {
+ /*
+ * This call is intentionally commented out, to allow this getter method to be
+ * called from a thread which is different from one that created the widget.
+ */
+ //checkWidget();
+ return rightMargin;
+}
+/**
+ * Compute the minimum size.
+ */
+private Point getTotalSize(Image image, String text) {
+ Point size = new Point(0, 0);
+
+ if (image != null) {
+ Rectangle r = image.getBounds();
+ size.x += r.width;
+ size.y += r.height;
+ }
+
+ GC gc = new GC(this);
+ if (text != null && text.length() > 0) {
+ Point e = gc.textExtent(text, DRAW_FLAGS);
+ size.x += e.x;
+ size.y = Math.max(size.y, e.y);
+ if (image != null) size.x += GAP;
+ } else {
+ size.y = Math.max(size.y, gc.getFontMetrics().getHeight());
+ }
+ gc.dispose();
+
+ return size;
+}
+@Override
+public int getStyle () {
+ int style = super.getStyle();
+ switch (align) {
+ case SWT.RIGHT: style |= SWT.RIGHT; break;
+ case SWT.CENTER: style |= SWT.CENTER; break;
+ case SWT.LEFT: style |= SWT.LEFT; break;
+ }
+ return style;
+}
+
+/**
+ * Return the Label's text.
+ *
+ * @return the text of the label or null
+ */
+public String getText() {
+ /*
+ * This call is intentionally commented out, to allow this getter method to be
+ * called from a thread which is different from one that created the widget.
+ */
+ //checkWidget();
+ return text;
+}
+@Override
+public String getToolTipText () {
+ checkWidget();
+ return appToolTipText;
+}
+/**
+ * Return the CLabel's top margin.
+ *
+ * @return the top margin of the label
+ *
+ * @since 3.6
+ */
+public int getTopMargin() {
+ /*
+ * This call is intentionally commented out, to allow this getter method to be
+ * called from a thread which is different from one that created the widget.
+ */
+ //checkWidget();
+ return topMargin;
+}
+private void initAccessible() {
+ Accessible accessible = getAccessible();
+ accessible.addAccessibleListener(new AccessibleAdapter() {
+ @Override
+ public void getName(AccessibleEvent e) {
+ e.result = getText();
+ }
+
+ @Override
+ public void getHelp(AccessibleEvent e) {
+ e.result = getToolTipText();
+ }
+
+ @Override
+ public void getKeyboardShortcut(AccessibleEvent e) {
+ char mnemonic = _findMnemonic(CLabel.this.text);
+ if (mnemonic != '\0') {
+ e.result = "Alt+"+mnemonic; //$NON-NLS-1$
+ }
+ }
+ });
+
+ accessible.addAccessibleControlListener(new AccessibleControlAdapter() {
+ @Override
+ public void getChildAtPoint(AccessibleControlEvent e) {
+ e.childID = ACC.CHILDID_SELF;
+ }
+
+ @Override
+ public void getLocation(AccessibleControlEvent e) {
+ Rectangle rect = getDisplay().map(getParent(), null, getBounds());
+ e.x = rect.x;
+ e.y = rect.y;
+ e.width = rect.width;
+ e.height = rect.height;
+ }
+
+ @Override
+ public void getChildCount(AccessibleControlEvent e) {
+ e.detail = 0;
+ }
+
+ @Override
+ public void getRole(AccessibleControlEvent e) {
+ e.detail = ACC.ROLE_LABEL;
+ }
+
+ @Override
+ public void getState(AccessibleControlEvent e) {
+ e.detail = ACC.STATE_READONLY;
+ }
+ });
+}
+void onDispose(Event event) {
+ /* make this handler run after other dispose listeners */
+ if (ignoreDispose) {
+ ignoreDispose = false;
+ return;
+ }
+ ignoreDispose = true;
+ notifyListeners (event.type, event);
+ event.type = SWT.NONE;
+
+ gradientColors = null;
+ gradientPercents = null;
+ backgroundImage = null;
+ text = null;
+ image = null;
+ appToolTipText = null;
+}
+void onMnemonic(TraverseEvent event) {
+ char mnemonic = _findMnemonic(text);
+ if (mnemonic == '\0') return;
+ if (Character.toLowerCase(event.character) != mnemonic) return;
+ Composite control = this.getParent();
+ while (control != null) {
+ Control [] children = control.getChildren();
+ int index = 0;
+ while (index < children.length) {
+ if (children [index] == this) break;
+ index++;
+ }
+ index++;
+ if (index < children.length) {
+ if (children [index].setFocus ()) {
+ event.doit = true;
+ event.detail = SWT.TRAVERSE_NONE;
+ }
+ }
+ control = control.getParent();
+ }
+}
+
+void onPaint(PaintEvent event) {
+ Rectangle rect = getClientArea();
+ if (rect.width == 0 || rect.height == 0) return;
+
+ boolean shortenText = false;
+ String t = text;
+ Image img = image;
+ int availableWidth = Math.max(0, rect.width - (leftMargin + rightMargin));
+ Point extent = getTotalSize(img, t);
+ if (extent.x > availableWidth) {
+ img = null;
+ extent = getTotalSize(img, t);
+ if (extent.x > availableWidth) {
+ shortenText = true;
+ }
+ }
+
+ GC gc = event.gc;
+ String[] lines = text == null ? null : splitString(text);
+
+ // shorten the text
+ if (shortenText) {
+ extent.x = 0;
+ for(int i = 0; i < lines.length; i++) {
+ Point e = gc.textExtent(lines[i], DRAW_FLAGS);
+ if (e.x > availableWidth) {
+ lines[i] = shortenText(gc, lines[i], availableWidth);
+ extent.x = Math.max(extent.x, getTotalSize(null, lines[i]).x);
+ } else {
+ extent.x = Math.max(extent.x, e.x);
+ }
+ }
+ if (appToolTipText == null) {
+ super.setToolTipText(text);
+ }
+ } else {
+ super.setToolTipText(appToolTipText);
+ }
+
+ // determine horizontal position
+ int x = rect.x + leftMargin;
+ if (align == SWT.CENTER) {
+ x = (rect.width - extent.x)/2;
+ }
+ if (align == SWT.RIGHT) {
+ x = rect.width - rightMargin - extent.x;
+ }
+
+ // draw a background image behind the text
+ try {
+ if (backgroundImage != null) {
+ // draw a background image behind the text
+ Rectangle imageRect = backgroundImage.getBounds();
+ // tile image to fill space
+ gc.setBackground(getBackground());
+ gc.fillRectangle(rect);
+ int xPos = 0;
+ while (xPos < rect.width) {
+ int yPos = 0;
+ while (yPos < rect.height) {
+ gc.drawImage(backgroundImage, xPos, yPos);
+ yPos += imageRect.height;
+ }
+ xPos += imageRect.width;
+ }
+ } else if (gradientColors != null) {
+ // draw a gradient behind the text
+ final Color oldBackground = gc.getBackground();
+ if (gradientColors.length == 1) {
+ if (gradientColors[0] != null) gc.setBackground(gradientColors[0]);
+ gc.fillRectangle(0, 0, rect.width, rect.height);
+ } else {
+ final Color oldForeground = gc.getForeground();
+ Color lastColor = gradientColors[0];
+ if (lastColor == null) lastColor = oldBackground;
+ int pos = 0;
+ for (int i = 0; i < gradientPercents.length; ++i) {
+ gc.setForeground(lastColor);
+ lastColor = gradientColors[i + 1];
+ if (lastColor == null) lastColor = oldBackground;
+ gc.setBackground(lastColor);
+ if (gradientVertical) {
+ final int gradientHeight = (gradientPercents[i] * rect.height / 100) - pos;
+ gc.fillGradientRectangle(0, pos, rect.width, gradientHeight, true);
+ pos += gradientHeight;
+ } else {
+ final int gradientWidth = (gradientPercents[i] * rect.width / 100) - pos;
+ gc.fillGradientRectangle(pos, 0, gradientWidth, rect.height, false);
+ pos += gradientWidth;
+ }
+ }
+ if (gradientVertical && pos < rect.height) {
+ gc.setBackground(getBackground());
+ gc.fillRectangle(0, pos, rect.width, rect.height - pos);
+ }
+ if (!gradientVertical && pos < rect.width) {
+ gc.setBackground(getBackground());
+ gc.fillRectangle(pos, 0, rect.width - pos, rect.height);
+ }
+ gc.setForeground(oldForeground);
+ }
+ gc.setBackground(oldBackground);
+ } else {
+ if ((background != null || (getStyle() & SWT.DOUBLE_BUFFERED) == 0) && background.getAlpha() > 0) {
+ gc.setBackground(getBackground());
+ gc.fillRectangle(rect);
+ }
+ }
+ } catch (SWTException e) {
+ if ((getStyle() & SWT.DOUBLE_BUFFERED) == 0) {
+ gc.setBackground(getBackground());
+ gc.fillRectangle(rect);
+ }
+ }
+
+ // draw border
+ int style = getStyle();
+ if ((style & SWT.SHADOW_IN) != 0 || (style & SWT.SHADOW_OUT) != 0) {
+ paintBorder(gc, rect);
+ }
+
+ /*
+ * Compute text height and image height. If image height is more than
+ * the text height, draw image starting from top margin. Else draw text
+ * starting from top margin.
+ */
+ Rectangle imageRect = null;
+ int lineHeight = 0, textHeight = 0, imageHeight = 0;
+
+ if (img != null) {
+ imageRect = img.getBounds();
+ imageHeight = imageRect.height;
+ }
+ if (lines != null) {
+ lineHeight = gc.getFontMetrics().getHeight();
+ textHeight = lines.length * lineHeight;
+ }
+
+ int imageY = 0, midPoint = 0, lineY = 0;
+ if (imageHeight > textHeight ) {
+ if (topMargin == DEFAULT_MARGIN && bottomMargin == DEFAULT_MARGIN) imageY = rect.y + (rect.height - imageHeight) / 2;
+ else imageY = topMargin;
+ midPoint = imageY + imageHeight/2;
+ lineY = midPoint - textHeight / 2;
+ }
+ else {
+ if (topMargin == DEFAULT_MARGIN && bottomMargin == DEFAULT_MARGIN) lineY = rect.y + (rect.height - textHeight) / 2;
+ else lineY = topMargin;
+ midPoint = lineY + textHeight/2;
+ imageY = midPoint - imageHeight / 2;
+ }
+
+ // draw the image
+ if (img != null) {
+ gc.drawImage(img, 0, 0, imageRect.width, imageHeight,
+ x, imageY, imageRect.width, imageHeight);
+ x += imageRect.width + GAP;
+ extent.x -= imageRect.width + GAP;
+ }
+
+ // draw the text
+ if (lines != null) {
+ gc.setForeground(getForeground());
+ for (int i = 0; i < lines.length; i++) {
+ int lineX = x;
+ if (lines.length > 1) {
+ if (align == SWT.CENTER) {
+ int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
+ lineX = x + Math.max(0, (extent.x - lineWidth) / 2);
+ }
+ if (align == SWT.RIGHT) {
+ int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
+ lineX = Math.max(x, rect.x + rect.width - rightMargin - lineWidth);
+ }
+ }
+ gc.drawText(lines[i], lineX, lineY, DRAW_FLAGS);
+ lineY += lineHeight;
+ }
+ }
+}
+/**
+ * Paint the Label's border.
+ */
+private void paintBorder(GC gc, Rectangle r) {
+ Display disp= getDisplay();
+
+ Color c1 = null;
+ Color c2 = null;
+
+ int style = getStyle();
+ if ((style & SWT.SHADOW_IN) != 0) {
+ c1 = disp.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+ c2 = disp.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
+ }
+ if ((style & SWT.SHADOW_OUT) != 0) {
+ c1 = disp.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);
+ c2 = disp.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+ }
+
+ if (c1 != null && c2 != null) {
+ gc.setLineWidth(1);
+ drawBevelRect(gc, r.x, r.y, r.width-1, r.height-1, c1, c2);
+ }
+}
+/**
+ * Set the horizontal alignment of the CLabel.
+ * Use the values LEFT, CENTER and RIGHT to align image and text within the available space.
+ *
+ * @param align the alignment style of LEFT, RIGHT or CENTER
+ *
+ * @exception SWTException For example, to draw a gradient that varies from dark blue to blue and then to + * white and stays white for the right half of the label, use the following call + * to setBackground:
+ *+ * clabel.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), + * display.getSystemColor(SWT.COLOR_BLUE), + * display.getSystemColor(SWT.COLOR_WHITE), + * display.getSystemColor(SWT.COLOR_WHITE)}, + * new int[] {25, 50, 100}); + *+ * + * @param colors an array of Color that specifies the colors to appear in the gradient + * in order of appearance from left to right; The value
null
+ * clears the background gradient; the value null
can be used
+ * inside the array of Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ * of the widget at which the color should change; the size of the percents
+ * array must be one less than the size of the colors array.
+ *
+ * @exception SWTException For example, to draw a gradient that varies from dark blue to white in the vertical, + * direction use the following call + * to setBackground:
+ *+ * clabel.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), + * display.getSystemColor(SWT.COLOR_WHITE)}, + * new int[] {100}, true); + *+ * + * @param colors an array of Color that specifies the colors to appear in the gradient + * in order of appearance from left/top to right/bottom; The value
null
+ * clears the background gradient; the value null
can be used
+ * inside the array of Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width/height
+ * of the widget at which the color should change; the size of the percents
+ * array must be one less than the size of the colors array.
+ * @param vertical indicate the direction of the gradient. True is vertical and false is horizontal.
+ *
+ * @exception SWTException null
clears it.
+ *
+ * @param image the image to be displayed in the label or null
+ *
+ * @exception SWTException null
clears it.
+ * + * Mnemonics are indicated by an '&' that causes the next + * character to be the mnemonic. When the user presses a + * key sequence that matches the mnemonic, focus is assigned + * to the control that follows the label. On most platforms, + * the mnemonic appears underlined but may be emphasised in a + * platform specific manner. The mnemonic indicator character + * '&' can be escaped by doubling it in the string, causing + * a single '&' to be displayed. + *
+ * Note: If control characters like '\n', '\t' etc. are used + * in the string, then the behavior is platform dependent. + *
+ * + * @param text the text to be displayed in the label or null + * + * @exception SWTExceptiont
so that its length doesn't exceed
+ * the given width. The default implementation replaces characters in the
+ * center of the original string with an ellipsis ("...").
+ * Override if you need a different strategy.
+ *
+ * @param gc the gc to use for text measurement
+ * @param t the text to shorten
+ * @param width the width to shorten the text to, in points
+ * @return the shortened text
+ */
+protected String shortenText(GC gc, String t, int width) {
+ if (t == null) return null;
+ int w = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x;
+ if (width<=w) return t;
+ int l = t.length();
+ int max = l/2;
+ int min = 0;
+ int mid = (max+min)/2 - 1;
+ if (mid <= 0) return t;
+ TextLayout layout = new TextLayout (getDisplay());
+ layout.setText(t);
+ mid = validateOffset(layout, mid);
+ while (min < mid && mid < max) {
+ String s1 = t.substring(0, mid);
+ String s2 = t.substring(validateOffset(layout, l-mid), l);
+ int l1 = gc.textExtent(s1, DRAW_FLAGS).x;
+ int l2 = gc.textExtent(s2, DRAW_FLAGS).x;
+ if (l1+w+l2 > width) {
+ max = mid;
+ mid = validateOffset(layout, (max+min)/2);
+ } else if (l1+w+l2 < width) {
+ min = mid;
+ mid = validateOffset(layout, (max+min)/2);
+ } else {
+ min = max;
+ }
+ }
+ String result = mid == 0 ? t : t.substring(0, mid) + ELLIPSIS + t.substring(validateOffset(layout, l-mid), l);
+ layout.dispose();
+ return result;
+}
+int validateOffset(TextLayout layout, int offset) {
+ int nextOffset = layout.getNextOffset(offset, SWT.MOVEMENT_CLUSTER);
+ if (nextOffset != offset) return layout.getPreviousOffset(nextOffset, SWT.MOVEMENT_CLUSTER);
+ return offset;
+}
+private String[] splitString(String text) {
+ String[] lines = new String[1];
+ int start = 0, pos;
+ do {
+ pos = text.indexOf('\n', start);
+ if (pos == -1) {
+ lines[lines.length - 1] = text.substring(start);
+ } else {
+ boolean crlf = (pos > 0) && (text.charAt(pos - 1) == '\r');
+ lines[lines.length - 1] = text.substring(start, pos - (crlf ? 1 : 0));
+ start = pos + 1;
+ String[] newLines = new String[lines.length+1];
+ System.arraycopy(lines, 0, newLines, 0, lines.length);
+ lines = newLines;
+ }
+ } while (pos != -1);
+ return lines;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CLayoutData.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CLayoutData.java
new file mode 100644
index 000000000..659291fc5
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CLayoutData.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+class CLayoutData {
+
+ int defaultWidth = -1, defaultHeight = -1;
+ int currentWhint, currentHhint, currentWidth = -1, currentHeight = -1;
+
+Point computeSize (Control control, int wHint, int hHint, boolean flushCache) {
+ if (flushCache) flushCache();
+ if (wHint == SWT.DEFAULT && hHint == SWT.DEFAULT) {
+ if (defaultWidth == -1 || defaultHeight == -1) {
+ Point size = control.computeSize (wHint, hHint, flushCache);
+ defaultWidth = size.x;
+ defaultHeight = size.y;
+ }
+ return new Point(defaultWidth, defaultHeight);
+ }
+ if (currentWidth == -1 || currentHeight == -1 || wHint != currentWhint || hHint != currentHhint) {
+ Point size = control.computeSize (wHint, hHint, flushCache);
+ currentWhint = wHint;
+ currentHhint = hHint;
+ currentWidth = size.x;
+ currentHeight = size.y;
+ }
+ return new Point(currentWidth, currentHeight);
+}
+void flushCache () {
+ defaultWidth = defaultHeight = -1;
+ currentWidth = currentHeight = -1;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolder.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolder.java
new file mode 100644
index 000000000..63d9676f5
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolder.java
@@ -0,0 +1,4137 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.DPIUtil.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ *
+ * Instances of this class implement the notebook user interface
+ * metaphor. It allows the user to select a notebook page from
+ * set of pages.
+ *
+ * The item children that may be added to instances of this class
+ * must be of type CTabItem
.
+ * Control
children are created and then set into a
+ * tab item using CTabItem#setControl
.
+ *
+ * Note that although this class is a subclass of Composite
,
+ * it does not make sense to set a layout on it.
+ *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see CTabFolder, CTabItem snippets + * @see SWT Example: CustomControlExample + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ + +public class CTabFolder extends Composite { + + /** + * marginWidth specifies the number of points of horizontal margin + * that will be placed along the left and right edges of the form. + * + * The default value is 0. + */ + public int marginWidth = 0; + /** + * marginHeight specifies the number of points of vertical margin + * that will be placed along the top and bottom edges of the form. + * + * The default value is 0. + */ + public int marginHeight = 0; + + /** + * A multiple of the tab height that specifies the minimum width to which a tab + * will be compressed before scrolling arrows are used to navigate the tabs. + * + * NOTE This field is badly named and can not be fixed for backwards compatibility. + * It should not be capitalized. + * + * @deprecated This field is no longer used. See setMinimumCharacters(int) + */ + @Deprecated + public int MIN_TAB_WIDTH = 4; + + /** + * Color of innermost line of drop shadow border. + * + * NOTE This field is badly named and can not be fixed for backwards compatibility. + * It should be capitalized. + * + * @deprecated drop shadow border is no longer drawn in 3.0 + */ + @Deprecated + public static RGB borderInsideRGB = new RGB (132, 130, 132); + /** + * Color of middle line of drop shadow border. + * + * NOTE This field is badly named and can not be fixed for backwards compatibility. + * It should be capitalized. + * + * @deprecated drop shadow border is no longer drawn in 3.0 + */ + @Deprecated + public static RGB borderMiddleRGB = new RGB (143, 141, 138); + /** + * Color of outermost line of drop shadow border. + * + * NOTE This field is badly named and can not be fixed for backwards compatibility. + * It should be capitalized. + * + * @deprecated drop shadow border is no longer drawn in 3.0 + */ + @Deprecated + public static RGB borderOutsideRGB = new RGB (171, 168, 165); + + /* sizing, positioning */ + boolean onBottom = false; + boolean single = false; + boolean simple = true; + int fixedTabHeight = SWT.DEFAULT; + int tabHeight; + int minChars = 20; + boolean borderVisible = false; + + /* item management */ + CTabFolderRenderer renderer; + CTabItem items[] = new CTabItem[0]; + /** index of the left most visible tab. */ + int firstIndex = -1; + int selectedIndex = -1; + + /** + * Indices of the elements in the {@link #items} array, used to manage tab + * visibility and candidates to be hidden/shown next. + *+ * If there is not enough place for all tabs, tabs starting from the end of + * the {@link #priority} array will be hidden first (independently from the + * {@link #mru} flag!) => the right most elements have the highest priority + * to be hidden. + *
+ * If there is more place to show previously hidden tabs, tabs starting from + * the beginning of the {@link #priority} array will be made visible first + * (independently from the {@link #mru} flag!) => the left most elements + * have the highest priority to be shown. + *
+ * The update strategy of the {@link #priority} array however depends on the + * {@link #mru} flag. + *
+ * If {@link #mru} flag is set, the first index is always the index of the + * currently selected tab, next one is the tab selected before current + * etc... + *
+ * Example: [4,2,5,1,3,0], just representing the last selection order. + *
+ * If {@link #mru} flag is not set, the first index is always the index of
+ * the left most visible tab ({@link #firstIndex} field), next indices are
+ * incremented by one up to priority.length-1
, and the rest
+ * filled with indices starting with firstIndex-1
and
+ * decremented by one until 0 index is reached.
+ *
+ * The tabs between first index and the index of the currently selected tab + * are always visible. + *
+ * Example: 6 tabs, 2 and 3 are indices of currently shown tabs: + * [2,3,4,5,1,0]. The array consists of two blocks: sorted ascending from + * first visible (2) to last available (5), and the rest sorted descending + * (1,0). 4 and 5 are the hidden tabs on the right side, 0 and 1 are the + * hidden tabs on the left side from the visible tabs 2 and 3. + * + * @see #updateItems(int) + * @see #setItemLocation(GC) + */ + int[] priority = new int[0]; + boolean mru = false; + Listener listener; + boolean ignoreTraverse; + boolean useDefaultRenderer; + + /* External Listener management */ + CTabFolder2Listener[] folderListeners = new CTabFolder2Listener[0]; + // support for deprecated listener mechanism + CTabFolderListener[] tabListeners = new CTabFolderListener[0]; + + /* Selected item appearance */ + Image selectionBgImage; + Color[] selectionGradientColors; + int[] selectionGradientPercents; + boolean selectionGradientVertical; + Color selectionForeground; + Color selectionBackground; + + /* Unselected item appearance */ + Color[] gradientColors; + int[] gradientPercents; + boolean gradientVertical; + boolean showUnselectedImage = true; + + // close, min/max and chevron buttons + boolean showClose = false; + boolean showUnselectedClose = true; + + boolean showMin = false; + boolean minimized = false; + boolean showMax = false; + boolean maximized = false; + ToolBar minMaxTb; + ToolItem maxItem; + ToolItem minItem; + Image maxImage; + Image minImage; + boolean hoverTb; + Rectangle hoverRect = new Rectangle(0,0,0,0); + boolean hovering; + boolean hoverTimerRunning; + boolean highlight; + boolean highlightEnabled = true; + + boolean showChevron = false; + Menu showMenu; + ToolBar chevronTb; + ToolItem chevronItem; + int chevronCount; + boolean chevronVisible = true; + + Image chevronImage; + Control topRight; + int topRightAlignment = SWT.RIGHT; + boolean ignoreResize; + Control[] controls; + int[] controlAlignments; + Rectangle[] controlRects; + Image[] controlBkImages; + + int updateFlags; + final static int REDRAW = 1 << 1; + final static int REDRAW_TABS = 1 << 2; + final static int UPDATE_TAB_HEIGHT = 1 << 3; + Runnable updateRun; + + // when disposing CTabFolder, don't try to layout the items or + // change the selection as each child is destroyed. + boolean inDispose = false; + + // keep track of size changes in order to redraw only affected area + // on Resize + Point oldSize; + Font oldFont; + + // internal constants + static final int DEFAULT_WIDTH = 64; + static final int DEFAULT_HEIGHT = 64; + + static final int SELECTION_FOREGROUND = SWT.COLOR_LIST_FOREGROUND; + static final int SELECTION_BACKGROUND = SWT.COLOR_LIST_BACKGROUND; + + static final int FOREGROUND = SWT.COLOR_WIDGET_FOREGROUND; + static final int BACKGROUND = SWT.COLOR_WIDGET_BACKGROUND; + + //TODO: add setter for spacing? + static final int SPACING = 3; +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
SelectionListener
+ * interface.
+ *
+ * widgetSelected
is called when the user changes the selected tab.
+ * widgetDefaultSelected
is not called.
+ *
true
if the receiver's border is visible.
+ *
+ * @return the receiver's border visibility state
+ *
+ * @exception SWTException true
if the chevron button
+ * is visible when necessary.
+ *
+ * @return the visibility of the chevron button
+ *
+ * @exception SWTException true
if the receiver is minimized.
+ *
+ * @return the receiver's minimized state
+ *
+ * @exception SWTException true
if the minimize button
+ * is visible.
+ *
+ * @return the visibility of the minimized button
+ *
+ * @exception SWTException true
if the receiver is maximized.
+ * + * + * @return the receiver's maximized state + * + * @exception SWTException
true
if the maximize button
+ * is visible.
+ *
+ * @return the visibility of the maximized button
+ *
+ * @exception SWTException true
if the receiver displays most
+ * recently used tabs and false
otherwise.
+ * + * When there is not enough horizontal space to show all the tabs, + * by default, tabs are shown sequentially from left to right in + * order of their index. When the MRU visibility is turned on, + * the tabs that are visible will be the tabs most recently selected. + * Tabs will still maintain their left to right order based on index + * but only the most recently selected tabs are visible. + *
+ * For example, consider a CTabFolder that contains "Tab 1", "Tab 2", + * "Tab 3" and "Tab 4" (in order by index). The user selects + * "Tab 1" and then "Tab 3". If the CTabFolder is now + * compressed so that only two tabs are visible, by default, + * "Tab 2" and "Tab 3" will be shown ("Tab 3" since it is currently + * selected and "Tab 2" because it is the previous item in index order). + * If MRU visibility is enabled, the two visible tabs will be "Tab 1" + * and "Tab 3" (in that order from left to right).
+ * + * @return the receiver's header's visibility state + * + * @exception SWTExceptiontrue
if the CTabFolder is rendered
+ * with a simple, traditional shape.
+ *
+ * @return true
if the CTabFolder is rendered with a simple shape
+ *
+ * @since 3.0
+ */
+public boolean getSimple() {
+ checkWidget();
+ return simple;
+}
+/**
+ * Returns true
if the CTabFolder only displays the selected tab
+ * and false
if the CTabFolder displays multiple tabs.
+ *
+ * @return true
if the CTabFolder only displays the selected tab and false
if the CTabFolder displays multiple tabs
+ *
+ * @since 3.0
+ */
+public boolean getSingle() {
+ checkWidget();
+ return single;
+}
+
+@Override
+public int getStyle() {
+ int style = super.getStyle();
+ style &= ~(SWT.TOP | SWT.BOTTOM);
+ style |= onBottom ? SWT.BOTTOM : SWT.TOP;
+ style &= ~(SWT.SINGLE | SWT.MULTI);
+ style |= single ? SWT.SINGLE : SWT.MULTI;
+ if (borderVisible) style |= SWT.BORDER;
+ style &= ~SWT.CLOSE;
+ if (showClose) style |= SWT.CLOSE;
+ return style;
+}
+/**
+ * Returns the height of the tab
+ *
+ * @return the height of the tab
+ *
+ * @exception SWTException SWT.RIGHT
or SWT.FILL
+ *
+ * @exception SWTException true
if the close button appears
+ * when the user hovers over an unselected tabs.
+ *
+ * @return true
if the close button appears on unselected tabs
+ *
+ * @since 3.0
+ */
+public boolean getUnselectedCloseVisible() {
+ checkWidget();
+ return showUnselectedClose;
+}
+/**
+ * Returns true
if an image appears
+ * in unselected tabs.
+ *
+ * @return true
if an image appears in unselected tabs
+ *
+ * @since 3.0
+ */
+public boolean getUnselectedImageVisible() {
+ checkWidget();
+ return showUnselectedImage;
+}
+/**
+ * Return the index of the specified tab or -1 if the tab is not
+ * in the receiver.
+ *
+ * @param item the tab item for which the index is required
+ *
+ * @return the index of the specified tab item or -1
+ *
+ * @exception IllegalArgumentException + * cfolder.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), + * display.getSystemColor(SWT.COLOR_BLUE), + * display.getSystemColor(SWT.COLOR_WHITE), + * display.getSystemColor(SWT.COLOR_WHITE)}, + * new int[] {25, 50, 100}); + *+ * + * @param colors an array of Color that specifies the colors to appear in the gradient + * in order of appearance left to right. The value
null
clears the
+ * background gradient. The value null
can be used inside the array of
+ * Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ * of the widget at which the color should change. The size of the percents
+ * array must be one less than the size of the colors
array.
+ *
+ * @exception SWTException + * cfolder.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), + * display.getSystemColor(SWT.COLOR_BLUE), + * display.getSystemColor(SWT.COLOR_WHITE), + * display.getSystemColor(SWT.COLOR_WHITE)}, + * new int[] {25, 50, 100}, true); + *+ * + * @param colors an array of Color that specifies the colors to appear in the gradient + * in order of appearance left to right. The value
null
clears the
+ * background gradient. The value null
can be used inside the array of
+ * Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ * of the widget at which the color should change. The size of the percents
+ * array must be one less than the size of the colors
array.
+ *
+ * @param vertical indicate the direction of the gradient. True
is vertical and false
is horizontal.
+ *
+ * @exception SWTException true
,
+ * and marks it invisible otherwise.
+ *
+ * @param visible the new visibility state
+ *
+ * @exception SWTException + * Note: No Layout can be set on this Control because it already + * manages the size and position of its children. + *
+ * + * @param layout the receiver's new layout or null + * + * @exception SWTExceptiontrue
,
+ * and marks it invisible otherwise.
+ *
+ * @param visible the new visibility state
+ *
+ * @exception SWTException + * For example, consider a CTabFolder that contains "Tab 1", "Tab 2", + * "Tab 3" and "Tab 4" (in order by index). The user selects + * "Tab 1" and then "Tab 3". If the CTabFolder is now + * compressed so that only two tabs are visible, by default, + * "Tab 2" and "Tab 3" will be shown ("Tab 3" since it is currently + * selected and "Tab 2" because it is the previous item in index order). + * If MRU visibility is enabled, the two visible tabs will be "Tab 1" + * and "Tab 3" (in that order from left to right).
+ * + * @param show the new visibility state + * + * @exception SWTException+ * cfolder.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), + * display.getSystemColor(SWT.COLOR_BLUE), + * display.getSystemColor(SWT.COLOR_WHITE), + * display.getSystemColor(SWT.COLOR_WHITE)}, + * new int[] {25, 50, 100}); + *+ * + * @param colors an array of Color that specifies the colors to appear in the gradient + * in order of appearance left to right. The value
null
clears the
+ * background gradient. The value null
can be used inside the array of
+ * Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ * of the widget at which the color should change. The size of the percents array must be one
+ * less than the size of the colors array.
+ *
+ * @exception SWTException + * cfolder.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), + * display.getSystemColor(SWT.COLOR_BLUE), + * display.getSystemColor(SWT.COLOR_WHITE), + * display.getSystemColor(SWT.COLOR_WHITE)}, + * new int[] {25, 50, 100}, true); + *+ * + * @param colors an array of Color that specifies the colors to appear in the gradient + * in order of appearance left to right. The value
null
clears the
+ * background gradient. The value null
can be used inside the array of
+ * Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ * of the widget at which the color should change. The size of the percents array must be one
+ * less than the size of the colors array.
+ *
+ * @param vertical indicate the direction of the gradient. True is vertical and false is horizontal.
+ *
+ * @exception SWTException true
if the CTabFolder should render itself in a simple, traditional style
+ *
+ * @exception SWTException true
if only the selected tab should be displayed otherwise, multiple tabs will be shown.
+ *
+ * @exception SWTException SWT.TOP
for tabs along the top or SWT.BOTTOM
for tabs along the bottom
+ *
+ * @exception SWTException
+ * The alignment parameter sets the layout of the control in the tab area.
+ * SWT.RIGHT
will cause the control to be positioned on the far
+ * right of the folder and it will have its default size. SWT.FILL
+ * will size the control to fill all the available space to the right of the
+ * last tab. If there is no available space, the control will not be visible.
+ * SWT.RIGHT | SWT.WRAP
will allow the control to wrap below the
+ * tabs if there is not enough available space to the right of the last tab.
+ *
SWT.RIGHT
or SWT.FILL
or SWT.RIGHT | SWT.WRAP
+ *
+ * @exception SWTException true
makes the close button appear
+ *
+ * @exception SWTException true
makes the image appear
+ *
+ * @exception SWTException
+* The flags parameter sets the layout of the control in the tab area.
+* SWT.LEAD
will cause the control to be positioned on the left
+* of the tabs. SWT.TRAIL
will cause the control to be positioned on
+* the far right of the folder and it will have its default size. SWT.TRAIL
+* can be combined with SWT.FILL
to fill all the available space to the
+* right of the last tab. SWT.WRAP
can also be added to SWT.TRAIL
+* only to cause a control to wrap if there is not enough space to display it in its
+* entirety.
+*
true
if the selected tab is rendered as
+ * highlighted.
+ *
+ * @return true
if the selected tab is rendered as
+ * highlighted
+ *
+ * @exception SWTException
+ * CTabFolder2Listener
interface.
+ *
+ * Classes that wish to deal with CTabFolderEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ *
+ * An alternative to this class are the static helper methods in + * {@link CTabFolder2Listener}, + * which accept a lambda expression or a method reference that implements the event consumer. + *
+ * + * @see CTabFolder2Listener + * @see CTabFolderEvent + * @see Sample code and further information + * + * @since 3.0 + */ +public class CTabFolder2Adapter implements CTabFolder2Listener { + +/** + * Sent when the user clicks on the close button of an item in the CTabFolder. The item being closed is specified + * in the event.item field. Setting the event.doit field to false will stop the CTabItem from closing. + * When the CTabItem is closed, it is disposed. The contents of the CTabItem (see CTabItem#setControl) will be + * made not visible when the CTabItem is closed. + *+ * The default behaviour is to close the CTabItem. + *
+ * + * @param event an event indicating the item being closed + */ +@Override +public void close(CTabFolderEvent event){} + +/** + * Sent when the user clicks on the minimize button of a CTabFolder. + *+ * The default behaviour is to do nothing. + *
+ * + * @param event an event containing information about the minimize + */ +@Override +public void minimize(CTabFolderEvent event){} + +/** + * Sent when the user clicks on the maximize button of a CTabFolder. + *+ * The default behaviour is to do nothing. + *
+ * + * @param event an event containing information about the maximize + */ +@Override +public void maximize(CTabFolderEvent event){} + +/** + * Sent when the user clicks on the restore button of a CTabFolder. + *+ * The default behaviour is to do nothing. + *
+ * + * @param event an event containing information about the restore + */ +@Override +public void restore(CTabFolderEvent event){} + +/** + * Sent when the user clicks on the chevron button of a CTabFolder. + *+ * The default behaviour is to show a list of items that are not currently + * visible and to change the selection based on the item selected from the list. + *
+ * + * @param event an event containing information about the show list + */ +@Override +public void showList(CTabFolderEvent event){} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolder2Listener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolder2Listener.java new file mode 100644 index 000000000..084e479e1 --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolder2Listener.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2000, 2017 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.custom; + +import java.util.function.*; + +import org.eclipse.swt.internal.*; + +/** + * Classes which implement this interface provide methods + * that deal with the events that are generated by the CTabFolder + * control. + *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a CTabFolder using the
+ * addCTabFolder2Listener
method and removed using
+ * the removeCTabFolder2Listener
method. When
+ * events occurs in a CTabFolder the appropriate method
+ * will be invoked.
+ *
false
and displaying a selection list.
+ *
+ * @param event an event containing information about the show list
+ *
+ * @see CTabFolder#setSelection(CTabItem)
+ */
+public void showList(CTabFolderEvent event);
+
+/**
+ * Static helper method to create a CTabFolder2Listener
for the
+ * {@link #close(CTabFolderEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return CTabFolder2Listener
+ * @since 3.107
+ */
+public static CTabFolder2Listener closeAdapter(ConsumerCTabFolder2Listener
for the
+ * {@link #minimize(CTabFolderEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return CTabFolder2Listener
+ * @since 3.107
+ */
+public static CTabFolder2Listener minimizeAdapter(ConsumerCTabFolder2Listener
for the
+ * {@link #maximize(CTabFolderEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return CTabFolder2Listener
+ * @since 3.107
+ */
+public static CTabFolder2Listener maximizeAdapter(ConsumerCTabFolder2Listener
for the
+ * {@link #restore(CTabFolderEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return CTabFolder2Listener
+ * @since 3.107
+ */
+public static CTabFolder2Listener restoreAdapter(ConsumerCTabFolder2Listener
for the
+ * {@link #showList(CTabFolderEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return CTabFolder2Listener
+ * @since 3.107
+ */
+public static CTabFolder2Listener showListAdapter(ConsumerCTabFolderListener
interface.
+ *
+ * @see CTabFolderListener
+ * @see CTabFolderEvent
+ * @see Sample code and further information
+ */
+public class CTabFolderAdapter implements CTabFolderListener {
+ @Override
+ public void itemClosed(CTabFolderEvent event){}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolderEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolderEvent.java
new file mode 100644
index 000000000..8bc5afa16
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolderEvent.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This event is sent when an event is generated in the CTabFolder.
+ *
+ * @see Sample code and further information
+ */
+public class CTabFolderEvent extends TypedEvent {
+ /**
+ * The tab item for the operation.
+ */
+ public Widget item;
+
+ /**
+ * A flag indicating whether the operation should be allowed.
+ * Setting this field to false
will cancel the operation.
+ * Applies to the close and showList events.
+ */
+ public boolean doit;
+
+ /**
+ * The widget-relative, x coordinate of the chevron button
+ * at the time of the event. Applies to the showList event.
+ *
+ * @since 3.0
+ */
+ public int x;
+ /**
+ * The widget-relative, y coordinate of the chevron button
+ * at the time of the event. Applies to the showList event.
+ *
+ * @since 3.0
+ */
+ public int y;
+ /**
+ * The width of the chevron button at the time of the event.
+ * Applies to the showList event.
+ *
+ * @since 3.0
+ */
+ public int width;
+ /**
+ * The height of the chevron button at the time of the event.
+ * Applies to the showList event.
+ *
+ * @since 3.0
+ */
+ public int height;
+
+ static final long serialVersionUID = 3760566386225066807L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param w the widget that fired the event
+ */
+CTabFolderEvent(Widget w) {
+ super(w);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " item=" + item
+ + " doit=" + doit
+ + " x=" + x
+ + " y=" + y
+ + " width=" + width
+ + " height=" + height
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolderLayout.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolderLayout.java
new file mode 100644
index 000000000..5b653a493
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolderLayout.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides the layout for CTabFolder
+ *
+ * @see CTabFolder
+ */
+class CTabFolderLayout extends Layout {
+@Override
+protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
+ CTabFolder folder = (CTabFolder)composite;
+ CTabItem[] items = folder.items;
+ CTabFolderRenderer renderer = folder.renderer;
+ // preferred width of tab area to show all tabs
+ int tabW = 0;
+ int selectedIndex = folder.selectedIndex;
+ if (selectedIndex == -1) selectedIndex = 0;
+ GC gc = new GC(folder);
+ for (int i = 0; i < items.length; i++) {
+ if (folder.single) {
+ tabW = Math.max(tabW, renderer.computeSize(i, SWT.SELECTED, gc, SWT.DEFAULT, SWT.DEFAULT).x);
+ } else {
+ int state = 0;
+ if (i == selectedIndex) state |= SWT.SELECTED;
+ tabW += renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x;
+ }
+ }
+
+ int width = 0, wrapHeight = 0;
+ boolean leftControl = false, rightControl = false;
+ if (wHint == SWT.DEFAULT) {
+ for (int i = 0; i < folder.controls.length; i++) {
+ Control control = folder.controls[i];
+ if (!control.isDisposed() && control.getVisible()) {
+ if ((folder.controlAlignments[i] & SWT.LEAD) != 0) {
+ leftControl = true;
+ } else {
+ rightControl = true;
+ }
+ width += control.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
+ }
+ }
+ } else {
+ Point size = new Point (wHint, hHint);
+ boolean[][] positions = new boolean[1][];
+ Rectangle[] rects = folder.computeControlBounds(size, positions);
+ int minY = Integer.MAX_VALUE, maxY = 0;
+ for (int i = 0; i < rects.length; i++) {
+ if (positions[0][i]) {
+ minY = Math.min(minY, rects[i].y);
+ maxY = Math.max(maxY, rects[i].y + rects[i].height);
+ wrapHeight = maxY - minY;
+ } else {
+ if ((folder.controlAlignments[i] & SWT.LEAD) != 0) {
+ leftControl = true;
+ } else {
+ rightControl = true;
+ }
+ width += rects[i].width;
+ }
+ }
+ }
+ if (leftControl) width += CTabFolder.SPACING * 2;
+ if (rightControl) width += CTabFolder.SPACING * 2;
+ tabW += width;
+
+ gc.dispose();
+
+ int controlW = 0;
+ int controlH = 0;
+ // preferred size of controls in tab items
+ for (int i = 0; i < items.length; i++) {
+ Control control = items[i].control;
+ if (control != null && !control.isDisposed()){
+ Point size = control.computeSize (wHint, hHint, flushCache);
+ controlW = Math.max (controlW, size.x);
+ controlH = Math.max (controlH, size.y);
+ }
+ }
+
+ int minWidth = Math.max(tabW, controlW + folder.marginWidth);
+ int minHeight = (folder.minimized) ? 0 : controlH + wrapHeight;
+ if (minWidth == 0) minWidth = CTabFolder.DEFAULT_WIDTH;
+ if (minHeight == 0) minHeight = CTabFolder.DEFAULT_HEIGHT;
+
+ if (wHint != SWT.DEFAULT) minWidth = wHint;
+ if (hHint != SWT.DEFAULT) minHeight = hHint;
+
+ return new Point (minWidth, minHeight);
+}
+@Override
+protected boolean flushCache(Control control) {
+ return true;
+}
+@Override
+protected void layout(Composite composite, boolean flushCache) {
+ CTabFolder folder = (CTabFolder)composite;
+ // resize content
+ if (folder.selectedIndex != -1) {
+ Control control = folder.items[folder.selectedIndex].control;
+ if (control != null && !control.isDisposed()) {
+ control.setBounds(folder.getClientArea());
+ }
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolderListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolderListener.java
new file mode 100644
index 000000000..ce2e1a2fd
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/CTabFolderListener.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * Classes which implement this interface provide a method
+ * that deals with events generated in the CTabFolder.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a CTabFolder using the
+ * addCTabFolderListener
method and removed using
+ * the removeCTabFolderListener
method. When a
+ * tab item is closed, the itemClosed method will be invoked.
+ *
CTabFolder
. This class can be subclassed in order to
+ * customize the look of a CTabFolder.
+ *
+ * @see Sample code and further information
+ * @since 3.6
+ */
+public class CTabFolderRenderer {
+
+ protected CTabFolder parent;
+
+ int[] curve;
+ int[] topCurveHighlightStart;
+ int[] topCurveHighlightEnd;
+ int curveWidth = 0;
+ int curveIndent = 0;
+ int lastTabHeight = -1;
+
+ Color fillColor;
+ /* Selected item appearance */
+ Color selectionHighlightGradientBegin = null; //null == no highlight
+ //Although we are given new colours all the time to show different states (active, etc),
+ //some of which may have a highlight and some not, we'd like to retain the highlight colours
+ //as a cache so that we can reuse them if we're again told to show the highlight.
+ //We are relying on the fact that only one tab state usually gets a highlight, so only
+ //a single cache is required. If that happens to not be true, cache simply becomes less effective,
+ //but we don't leak colours.
+ Color[] selectionHighlightGradientColorsCache = null; //null is a legal value, check on access
+ /* Colors for anti-aliasing */
+ Color selectedOuterColor = null;
+ Color selectedInnerColor = null;
+ Color tabAreaColor = null;
+ Color minMaxBorderColor = null;
+ /*
+ * Border color that was used in computing the cached anti-alias Colors.
+ * We have to recompute the colors if the border color changes
+ */
+ Color lastBorderColor = null;
+
+ Font chevronFont = null;
+
+ //TOP_LEFT_CORNER_HILITE is laid out in reverse (ie. top to bottom)
+ //so can fade in same direction as right swoop curve
+ static final int[] TOP_LEFT_CORNER_HILITE = new int[] {5,2, 4,2, 3,3, 2,4, 2,5, 1,6};
+
+ static final int[] TOP_LEFT_CORNER = new int[] {0,6, 1,5, 1,4, 4,1, 5,1, 6,0};
+ static final int[] TOP_RIGHT_CORNER = new int[] {-6,0, -5,1, -4,1, -1,4, -1,5, 0,6};
+ static final int[] BOTTOM_LEFT_CORNER = new int[] {0,-6, 1,-5, 1,-4, 4,-1, 5,-1, 6,0};
+ static final int[] BOTTOM_RIGHT_CORNER = new int[] {-6,0, -5,-1, -4,-1, -1,-4, -1,-5, 0,-6};
+
+ static final int[] SIMPLE_TOP_LEFT_CORNER = new int[] {0,2, 1,1, 2,0};
+ static final int[] SIMPLE_TOP_RIGHT_CORNER = new int[] {-2,0, -1,1, 0,2};
+ static final int[] SIMPLE_BOTTOM_LEFT_CORNER = new int[] {0,-2, 1,-1, 2,0};
+ static final int[] SIMPLE_BOTTOM_RIGHT_CORNER = new int[] {-2,0, -1,-1, 0,-2};
+ static final int[] SIMPLE_UNSELECTED_INNER_CORNER = new int[] {0,0};
+
+ static final int[] TOP_LEFT_CORNER_BORDERLESS = new int[] {0,6, 1,5, 1,4, 4,1, 5,1, 6,0};
+ static final int[] TOP_RIGHT_CORNER_BORDERLESS = new int[] {-7,0, -6,1, -5,1, -2,4, -2,5, -1,6};
+ static final int[] BOTTOM_LEFT_CORNER_BORDERLESS = new int[] {0,-6, 1,-6, 1,-5, 2,-4, 4,-2, 5,-1, 6,-1, 6,0};
+ static final int[] BOTTOM_RIGHT_CORNER_BORDERLESS = new int[] {-7,0, -7,-1, -6,-1, -5,-2, -3,-4, -2,-5, -2,-6, -1,-6};
+
+ static final int[] SIMPLE_TOP_LEFT_CORNER_BORDERLESS = new int[] {0,2, 1,1, 2,0};
+ static final int[] SIMPLE_TOP_RIGHT_CORNER_BORDERLESS= new int[] {-3,0, -2,1, -1,2};
+ static final int[] SIMPLE_BOTTOM_LEFT_CORNER_BORDERLESS = new int[] {0,-3, 1,-2, 2,-1, 3,0};
+ static final int[] SIMPLE_BOTTOM_RIGHT_CORNER_BORDERLESS = new int[] {-4,0, -3,-1, -2,-2, -1,-3};
+
+ static final RGB CLOSE_FILL = new RGB(252, 160, 160);
+
+ static final int BUTTON_SIZE = 16;
+ static final int BUTTON_TRIM = 1;
+
+ static final int BUTTON_BORDER = SWT.COLOR_WIDGET_DARK_SHADOW;
+ static final int BUTTON_FILL = SWT.COLOR_LIST_BACKGROUND;
+ static final int BORDER1_COLOR = SWT.COLOR_WIDGET_NORMAL_SHADOW;
+
+ static final int ITEM_TOP_MARGIN = 2;
+ static final int ITEM_BOTTOM_MARGIN = 2;
+ static final int ITEM_LEFT_MARGIN = 4;
+ static final int ITEM_RIGHT_MARGIN = 4;
+ static final int INTERNAL_SPACING = 4;
+ static final int FLAGS = SWT.DRAW_TRANSPARENT | SWT.DRAW_MNEMONIC | SWT.DRAW_DELIMITER;
+ static final String ELLIPSIS = "..."; //$NON-NLS-1$
+ private static final String CHEVRON_ELLIPSIS = "99+"; //$NON-NLS-1$
+ private static final int CHEVRON_FONT_HEIGHT = 10;
+
+ //Part constants
+ /**
+ * Part constant indicating the body of the tab folder. The body is the
+ * underlying container for all of the tab folder and all other parts are
+ * drawn on top of it. (value is -1).
+ *
+ * @see #computeSize(int, int, GC, int, int)
+ * @see #computeTrim(int, int, int, int, int, int)
+ * @see #draw(int, int, Rectangle, GC)
+ */
+ public static final int PART_BODY = -1;
+ /**
+ * Part constant indicating the tab header of the folder (value is -2). The
+ * header is drawn on top of the body and provides an area for the tabs and
+ * other tab folder buttons to be rendered.
+ *
+ * @see #computeSize(int, int, GC, int, int)
+ * @see #computeTrim(int, int, int, int, int, int)
+ * @see #draw(int, int, Rectangle, GC)
+ */
+ public static final int PART_HEADER = -2;
+ /**
+ * Part constant indicating the border of the tab folder. (value is -3). The
+ * border is drawn around the body and is part of the body trim.
+ *
+ * @see #computeSize(int, int, GC, int, int)
+ * @see #computeTrim(int, int, int, int, int, int)
+ * @see #draw(int, int, Rectangle, GC)
+ */
+ public static final int PART_BORDER = -3;
+ /**
+ * Part constant indicating the background of the tab folder. (value is -4).
+ *
+ * @see #computeSize(int, int, GC, int, int)
+ * @see #computeTrim(int, int, int, int, int, int)
+ * @see #draw(int, int, Rectangle, GC)
+ */
+ public static final int PART_BACKGROUND = -4;
+ /**
+ * Part constant indicating the maximize button of the tab folder. (value is
+ * -5).
+ *
+ * @see #computeSize(int, int, GC, int, int)
+ * @see #computeTrim(int, int, int, int, int, int)
+ * @see #draw(int, int, Rectangle, GC)
+ */
+ public static final int PART_MAX_BUTTON = -5;
+ /**
+ * Part constant indicating the minimize button of the tab folder. (value is
+ * -6).
+ *
+ * @see #computeSize(int, int, GC, int, int)
+ * @see #computeTrim(int, int, int, int, int, int)
+ * @see #draw(int, int, Rectangle, GC)
+ */
+ public static final int PART_MIN_BUTTON = -6;
+ /**
+ * Part constant indicating the chevron button of the tab folder. (value is
+ * -7).
+ *
+ * @see #computeSize(int, int, GC, int, int)
+ * @see #computeTrim(int, int, int, int, int, int)
+ * @see #draw(int, int, Rectangle, GC)
+ */
+ public static final int PART_CHEVRON_BUTTON = -7;
+ /**
+ * Part constant indicating the close button of a tab item. (value is -8).
+ *
+ * @see #computeSize(int, int, GC, int, int)
+ * @see #computeTrim(int, int, int, int, int, int)
+ * @see #draw(int, int, Rectangle, GC)
+ */
+ public static final int PART_CLOSE_BUTTON = -8;
+
+ public static final int MINIMUM_SIZE = 1 << 24; //TODO: Should this be a state?
+
+
+ /**
+ * Constructs a new instance of this class given its parent.
+ *
+ * @param parent CTabFolder
+ *
+ * @exception IllegalArgumentException
+ * The preferred size of a part is the size that it would
+ * best be displayed at. The width hint and height hint arguments
+ * allow the caller to ask a control questions such as "Given a particular
+ * width, how high does the part need to be to show all of the contents?"
+ * To indicate that the caller does not wish to constrain a particular
+ * dimension, the constant SWT.DEFAULT
is passed for the hint.
+ *
+ * The part
value indicated what component the preferred size is
+ * to be calculated for. Valid values are any of the part constants:
+ *
+ * The state
parameter may be one of the following:
+ *
SWT.DEFAULT
)
+ * @param hHint the height hint (can be SWT.DEFAULT
)
+ * @return the preferred size of the part
+ *
+ * @since 3.6
+ */
+ protected Point computeSize (int part, int state, GC gc, int wHint, int hHint) {
+ int width = 0, height = 0;
+ switch (part) {
+ case PART_HEADER:
+ if (parent.fixedTabHeight != SWT.DEFAULT) {
+ height = parent.fixedTabHeight == 0 ? 0 : parent.fixedTabHeight + 1; // +1 for line drawn across top of tab
+ } else {
+ CTabItem[] items = parent.items;
+ if (items.length == 0) {
+ height = gc.textExtent("Default", FLAGS).y + ITEM_TOP_MARGIN + ITEM_BOTTOM_MARGIN; //$NON-NLS-1$
+ } else {
+ for (int i=0; i < items.length; i++) {
+ height = Math.max(height, computeSize(i, SWT.NONE, gc, wHint, hHint).y);
+ }
+ }
+ gc.dispose();
+ }
+ break;
+ case PART_MAX_BUTTON:
+ case PART_MIN_BUTTON:
+ case PART_CLOSE_BUTTON:
+ width = height = BUTTON_SIZE;
+ break;
+ case PART_CHEVRON_BUTTON:
+ Font prevFont = gc.getFont();
+ gc.setFont(getChevronFont(parent.getDisplay()));
+ int widthOfDoubleArrows = 8; // see drawChevron method
+ width = gc.textExtent(CHEVRON_ELLIPSIS).x + widthOfDoubleArrows;
+ height = BUTTON_SIZE;
+ gc.setFont(prevFont);
+ break;
+ default:
+ if (0 <= part && part < parent.getItemCount()) {
+ updateCurves();
+ CTabItem item = parent.items[part];
+ if (item.isDisposed()) return new Point(0,0);
+ Image image = item.getImage();
+ if (image != null && !image.isDisposed()) {
+ Rectangle bounds = image.getBounds();
+ if ((state & SWT.SELECTED) != 0 || parent.showUnselectedImage) {
+ width += bounds.width;
+ }
+ height = bounds.height;
+ }
+ String text = null;
+ if ((state & MINIMUM_SIZE) != 0) {
+ int minChars = parent.minChars;
+ text = minChars == 0 ? null : item.getText();
+ if (text != null && text.length() > minChars) {
+ if (useEllipses()) {
+ int end = minChars < ELLIPSIS.length() + 1 ? minChars : minChars - ELLIPSIS.length();
+ text = text.substring(0, end);
+ if (minChars > ELLIPSIS.length() + 1) text += ELLIPSIS;
+ } else {
+ int end = minChars;
+ text = text.substring(0, end);
+ }
+ }
+ } else {
+ text = item.getText();
+ }
+ if (text != null) {
+ if (width > 0) width += INTERNAL_SPACING;
+ if (item.font == null) {
+ Point size = gc.textExtent(text, FLAGS);
+ width += size.x;
+ height = Math.max(height, size.y);
+ } else {
+ Font gcFont = gc.getFont();
+ gc.setFont(item.font);
+ Point size = gc.textExtent(text, FLAGS);
+ width += size.x;
+ height = Math.max(height, size.y);
+ gc.setFont(gcFont);
+ }
+ }
+ if (parent.showClose || item.showClose) {
+ if ((state & SWT.SELECTED) != 0 || parent.showUnselectedClose) {
+ if (width > 0) width += INTERNAL_SPACING;
+ width += computeSize(PART_CLOSE_BUTTON, SWT.NONE, gc, SWT.DEFAULT, SWT.DEFAULT).x;
+ }
+ }
+ }
+ break;
+ }
+ Rectangle trim = computeTrim(part, state, 0, 0, width, height);
+ width = trim.width;
+ height = trim.height;
+ return new Point(width, height);
+ }
+
+ /**
+ * Given a desired client area for the part
+ * (as described by the arguments), returns the bounding
+ * rectangle which would be required to produce that client
+ * area.
+ * + * In other words, it returns a rectangle such that, if the + * part's bounds were set to that rectangle, the area + * of the part which is capable of displaying data + * (that is, not covered by the "trimmings") would be the + * rectangle described by the arguments (relative to the + * receiver's parent). + *
+ * + * @param part one of the part constants + * @param state the state of the part + * @param x the desired x coordinate of the client area + * @param y the desired y coordinate of the client area + * @param width the desired width of the client area + * @param height the desired height of the client area + * @return the required bounds to produce the given client area + * + * @see CTabFolderRenderer#computeSize(int, int, GC, int, int) valid part and state values + * + * @since 3.6 + */ + protected Rectangle computeTrim (int part, int state, int x, int y, int width, int height) { + int borderLeft = parent.borderVisible ? 1 : 0; + int borderRight = borderLeft; + int borderTop = parent.onBottom ? borderLeft : 0; + int borderBottom = parent.onBottom ? 0 : borderLeft; + int tabHeight = parent.tabHeight; + switch (part) { + case PART_BODY: + int style = parent.getStyle(); + int highlight_header = (style & SWT.FLAT) != 0 ? 1 : 3; + int highlight_margin = (style & SWT.FLAT) != 0 ? 0 : 2; + if (parent.fixedTabHeight == 0 && (style & SWT.FLAT) != 0 && (style & SWT.BORDER) == 0) { + highlight_header = 0; + } + int marginWidth = parent.marginWidth; + int marginHeight = parent.marginHeight; + x = x - marginWidth - highlight_margin - borderLeft; + width = width + borderLeft + borderRight + 2*marginWidth + 2*highlight_margin; + if (parent.minimized) { + y = parent.onBottom ? y - borderTop : y - highlight_header - tabHeight - borderTop; + height = borderTop + borderBottom + tabHeight + highlight_header; + } else { + y = parent.onBottom ? y - marginHeight - highlight_margin - borderTop : y - marginHeight - highlight_header - tabHeight - borderTop; + height = height + borderTop + borderBottom + 2*marginHeight + tabHeight + highlight_header + highlight_margin; + } + break; + case PART_HEADER: + //no trim + break; + case PART_MAX_BUTTON: + case PART_MIN_BUTTON: + case PART_CLOSE_BUTTON: + case PART_CHEVRON_BUTTON: + x -= BUTTON_TRIM; + y -= BUTTON_TRIM; + width += BUTTON_TRIM*2; + height += BUTTON_TRIM*2; + break; + case PART_BORDER: + x = x - borderLeft; + width = width + borderLeft + borderRight; + if (!parent.simple) width += 2; // TOP_RIGHT_CORNER needs more space + y = y - borderTop; + height = height + borderTop + borderBottom; + break; + default: + if (0 <= part && part < parent.getItemCount()) { + updateCurves(); + x = x - ITEM_LEFT_MARGIN; + width = width + ITEM_LEFT_MARGIN + ITEM_RIGHT_MARGIN; + if (!parent.simple && !parent.single && (state & SWT.SELECTED) != 0) { + width += curveWidth - curveIndent; + } + y = y - ITEM_TOP_MARGIN; + height = height + ITEM_TOP_MARGIN + ITEM_BOTTOM_MARGIN; + } + break; + } + return new Rectangle(x, y, width, height); + } + + void createAntialiasColors() { + disposeAntialiasColors(); + lastBorderColor = parent.getDisplay().getSystemColor(BORDER1_COLOR); + RGB lineRGB = lastBorderColor.getRGB(); + /* compute the selected color */ + RGB innerRGB = parent.selectionBackground.getRGB(); + if (parent.selectionBgImage != null || + (parent.selectionGradientColors != null && parent.selectionGradientColors.length > 1)) { + innerRGB = null; + } + RGB outerRGB = parent.getBackground().getRGB(); + if (parent.gradientColors != null && parent.gradientColors.length > 1) { + outerRGB = null; + } + if (outerRGB != null) { + RGB from = lineRGB; + RGB to = outerRGB; + int red = from.red + 2*(to.red - from.red)/3; + int green = from.green + 2*(to.green - from.green)/3; + int blue = from.blue + 2*(to.blue - from.blue)/3; + selectedOuterColor = new Color(parent.getDisplay(), red, green, blue); + } + if (innerRGB != null) { + RGB from = lineRGB; + RGB to = innerRGB; + int red = from.red + 2*(to.red - from.red)/3; + int green = from.green + 2*(to.green - from.green)/3; + int blue = from.blue + 2*(to.blue - from.blue)/3; + selectedInnerColor = new Color(parent.getDisplay(), red, green, blue); + } + /* compute the tabArea color */ + outerRGB = parent.getParent().getBackground().getRGB(); + if (outerRGB != null) { + RGB from = lineRGB; + RGB to = outerRGB; + int red = from.red + 2*(to.red - from.red)/3; + int green = from.green + 2*(to.green - from.green)/3; + int blue = from.blue + 2*(to.blue - from.blue)/3; + tabAreaColor = new Color(parent.getDisplay(), red, green, blue); + } + } + + /* + * Allocate colors for the highlight line. + * Colours will be a gradual blend ranging from to. + * Blend length will be tab height. + * Recompute this if tab height changes. + * Could remain null if there'd be no gradient (start=end or low colour display) + */ + void createSelectionHighlightGradientColors(Color start) { + disposeSelectionHighlightGradientColors(); //dispose if existing + + if(start == null) //shouldn't happen but just to be safe + return; + + //alloc colours for entire height to ensure it matches wherever we stop drawing + int fadeGradientSize = parent.tabHeight; + + RGB from = start.getRGB(); + RGB to = parent.selectionBackground.getRGB(); + + selectionHighlightGradientColorsCache = new Color[fadeGradientSize]; + int denom = fadeGradientSize - 1; + + for (int i = 0; i < fadeGradientSize; i++) { + int propFrom = denom - i; + int propTo = i; + int red = (to.red * propTo + from.red * propFrom) / denom; + int green = (to.green * propTo + from.green * propFrom) / denom; + int blue = (to.blue * propTo + from.blue * propFrom) / denom; + selectionHighlightGradientColorsCache[i] = new Color(parent.getDisplay(), red, green, blue); + } + } + + /** + * Dispose of any operating system resources associated with + * the renderer. Called by the CTabFolder parent upon receiving + * the dispose event or when changing the renderer. + * + * @since 3.6 + */ + protected void dispose() { + disposeAntialiasColors(); + disposeSelectionHighlightGradientColors(); + if (fillColor != null) { + fillColor.dispose(); + fillColor = null; + } + if (chevronFont != null) { + chevronFont.dispose(); + chevronFont = null; + } + if (minMaxBorderColor != null) { + minMaxBorderColor.dispose(); + minMaxBorderColor = null; + } + } + + void disposeAntialiasColors() { + if (tabAreaColor != null) tabAreaColor.dispose(); + if (selectedInnerColor != null) selectedInnerColor.dispose(); + if (selectedOuterColor != null) selectedOuterColor.dispose(); + tabAreaColor = selectedInnerColor = selectedOuterColor = null; + } + + void disposeSelectionHighlightGradientColors() { + if(selectionHighlightGradientColorsCache == null) + return; + for (Color element : selectionHighlightGradientColorsCache) { + element.dispose(); + } + selectionHighlightGradientColorsCache = null; + } + + /** + * Draw a specifiedpart
of the CTabFolder using the provided bounds
and GC
.
+ * The valid CTabFolder part
constants are:
+ *
+ * The state
parameter may be a combination of:
+ *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see CTabFolder, CTabItem snippets + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class CTabItem extends Item { + CTabFolder parent; + int x,y,width,height = 0; + Control control; // the tab page + + String toolTipText; + String shortenedText; + int shortenedTextWidth; + + // Appearance + Font font; + Image disabledImage; + + Rectangle closeRect = new Rectangle(0, 0, 0, 0); + int closeImageState = SWT.BACKGROUND; + int state = SWT.NONE; + boolean showClose = false; + boolean showing = false; + +/** + * Constructs a new instance of this class given its parent + * (which must be aCTabFolder
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
CTabFolder
), a style value
+ * describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
CTabFolder
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException true
to indicate that the receiver's close button should be shown.
+ * Otherwise return false
. The initial value is defined by the style (SWT.CLOSE)
+ * that was used to create the receiver.
+ *
+ * @return true
if the close button should be shown
+ *
+ * @exception SWTException true
if the item will be rendered in the visible area of the CTabFolder. Returns false otherwise.
+*
+* @return true
if the item will be rendered in the visible area of the CTabFolder. Returns false otherwise.
+*
+* @exception SWTException true
to indicate that the receiver's close button should be shown.
+ * If the parent (CTabFolder) was created with SWT.CLOSE style, changing this value has
+ * no effect.
+ *
+ * @param close the new state of the close button
+ *
+ * @exception SWTException + * The mnemonic indicator (character '&') is not displayed in a tool tip. + * To display a single '&' in the tool tip, the character '&' can be + * escaped by doubling it in the string. + *
+ * + * @param string the new tool tip text (or null) + * + * @exception SWTExceptionHere is an example of using a ControlEditor:
+* +*
+* Canvas canvas = new Canvas(shell, SWT.BORDER);
+* canvas.setBounds(10, 10, 300, 300);
+* Color color = new Color(null, 255, 0, 0);
+* canvas.setBackground(color);
+* ControlEditor editor = new ControlEditor (canvas);
+* // The editor will be a button in the bottom right corner of the canvas.
+* // When selected, it will launch a Color dialog that will change the background
+* // of the canvas.
+* Button button = new Button(canvas, SWT.PUSH);
+* button.setText("Select Color...");
+* button.addSelectionListener (new SelectionAdapter() {
+* public void widgetSelected(SelectionEvent e) {
+* ColorDialog dialog = new ColorDialog(shell);
+* dialog.open();
+* RGB rgb = dialog.getRGB();
+* if (rgb != null) {
+* if (color != null) color.dispose();
+* color = new Color(null, rgb);
+* canvas.setBackground(color);
+* }
+*
+* }
+* });
+*
+* editor.horizontalAlignment = SWT.RIGHT;
+* editor.verticalAlignment = SWT.BOTTOM;
+* editor.grabHorizontal = false;
+* editor.grabVertical = false;
+* Point size = button.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+* editor.minimumWidth = size.x;
+* editor.minimumHeight = size.y;
+* editor.setEditor (button);
+*
+*
+* @see Sample code and further information
+*/
+public class ControlEditor {
+
+ /**
+ * Specifies how the editor should be aligned relative to the control. Allowed values
+ * are SWT.LEFT, SWT.RIGHT and SWT.CENTER. The default value is SWT.CENTER.
+ */
+ public int horizontalAlignment = SWT.CENTER;
+
+ /**
+ * Specifies whether the editor should be sized to use the entire width of the control.
+ * True means resize the editor to the same width as the cell. False means do not adjust
+ * the width of the editor. The default value is false.
+ */
+ public boolean grabHorizontal = false;
+
+ /**
+ * Specifies the minimum width the editor can have. This is used in association with
+ * a true value of grabHorizontal. If the cell becomes smaller than the minimumWidth, the
+ * editor will not made smaller than the minimum width value. The default value is 0.
+ */
+ public int minimumWidth = 0;
+
+ /**
+ * Specifies how the editor should be aligned relative to the control. Allowed values
+ * are SWT.TOP, SWT.BOTTOM and SWT.CENTER. The default value is SWT.CENTER.
+ */
+ public int verticalAlignment = SWT.CENTER;
+
+ /**
+ * Specifies whether the editor should be sized to use the entire height of the control.
+ * True means resize the editor to the same height as the underlying control. False means do not adjust
+ * the height of the editor. The default value is false.
+ */
+ public boolean grabVertical = false;
+
+ /**
+ * Specifies the minimum height the editor can have. This is used in association with
+ * a true value of grabVertical. If the control becomes smaller than the minimumHeight, the
+ * editor will not made smaller than the minimum height value. The default value is 0.
+ */
+ public int minimumHeight = 0;
+
+ Composite parent;
+ Control editor;
+ private boolean hadFocus;
+ private Listener controlListener;
+ private Listener scrollbarListener;
+
+ private final static int [] EVENTS = {SWT.KeyDown, SWT.KeyUp, SWT.MouseDown, SWT.MouseUp, SWT.Resize};
+/**
+* Creates a ControlEditor for the specified Composite.
+*
+* @param parent the Composite above which this editor will be displayed
+*
+*/
+public ControlEditor (Composite parent) {
+ this.parent = parent;
+
+ controlListener = e -> layout ();
+ for (int i=0; iStyledTextContent
will always have
+ * at least one empty line.
+ */
+DefaultContent() {
+ super();
+ setText("");
+}
+/**
+ * Adds a line to the end of the line indexes array. Increases the size of the array if necessary.
+ * lineCount
is updated to reflect the new entry.
+ *
+ *
+ * @param start the start of the line
+ * @param length the length of the line
+ */
+void addLineIndex(int start, int length) {
+ int size = lines.length;
+ if (lineCount == size) {
+ // expand the lines by powers of 2
+ int[][] newLines = new int[size+Compatibility.pow2(expandExp)][2];
+ System.arraycopy(lines, 0, newLines, 0, size);
+ lines = newLines;
+ expandExp++;
+ }
+ int[] range = new int[] {start, length};
+ lines[lineCount] = range;
+ lineCount++;
+}
+/**
+ * Adds a line index to the end of linesArray
. Increases the
+ * size of the array if necessary and returns a new array.
+ *
+ *
+ * @param start the start of the line
+ * @param length the length of the line
+ * @param linesArray the array to which to add the line index
+ * @param count the position at which to add the line
+ * @return a new array of line indexes
+ */
+int[][] addLineIndex(int start, int length, int[][] linesArray, int count) {
+ int size = linesArray.length;
+ int[][] newLines = linesArray;
+ if (count == size) {
+ newLines = new int[size+Compatibility.pow2(replaceExpandExp)][2];
+ replaceExpandExp++;
+ System.arraycopy(linesArray, 0, newLines, 0, size);
+ }
+ int[] range = new int[] {start, length};
+ newLines[count] = range;
+ return newLines;
+}
+/**
+ * Adds a TextChangeListener
listening for
+ * TextChangingEvent
and TextChangedEvent
. A
+ * TextChangingEvent
is sent before changes to the text occur.
+ * A TextChangedEvent
is sent after changes to the text
+ * occurred.
+ *
+ * + * @param listener the listener + * @exception IllegalArgumentException
+ * + * @param position the position at which a change is occurring + * @param sizeHint the size of the change + * @param line the line where the gap will go + */ +void adjustGap(int position, int sizeHint, int line) { + if (position == gapStart) { + // text is being inserted at the gap position + int size = (gapEnd - gapStart) - sizeHint; + if (lowWatermark <= size && size <= highWatermark) + return; + } else if ((position + sizeHint == gapStart) && (sizeHint < 0)) { + // text is being deleted at the gap position + int size = (gapEnd - gapStart) - sizeHint; + if (lowWatermark <= size && size <= highWatermark) + return; + } + moveAndResizeGap(position, sizeHint, line); +} +/** + * Calculates the indexes of each line in the text store. Assumes no gap exists. + * Optimized to do less checking. + */ +void indexLines(){ + int start = 0; + lineCount = 0; + int textLength = textStore.length; + int i; + for (i = start; i < textLength; i++) { + char ch = textStore[i]; + if (ch == SWT.CR) { + // see if the next character is a LF + if (i + 1 < textLength) { + ch = textStore[i+1]; + if (ch == SWT.LF) { + i++; + } + } + addLineIndex(start, i - start + 1); + start = i + 1; + } else if (ch == SWT.LF) { + addLineIndex(start, i - start + 1); + start = i + 1; + } + } + addLineIndex(start, i - start); +} +/** + * Returns whether or not the given character is a line delimiter. Both CR and LF + * are valid line delimiters. + *
+ * + * @param ch the character to test + * @return true if ch is a delimiter, false otherwise + */ +boolean isDelimiter(char ch) { + if (ch == SWT.CR) return true; + if (ch == SWT.LF) return true; + return false; +} +/** + * Determine whether or not the replace operation is valid. DefaultContent will not allow + * the /r/n line delimiter to be split or partially deleted. + *
+ * + * @param start start offset of text to replace + * @param replaceLength start offset of text to replace + * @param newText start offset of text to replace + * @return a boolean specifying whether or not the replace operation is valid + */ +protected boolean isValidReplace(int start, int replaceLength, String newText){ + if (replaceLength == 0) { + // inserting text, see if the \r\n line delimiter is being split + if (start == 0) return true; + if (start == getCharCount()) return true; + char before = getTextRange(start - 1, 1).charAt(0); + if (before == '\r') { + char after = getTextRange(start, 1).charAt(0); + if (after == '\n') return false; + } + } else { + // deleting text, see if part of a \r\n line delimiter is being deleted + char startChar = getTextRange(start, 1).charAt(0); + if (startChar == '\n') { + // see if char before delete position is \r + if (start != 0) { + char before = getTextRange(start - 1, 1).charAt(0); + if (before == '\r') return false; + } + } + char endChar = getTextRange(start + replaceLength - 1, 1).charAt(0); + if (endChar == '\r') { + // see if char after delete position is \n + if (start + replaceLength != getCharCount()) { + char after = getTextRange(start + replaceLength, 1).charAt(0); + if (after == '\n') return false; + } + } + } + return true; +} +/** + * Calculates the indexes of each line of text in the given range. + *
+ * + * @param offset the logical start offset of the text lineate + * @param length the length of the text to lineate, includes gap + * @param numLines the number of lines to initially allocate for the line index array, + * passed in for efficiency (the exact number of lines may be known) + * @return a line indexes array where each line is identified by a start offset and + * a length + */ +int[][] indexLines(int offset, int length, int numLines){ + int[][] indexedLines = new int[numLines][2]; + int start = 0; + int lineCount = 0; + int i; + replaceExpandExp = 1; + for (i = start; i < length; i++) { + int location = i + offset; + if ((location >= gapStart) && (location < gapEnd)) { + // ignore the gap + } else { + char ch = textStore[location]; + if (ch == SWT.CR) { + // see if the next character is a LF + if (location+1 < textStore.length) { + ch = textStore[location+1]; + if (ch == SWT.LF) { + i++; + } + } + indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount); + lineCount++; + start = i + 1; + } else if (ch == SWT.LF) { + indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount); + lineCount++; + start = i + 1; + } + } + } + int[][] newLines = new int[lineCount+1][2]; + System.arraycopy(indexedLines, 0, newLines, 0, lineCount); + int[] range = new int[] {start, i - start}; + newLines[lineCount] = range; + return newLines; +} +/** + * Inserts text. + *
+ * + * @param position the position at which to insert the text + * @param text the text to insert + */ +void insert(int position, String text) { + if (text.length() == 0) return; + + int startLine = getLineAtOffset(position); + int change = text.length(); + boolean endInsert = position == getCharCount(); + adjustGap(position, change, startLine); + + // during an insert the gap will be adjusted to start at + // position and it will be associated with startline, the + // inserted text will be placed in the gap + int startLineOffset = getOffsetAtLine(startLine); + // at this point, startLineLength will include the start line + // and all of the newly inserted text + int startLineLength = getPhysicalLine(startLine).length(); + + if (change > 0) { + // shrink gap + gapStart += (change); + for (int i = 0; i < text.length(); i++) { + textStore[position + i]= text.charAt(i); + } + } + + // figure out the number of new lines that have been inserted + int [][] newLines = indexLines(startLineOffset, startLineLength, 10); + // only insert an empty line if it is the last line in the text + int numNewLines = newLines.length - 1; + if (newLines[numNewLines][1] == 0) { + // last inserted line is a new line + if (endInsert) { + // insert happening at end of the text, leave numNewLines as + // is since the last new line will not be concatenated with another + // line + numNewLines += 1; + } else { + numNewLines -= 1; + } + } + + // make room for the new lines + expandLinesBy(numNewLines); + // shift down the lines after the replace line + for (int i = lineCount - 1; i > startLine; i--) { + lines[i + numNewLines]=lines[i]; + } + // insert the new lines + for (int i = 0; i < numNewLines; i++) { + newLines[i][0] += startLineOffset; + lines[startLine + i]=newLines[i]; + } + // update the last inserted line + if (numNewLines < newLines.length) { + newLines[numNewLines][0] += startLineOffset; + lines[startLine + numNewLines] = newLines[numNewLines]; + } + + lineCount += numNewLines; + gapLine = getLineAtPhysicalOffset(gapStart); +} +/** + * Moves the gap and adjusts its size in anticipation of a text change. + * The gap is resized to actual size + the specified size and moved to the given + * position. + *
+ * + * @param position the position at which a change is occurring + * @param size the size of the change + * @param newGapLine the line where the gap should be put + */ +void moveAndResizeGap(int position, int size, int newGapLine) { + char[] content = null; + int oldSize = gapEnd - gapStart; + int newSize; + if (size > 0) { + newSize = highWatermark + size; + } else { + newSize = lowWatermark - size; + } + // remove the old gap from the lines information + if (gapExists()) { + // adjust the line length + lines[gapLine][1] = lines[gapLine][1] - oldSize; + // adjust the offsets of the lines after the gapLine + for (int i = gapLine + 1; i < lineCount; i++) { + lines[i][0] = lines[i][0] - oldSize; + } + } + + if (newSize < 0) { + if (oldSize > 0) { + // removing the gap + content = new char[textStore.length - oldSize]; + System.arraycopy(textStore, 0, content, 0, gapStart); + System.arraycopy(textStore, gapEnd, content, gapStart, content.length - gapStart); + textStore = content; + } + gapStart = gapEnd = position; + return; + } + content = new char[textStore.length + (newSize - oldSize)]; + int newGapStart = position; + int newGapEnd = newGapStart + newSize; + if (oldSize == 0) { + System.arraycopy(textStore, 0, content, 0, newGapStart); + System.arraycopy(textStore, newGapStart, content, newGapEnd, content.length - newGapEnd); + } else if (newGapStart < gapStart) { + int delta = gapStart - newGapStart; + System.arraycopy(textStore, 0, content, 0, newGapStart); + System.arraycopy(textStore, newGapStart, content, newGapEnd, delta); + System.arraycopy(textStore, gapEnd, content, newGapEnd + delta, textStore.length - gapEnd); + } else { + int delta = newGapStart - gapStart; + System.arraycopy(textStore, 0, content, 0, gapStart); + System.arraycopy(textStore, gapEnd, content, gapStart, delta); + System.arraycopy(textStore, gapEnd + delta, content, newGapEnd, content.length - newGapEnd); + } + textStore = content; + gapStart = newGapStart; + gapEnd = newGapEnd; + + // add the new gap to the lines information + if (gapExists()) { + gapLine = newGapLine; + // adjust the line length + int gapLength = gapEnd - gapStart; + lines[gapLine][1] = lines[gapLine][1] + (gapLength); + // adjust the offsets of the lines after the gapLine + for (int i = gapLine + 1; i < lineCount; i++) { + lines[i][0] = lines[i][0] + gapLength; + } + } +} +/** + * Returns the number of lines that are in the specified text. + *
+ * + * @param startOffset the start of the text to lineate + * @param length the length of the text to lineate + * @return number of lines + */ +int lineCount(int startOffset, int length){ + if (length == 0) { + return 0; + } + int lineCount = 0; + int count = 0; + int i = startOffset; + if (i >= gapStart) { + i += gapEnd - gapStart; + } + while (count < length) { + if ((i >= gapStart) && (i < gapEnd)) { + // ignore the gap + } else { + char ch = textStore[i]; + if (ch == SWT.CR) { + // see if the next character is a LF + if (i + 1 < textStore.length) { + ch = textStore[i+1]; + if (ch == SWT.LF) { + i++; + count++; + } + } + lineCount++; + } else if (ch == SWT.LF) { + lineCount++; + } + count++; + } + i++; + } + return lineCount; +} +/** + * Returns the number of lines that are in the specified text. + *
+ *
+ * @param text the text to lineate
+ * @return number of lines in the text
+ */
+int lineCount(String text){
+ int lineCount = 0;
+ int length = text.length();
+ for (int i = 0; i < length; i++) {
+ char ch = text.charAt(i);
+ if (ch == SWT.CR) {
+ if (i + 1 < length && text.charAt(i + 1) == SWT.LF) {
+ i++;
+ }
+ lineCount++;
+ } else if (ch == SWT.LF) {
+ lineCount++;
+ }
+ }
+ return lineCount;
+}
+/**
+ * @return the logical length of the text store
+ */
+@Override
+public int getCharCount() {
+ int length = gapEnd - gapStart;
+ return (textStore.length - length);
+}
+/**
+ * Returns the line at index
without delimiters.
+ *
+ * + * @param index the index of the line to return + * @return the logical line text (i.e., without the gap) + * @exception IllegalArgumentException
StyledTextContent
interface.
+ * + * + * @return the platform line delimiter as specified in the line.separator + * system property. + */ +@Override +public String getLineDelimiter() { + return LineDelimiter; +} +/** + * Returns the line at the given index with delimiters. + *
+ * @param index the index of the line to return + * @return the logical line text (i.e., without the gap) with delimiters + */ +String getFullLine(int index) { + int start = lines[index][0]; + int length = lines[index][1]; + int end = start + length - 1; + if (!gapExists() || (end < gapStart) || (start >= gapEnd)) { + // line is before or after the gap + return new String(textStore, start, length); + } else { + // gap is in the specified range, strip out the gap + StringBuilder buffer = new StringBuilder(); + int gapLength = gapEnd - gapStart; + buffer.append(textStore, start, gapStart - start); + buffer.append(textStore, gapEnd, length - gapLength - (gapStart - start)); + return buffer.toString(); + } +} +/** + * Returns the physical line at the given index (i.e., with delimiters and the gap). + *
+ * + * @param index the line index + * @return the physical line + */ +String getPhysicalLine(int index) { + int start = lines[index][0]; + int length = lines[index][1]; + return getPhysicalText(start, length); +} +/** + * @return the number of lines in the text store + */ +@Override +public int getLineCount(){ + return lineCount; +} +/** + * Returns the line at the given offset. + *
+ * + * @param charPosition logical character offset (i.e., does not include gap) + * @return the line index + * @exception IllegalArgumentException
+ * + * @param position physical character offset (i.e., includes gap) + * @return the line index + */ +int getLineAtPhysicalOffset(int position){ + int high = lineCount; + int low = -1; + int index = lineCount; + while (high - low > 1) { + index = (high + low) / 2; + int lineStart = lines[index][0]; + int lineEnd = lineStart + lines[index][1] - 1; + if (position <= lineStart) { + high = index; + } else if (position <= lineEnd) { + high = index; + break; + } else { + low = index; + } + } + return high; +} +/** + * Returns the logical offset of the given line. + *
+ * + * @param lineIndex index of line + * @return the logical starting offset of the line. When there are not any lines, + * getOffsetAtLine(0) is a valid call that should answer 0. + * @exception IllegalArgumentException
+ * + * @param numLines the number to increase the array by + */ +void expandLinesBy(int numLines) { + int size = lines.length; + if (size - lineCount >= numLines) { + return; + } + int[][] newLines = new int[size+Math.max(10, numLines)][2]; + System.arraycopy(lines, 0, newLines, 0, size); + lines = newLines; +} +/** + * Reports an SWT error. + *
+ * + * @param code the error code + */ +void error (int code) { + SWT.error(code); +} +/** + * Returns whether or not a gap exists in the text store. + *
+ * + * @return true if gap exists, false otherwise + */ +boolean gapExists() { + return gapStart != gapEnd; +} +/** + * Returns a string representing the continuous content of + * the text store. + *
+ * + * @param start the physical start offset of the text to return + * @param length the physical length of the text to return + * @return the text + */ +String getPhysicalText(int start, int length) { + return new String(textStore, start, length); +} +/** + * Returns a string representing the logical content of + * the text store (i.e., gap stripped out). + *
+ *
+ * @param start the logical start offset of the text to return
+ * @param length the logical length of the text to return
+ * @return the text
+ */
+@Override
+public String getTextRange(int start, int length) {
+ if (textStore == null)
+ return "";
+ if (length == 0)
+ return "";
+ int end= start + length;
+ if (!gapExists() || (end < gapStart))
+ return new String(textStore, start, length);
+ if (gapStart < start) {
+ int gapLength= gapEnd - gapStart;
+ return new String(textStore, start + gapLength , length);
+ }
+ StringBuilder buf = new StringBuilder();
+ buf.append(textStore, start, gapStart - start);
+ buf.append(textStore, gapEnd, end - gapStart);
+ return buf.toString();
+}
+/**
+ * Removes the specified TextChangeListener
.
+ *
+ * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException
newText
starting at position start
+ * for a length of replaceLength
. Notifies the appropriate listeners.
+ *
+ *
+ * When sending the TextChangingEvent, newLineCount
is the number of
+ * lines that are going to be inserted and replaceLineCount
is
+ * the number of lines that are going to be deleted, based on the change
+ * that occurs visually. For example:
+ *
+ * + * @param text the text + */ +@Override +public void setText (String text){ + textStore = text.toCharArray(); + gapStart = -1; + gapEnd = -1; + expandExp = 1; + indexLines(); + StyledTextEvent event = new StyledTextEvent(this); + event.type = ST.TextSet; + event.text = ""; + sendTextEvent(event); +} +/** + * Deletes text. + *
+ * @param position the position at which the text to delete starts + * @param length the length of the text to delete + * @param numLines the number of lines that are being deleted + */ +void delete(int position, int length, int numLines) { + if (length == 0) return; + + int startLine = getLineAtOffset(position); + int startLineOffset = getOffsetAtLine(startLine); + int endLine = getLineAtOffset(position + length); + + String endText = ""; + boolean splittingDelimiter = false; + if (position + length < getCharCount()) { + endText = getTextRange(position + length - 1, 2); + if ((endText.charAt(0) == SWT.CR) && (endText.charAt(1) == SWT.LF)) { + splittingDelimiter = true; + } + } + + adjustGap(position + length, -length, startLine); + int [][] oldLines = indexLines(position, length + (gapEnd - gapStart), numLines); + + // enlarge the gap - the gap can be enlarged either to the + // right or left + if (position + length == gapStart) { + gapStart -= length; + } else { + gapEnd += length; + } + + // figure out the length of the new concatenated line, do so by + // finding the first line delimiter after position + int j = position; + boolean eol = false; + while (j < textStore.length && !eol) { + if (j < gapStart || j >= gapEnd) { + char ch = textStore[j]; + if (isDelimiter(ch)) { + if (j + 1 < textStore.length) { + if (ch == SWT.CR && (textStore[j+1] == SWT.LF)) { + j++; + } + } + eol = true; + } + } + j++; + } + // update the line where the deletion started + lines[startLine][1] = (position - startLineOffset) + (j - position); + // figure out the number of lines that have been deleted + int numOldLines = oldLines.length - 1; + if (splittingDelimiter) numOldLines -= 1; + // shift up the lines after the last deleted line, no need to update + // the offset or length of the lines + for (int i = endLine + 1; i < lineCount; i++) { + lines[i - numOldLines] = lines[i]; + } + lineCount -= numOldLines; + gapLine = getLineAtPhysicalOffset(gapStart); +} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ExtendedModifyEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ExtendedModifyEvent.java new file mode 100644 index 000000000..1b7c1ab3b --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ExtendedModifyEvent.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.custom; + +import org.eclipse.swt.events.*; + +/** + * This event is sent after a text change occurs. + * + * @see Sample code and further information + */ +public final class ExtendedModifyEvent extends TypedEvent { + /** start offset of the new text */ + public int start; + /** length of the new text */ + public int length; + /** replaced text or empty string if no text was replaced */ + public String replacedText; + + static final long serialVersionUID = 3258696507027830832L; + +/** + * Constructs a new instance of this class based on the + * information in the given event. + * + * @param e the event containing the information + */ +public ExtendedModifyEvent(StyledTextEvent e) { + super(e); + start = e.start; + length = e.end - e.start; + replacedText = e.text; +} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ExtendedModifyListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ExtendedModifyListener.java new file mode 100644 index 000000000..3652482bc --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ExtendedModifyListener.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.custom; + +import org.eclipse.swt.internal.*; + +/** + * Classes which implement this interface provide a method + * that deals with the event that is generated when text + * is modified. + * + * @see ExtendedModifyEvent + * @see Sample code and further information + */ +@FunctionalInterface +public interface ExtendedModifyListener extends SWTEventListener { + +/** + * This method is called after a text change occurs. + *
+ * The following event fields are used:
+ * The following event fields are used:
ranges
can be used to share
+ * styles and reduce memory usage.
+ */
+ public StyleRange[] styles;
+
+ /**
+ * line alignment (input, output)
+ *
+ * @since 3.2
+ */
+ public int alignment;
+
+ /**
+ * line indent (input, output)
+ *
+ * @since 3.2
+ */
+ public int indent;
+
+ /**
+ * line vertical indent (input, output)
+ *
+ * @since 3.109
+ */
+ int verticalIndent;
+
+ /**
+ * line wrap indent (input, output)
+ *
+ * @since 3.6
+ */
+ public int wrapIndent;
+
+ /**
+ * line justification (input, output)
+ *
+ * @since 3.2
+ */
+ public boolean justify;
+
+ /**
+ * line bullet (output)
+ * @since 3.2
+ */
+ public Bullet bullet;
+
+ /**
+ * line bullet index (output)
+ * @since 3.2
+ */
+ public int bulletIndex;
+
+ /**
+ * line tab stops (output)
+ * @since 3.6
+ */
+ public int[] tabStops;
+
+
+ static final long serialVersionUID = 3906081274027192884L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given event.
+ *
+ * @param e the event containing the information
+ */
+public LineStyleEvent(StyledTextEvent e) {
+ super(e);
+ styles = e.styles;
+ ranges = e.ranges;
+ lineOffset = e.detail;
+ lineText = e.text;
+ alignment = e.alignment;
+ justify = e.justify;
+ indent = e.indent;
+ verticalIndent = e.verticalIndent;
+ wrapIndent = e.wrapIndent;
+ bullet = e.bullet;
+ bulletIndex = e.bulletIndex;
+ tabStops = e.tabStops;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/LineStyleListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/LineStyleListener.java
new file mode 100644
index 000000000..8e2797986
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/LineStyleListener.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * Classes which implement this interface provide a method
+ * that can provide the style information for a line that
+ * is to be drawn.
+ *
+ * @see LineStyleEvent
+ * @see Sample code and further information
+ */
+@FunctionalInterface
+public interface LineStyleListener extends SWTEventListener {
+
+/**
+ * This method is called when a line is about to be drawn in order to get the
+ * line's style information.
+ * + * The following event fields are used:
StyledText
widgets:
+ * + * When the user clicks on the wheel, a circle with arrows appears. When the user moves the mouse, + * the StyledText content is scrolled (on the right or on the left for horizontal movements, up or down for vertical movements). + *
+ * + * @since 3.110 + */ +class MouseNavigator { + private final StyledText parent; + boolean navigationActivated = false; + private GC gc; + private static final int CIRCLE_RADIUS = 15; + private static final int CENTRAL_POINT_RADIUS = 2; + private Point originalMouseLocation; + private final Listener mouseDownListener, mouseUpListener, paintListener, mouseMoveListener, focusOutListener; + private boolean hasHBar, hasVBar; + private Cursor previousCursor; + + MouseNavigator(final StyledText styledText) { + if (styledText == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (styledText.isDisposed()) { + SWT.error(SWT.ERROR_WIDGET_DISPOSED); + } + parent = styledText; + + mouseDownListener = (event) -> { + onMouseDown(event); + }; + parent.addListener(SWT.MouseDown, mouseDownListener); + + mouseUpListener = (event) -> { + onMouseUp(event); + }; + parent.addListener(SWT.MouseUp, mouseUpListener); + + paintListener = (event) -> { + onPaint(event); + }; + parent.addListener(SWT.Paint, paintListener); + + mouseMoveListener = (event) -> { + onMouseMove(event); + }; + parent.addListener(SWT.MouseMove, mouseMoveListener); + + focusOutListener = (event) -> { + onFocusOut(event); + }; + parent.addListener(SWT.FocusOut, focusOutListener); + } + + void onMouseDown(Event e) { + if ((e.button != 2) || navigationActivated) { + return; + } + + if (!parent.isVisible() || !parent.getEnabled() || parent.middleClickPressed) { + return; + } + + // Widget has no bar or bars are not enabled + initBarState(); + + if (!hasHBar && !hasVBar) { + return; + } + + navigationActivated = true; + previousCursor = parent.getCursor(); + parent.setCursor(parent.getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); + originalMouseLocation = getMouseLocation(); + parent.redraw(); + } + + private void initBarState() { + hasHBar = computeHasHorizontalBar(); + hasVBar = computeHasVerticalBar(); + } + + private boolean computeHasHorizontalBar() { + final ScrollBar horizontalBar = parent.getHorizontalBar(); + final boolean hasHorizontalBar = horizontalBar != null && horizontalBar.isVisible(); + final boolean exceedHorizontalSpace = parent.computeSize(SWT.DEFAULT, SWT.DEFAULT).x > parent.getSize().x; + return hasHorizontalBar && exceedHorizontalSpace; + } + + private boolean computeHasVerticalBar() { + final ScrollBar verticalBar = parent.getVerticalBar(); + final boolean hasVerticalBar = verticalBar != null && verticalBar.isEnabled(); + final boolean exceedVerticalSpace = parent.computeSize(SWT.DEFAULT, SWT.DEFAULT).y > parent.getSize().y; + return hasVerticalBar && exceedVerticalSpace; + } + + private void onMouseUp(Event e) { + if ((computeDist() < CIRCLE_RADIUS) && (computeDist() >= 0)) { + return; + } + deactivate(); + } + + public int computeDist() { + if (originalMouseLocation == null) { + return -1; + } + final Point mouseLocation = getMouseLocation(); + final int deltaX = originalMouseLocation.x - mouseLocation.x; + final int deltaY = originalMouseLocation.y - mouseLocation.y; + final int dist = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY); + return dist; + } + + private void deactivate() { + parent.setCursor(previousCursor); + navigationActivated = false; + originalMouseLocation = null; + parent.redraw(); + } + + private void onFocusOut(Event e) { + deactivate(); + } + + private void onMouseMove(Event e) { + if (!navigationActivated) { + return; + } + + final Point mouseLocation = getMouseLocation(); + final int deltaX = originalMouseLocation.x - mouseLocation.x; + final int deltaY = originalMouseLocation.y - mouseLocation.y; + final int dist = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY); + if (dist < CIRCLE_RADIUS) { + return; + } + + parent.setRedraw(false); + if (hasHBar) { + final ScrollBar bar = parent.getHorizontalBar(); + bar.setSelection((int) (bar.getSelection() - deltaX * .1)); + fireSelectionEvent(e, bar); + } + + if (hasVBar) { + final ScrollBar bar = parent.getVerticalBar(); + bar.setSelection((int) (bar.getSelection() - deltaY * .1)); + fireSelectionEvent(e, bar); + } + parent.setRedraw(true); + parent.redraw(); + } + + private void fireSelectionEvent(final Event e, final ScrollBar bar) { + final Event event = new Event(); + event.widget = bar; + event.display = parent.getDisplay(); + event.type = SWT.Selection; + event.time = e.time; + + for (final Listener selectionListener : bar.getListeners(SWT.Selection)) { + selectionListener.handleEvent(event); + } + } + + private Point getMouseLocation() { + final Point cursorLocation = Display.getCurrent().getCursorLocation(); + final Point relativeCursorLocation = parent.toControl(cursorLocation); + return relativeCursorLocation; + } + + private void onPaint(final Event e) { + if (!navigationActivated) { + return; + } + + final Rectangle rect = parent.getClientArea(); + if (rect.width == 0 || rect.height == 0) { + return; + } + gc = e.gc; + gc.setAntialias(SWT.ON); + gc.setAdvanced(true); + + final Color oldForegroundColor = gc.getForeground(); + final Color oldBackgroundColor = gc.getBackground(); + gc.setBackground(parent.getForeground()); + + drawCircle(); + drawCentralPoint(); + + drawArrows(); + + gc.setForeground(oldForegroundColor); + gc.setBackground(oldBackgroundColor); + } + + private void drawCircle() { + gc.setBackground(parent.getBackground()); + gc.setForeground(parent.getForeground()); + gc.setAlpha(200); + gc.fillOval(originalMouseLocation.x - CIRCLE_RADIUS, originalMouseLocation.y - CIRCLE_RADIUS, CIRCLE_RADIUS * 2, CIRCLE_RADIUS * 2); + gc.setBackground(parent.getForeground()); + gc.setAlpha(255); + gc.drawOval(originalMouseLocation.x - CIRCLE_RADIUS, originalMouseLocation.y - CIRCLE_RADIUS, CIRCLE_RADIUS * 2, CIRCLE_RADIUS * 2); + } + + private void drawCentralPoint() { + gc.fillOval(originalMouseLocation.x - CENTRAL_POINT_RADIUS, originalMouseLocation.y - CENTRAL_POINT_RADIUS, CENTRAL_POINT_RADIUS * 2, CENTRAL_POINT_RADIUS * 2); + } + + private void drawArrows() { + gc.setLineWidth(2); + if (hasHBar) { + drawHorizontalArrows(); + } + if (hasVBar) { + drawVerticalArrows(); + } + } + + private void drawHorizontalArrows() { + final int[] points = new int[6]; + // Left + points[0] = originalMouseLocation.x - 6; + points[1] = originalMouseLocation.y + 3; + points[2] = originalMouseLocation.x - 9; + points[3] = originalMouseLocation.y; + points[4] = originalMouseLocation.x - 6; + points[5] = originalMouseLocation.y - 3; + gc.drawPolyline(points); + + // Right + points[0] = originalMouseLocation.x + 7; + points[1] = originalMouseLocation.y + 3; + points[2] = originalMouseLocation.x + 10; + points[3] = originalMouseLocation.y; + points[4] = originalMouseLocation.x + 7; + points[5] = originalMouseLocation.y - 3; + gc.drawPolyline(points); + } + + private void drawVerticalArrows() { + final int[] points = new int[6]; + // Upper + points[0] = originalMouseLocation.x - 3; + points[1] = originalMouseLocation.y - 6; + points[2] = originalMouseLocation.x; + points[3] = originalMouseLocation.y - 10; + points[4] = originalMouseLocation.x + 3; + points[5] = originalMouseLocation.y - 6; + gc.drawPolyline(points); + + // Lower + points[0] = originalMouseLocation.x - 3; + points[1] = originalMouseLocation.y + 7; + points[2] = originalMouseLocation.x; + points[3] = originalMouseLocation.y + 11; + points[4] = originalMouseLocation.x + 3; + points[5] = originalMouseLocation.y + 7; + gc.drawPolyline(points); + + } + + void dispose() { + if (parent.isDisposed()) { + return; + } + parent.removeListener(SWT.MouseDown, mouseDownListener); + parent.removeListener(SWT.MouseUp, mouseUpListener); + parent.removeListener(SWT.Paint, paintListener); + parent.removeListener(SWT.MouseMove, mouseMoveListener); + parent.removeListener(SWT.MouseExit, focusOutListener); + } +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/MovementEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/MovementEvent.java new file mode 100644 index 000000000..ccc0dafb2 --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/MovementEvent.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.custom; + +import org.eclipse.swt.events.*; + +/** + * This event is sent when a new offset is required based on the current + * offset and a movement type. + * + * @see Sample code and further information + * + * @since 3.3 + */ +public class MovementEvent extends TypedEvent { + + /** + * line start offset (input) + */ + public int lineOffset; + + /** + * line text (input) + */ + public String lineText; + + /** + * the current offset (input) + */ + public int offset; + + /** + * the new offset (input, output) + */ + public int newOffset; + + /** + * the movement type (input) + * + * @see org.eclipse.swt.SWT#MOVEMENT_WORD + * @see org.eclipse.swt.SWT#MOVEMENT_WORD_END + * @see org.eclipse.swt.SWT#MOVEMENT_WORD_START + * @see org.eclipse.swt.SWT#MOVEMENT_CHAR + * @see org.eclipse.swt.SWT#MOVEMENT_CLUSTER + */ + public int movement; + + static final long serialVersionUID = 3978765487853324342L; + +/** + * Constructs a new instance of this class based on the + * information in the given event. + * + * @param e the event containing the information + */ +public MovementEvent(StyledTextEvent e) { + super(e); + lineOffset = e.detail; + lineText = e.text; + movement = e.count; + offset = e.start; + newOffset = e.end; +} +} + + diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/MovementListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/MovementListener.java new file mode 100644 index 000000000..6fcb0f73c --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/MovementListener.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.custom; + +import org.eclipse.swt.internal.SWTEventListener; + +/** + * This listener is invoked when a new offset is required based on the current + * offset and a movement type. + * + * @see org.eclipse.swt.SWT#MOVEMENT_WORD + * @see org.eclipse.swt.SWT#MOVEMENT_WORD_END + * @see org.eclipse.swt.SWT#MOVEMENT_WORD_START + * @see org.eclipse.swt.SWT#MOVEMENT_CHAR + * @see org.eclipse.swt.SWT#MOVEMENT_CLUSTER + * + * @since 3.3 + */ +public interface MovementListener extends SWTEventListener { +/** + * This method is called when a new offset is required based on the current + * offset and a movement type. + * + *+ * The following event fields are used:
+ * The following event fields are used:
+ * The following event fields are used:
+* @return the widget font +* +* @exception SWTException
+* This operation will fail if the items cannot +* be queried from the OS. +* +* @return the items in the widget +* +* @exception SWTException
+* If the item is not currently selected, it is selected. +* If the item at an index is selected, it remains selected. +* If the string is not matched, it is ignored. +* +* @param string the text of the item +* +* @exception SWTException
+* When new font is null, the font reverts +* to the default system font for the widget. +* +* @param font the new font (or null) +* +* @exception SWTException
+* The previous selection is cleared. +* The previous items are deleted. +* The new items are added. +* The top index is set to 0. +* +* @param strings the array of items +* +* This operation will fail when an item is null +* or could not be added in the OS. +* +* @exception IllegalArgumentException
StyledText
.
+ *
+ * @see Sample code and further information
+ */
+public class ST {
+
+ /*
+ * Navigation Key Actions. Key bindings for the actions are set
+ * by the StyledText widget.
+ */
+ public static final int LINE_UP = 16777217; // binding = SWT.ARROW_UP
+ public static final int LINE_DOWN = 16777218; // binding = SWT.ARROW_DOWN
+ public static final int LINE_START = 16777223; // binding = SWT.HOME
+ public static final int LINE_END = 16777224; // binding = SWT.END
+ public static final int COLUMN_PREVIOUS = 16777219; // binding = SWT.ARROW_LEFT
+ public static final int COLUMN_NEXT = 16777220; // binding = SWT.ARROW_RIGHT
+ public static final int PAGE_UP = 16777221; // binding = SWT.PAGE_UP
+ public static final int PAGE_DOWN = 16777222; // binding = SWT.PAGE_DOWN
+ public static final int WORD_PREVIOUS = 17039363; // binding = SWT.MOD1 + SWT.ARROW_LEFT
+ public static final int WORD_NEXT = 17039364; // binding = SWT.MOD1 + SWT.ARROW_RIGHT
+ public static final int TEXT_START = 17039367; // binding = SWT.MOD1 + SWT.HOME
+ public static final int TEXT_END = 17039368; // binding = SWT.MOD1 + SWT.END
+ public static final int WINDOW_START = 17039365; // binding = SWT.MOD1 + SWT.PAGE_UP
+ public static final int WINDOW_END = 17039366; // binding = SWT.MOD1 + SWT.PAGE_DOWN
+
+ /*
+ * Selection Key Actions
+ */
+ public static final int SELECT_ALL = 262209; // binding = SWT.MOD1 + 'A'
+ public static final int SELECT_LINE_UP = 16908289; // binding = SWT.MOD2 + SWT.ARROW_UP
+ public static final int SELECT_LINE_DOWN = 16908290; // binding = SWT.MOD2 + SWT.ARROW_DOWN
+ public static final int SELECT_LINE_START = 16908295; // binding = SWT.MOD2 + SWT.HOME
+ public static final int SELECT_LINE_END = 16908296; // binding = SWT.MOD2 + SWT.END
+ public static final int SELECT_COLUMN_PREVIOUS = 16908291; // binding = SWT.MOD2 + SWT.ARROW_LEFT
+ public static final int SELECT_COLUMN_NEXT = 16908292; // binding = SWT.MOD2 + SWT.ARROW_RIGHT
+ public static final int SELECT_PAGE_UP = 16908293; // binding = SWT.MOD2 + SWT.PAGE_UP
+ public static final int SELECT_PAGE_DOWN = 16908294; // binding = SWT.MOD2 + SWT.PAGE_DOWN
+ public static final int SELECT_WORD_PREVIOUS = 17170435; // binding = SWT.MOD1 + SWT.MOD2 + SWT.ARROW_LEFT
+ public static final int SELECT_WORD_NEXT = 17170436; // binding = SWT.MOD1 + SWT.MOD2 + SWT.ARROW_RIGHT
+ public static final int SELECT_TEXT_START = 17170439; // binding = SWT.MOD1 + SWT.MOD2 + SWT.HOME
+ public static final int SELECT_TEXT_END = 17170440; // binding = SWT.MOD1 + SWT.MOD2 + SWT.END
+ public static final int SELECT_WINDOW_START = 17170437; // binding = SWT.MOD1 + SWT.MOD2 + SWT.PAGE_UP
+ public static final int SELECT_WINDOW_END = 17170438; // binding = SWT.MOD1 + SWT.MOD2 + SWT.PAGE_DOWN
+
+ /*
+ * Modification Key Actions
+ */
+ public static final int CUT = 131199; // binding = SWT.MOD2 + SWT.DEL
+ public static final int COPY = 17039369; // binding = SWT.MOD1 + SWT.INSERT;
+ public static final int PASTE = 16908297; // binding = SWT.MOD2 + SWT.INSERT ;
+ public static final int DELETE_PREVIOUS = '\b'; // binding = SWT.BS;
+ public static final int DELETE_NEXT = 0x7F; // binding = SWT.DEL;
+ public static final int DELETE_WORD_PREVIOUS = 262152; // binding = SWT.BS | SWT.MOD1;
+ public static final int DELETE_WORD_NEXT = 262271; // binding = SWT.DEL | SWT.MOD1;
+
+ /*
+ * Miscellaneous Key Actions
+ */
+ public static final int TOGGLE_OVERWRITE = 16777225; // binding = SWT.INSERT;
+
+ /**
+ * TEMPORARY CODE - API SUBJECT TO CHANGE
+ *
+ * Toggle block selection mode
+ *
+ * @since 3.5
+ */
+ public static final int TOGGLE_BLOCKSELECTION = 16777226;
+
+ /**
+ * Bullet style dot.
+ *
+ * @see Bullet
+ *
+ * @since 3.2
+ */
+ public static final int BULLET_DOT = 1 << 0;
+
+ /**
+ * Bullet style number.
+ *
+ * @see Bullet
+ *
+ * @since 3.2
+ */
+ public static final int BULLET_NUMBER = 1 << 1;
+
+ /**
+ * Bullet style lower case letter.
+ *
+ * @see Bullet
+ *
+ * @since 3.2
+ */
+ public static final int BULLET_LETTER_LOWER = 1 << 2;
+
+ /**
+ * Bullet style upper case letter.
+ *
+ * @see Bullet
+ *
+ * @since 3.2
+ */
+ public static final int BULLET_LETTER_UPPER = 1 << 3;
+
+ /**
+ * Bullet style text.
+ *
+ * @see Bullet
+ *
+ * @since 3.2
+ */
+ public static final int BULLET_TEXT = 1 << 4;
+
+ /**
+ * Bullet style custom draw.
+ *
+ * @see StyledText#addPaintObjectListener(PaintObjectListener)
+ * @see StyledText#removePaintObjectListener(PaintObjectListener)
+ * @see Bullet
+ *
+ * @since 3.2
+ */
+ public static final int BULLET_CUSTOM = 1 << 5;
+
+ /**
+ * The ExtendedModify event type (value is 3000).
+ *
+ * @since 3.8
+ */
+ public static final int ExtendedModify = 3000;
+
+ /**
+ * The LineGetBackground event type (value is 3001).
+ *
+ * @since 3.8
+ */
+ public static final int LineGetBackground = 3001;
+
+ /**
+ * The LineGetStyle event type (value is 3002).
+ *
+ * @since 3.8
+ */
+ public static final int LineGetStyle = 3002;
+
+ /**
+ * The TextChanging event type (value is 3003).
+ *
+ * @since 3.8
+ */
+ public static final int TextChanging = 3003;
+
+ /**
+ * The TextSet event type (value is 3004).
+ *
+ * @since 3.8
+ */
+ public static final int TextSet = 3004;
+
+ /**
+ * The VerifyKey event type (value is 3005).
+ *
+ * @since 3.8
+ */
+ public static final int VerifyKey = 3005;
+
+ /**
+ * The TextChanged event type (value is 3006).
+ *
+ * @since 3.8
+ */
+ public static final int TextChanged = 3006;
+
+ /**
+ * The LineGetSegments event type (value is 3007).
+ *
+ * @since 3.8
+ */
+ public static final int LineGetSegments = 3007;
+
+ /**
+ * The PaintObject event type (value is 3008).
+ *
+ * @since 3.8
+ */
+ public static final int PaintObject = 3008;
+
+ /**
+ * The WordNext event type (value is 3009).
+ *
+ * @since 3.8
+ */
+ public static final int WordNext = 3009;
+
+ /**
+ * The WordPrevious event type (value is 3010).
+ *
+ * @since 3.8
+ */
+ public static final int WordPrevious = 3010;
+
+ /**
+ * The CaretMoved event type (value is 3011).
+ *
+ * @since 3.8
+ */
+ public static final int CaretMoved = 3011;
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/SashForm.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/SashForm.java
new file mode 100644
index 000000000..90b067c63
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/SashForm.java
@@ -0,0 +1,474 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * The SashForm is a composite control that lays out its children in a
+ * row or column arrangement (as specified by the orientation) and places
+ * a Sash between each child. One child may be maximized to occupy the
+ * entire size of the SashForm. The relative sizes of the children may
+ * be specified using weights.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * To retrieve the bidi orientation of the SashForm use {@link #getStyle()}
+ * and test if the SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT bits are set.
+ *
+ * Since 3.7, this method can also be called with SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT + * to change the bidi orientation of the SashForm. + *
+ * + * @param orientation SWT.HORIZONTAL or SWT.VERTICAL, SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT + * + * @see Control#setOrientation(int) + * + * @exception SWTException+ * Note: No Layout can be set on this Control because it already + * manages the size and position of its children. + *
+ * + * @param layout the receiver's new layout or null + * + * @exception SWTExceptionThere are two ways to use the ScrolledComposite: + * + *
+ *
+ * public static void main (String [] args) {
+ * Display display = new Display ();
+ * Color red = display.getSystemColor(SWT.COLOR_RED);
+ * Color blue = display.getSystemColor(SWT.COLOR_BLUE);
+ * Shell shell = new Shell (display);
+ * shell.setLayout(new FillLayout());
+ *
+ * // set the size of the scrolled content - method 1
+ * final ScrolledComposite sc1 = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+ * final Composite c1 = new Composite(sc1, SWT.NONE);
+ * sc1.setContent(c1);
+ * c1.setBackground(red);
+ * GridLayout layout = new GridLayout();
+ * layout.numColumns = 4;
+ * c1.setLayout(layout);
+ * Button b1 = new Button (c1, SWT.PUSH);
+ * b1.setText("first button");
+ * c1.setSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ *
+ * // set the minimum width and height of the scrolled content - method 2
+ * final ScrolledComposite sc2 = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+ * sc2.setExpandHorizontal(true);
+ * sc2.setExpandVertical(true);
+ * final Composite c2 = new Composite(sc2, SWT.NONE);
+ * sc2.setContent(c2);
+ * c2.setBackground(blue);
+ * layout = new GridLayout();
+ * layout.numColumns = 4;
+ * c2.setLayout(layout);
+ * Button b2 = new Button (c2, SWT.PUSH);
+ * b2.setText("first button");
+ * sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ *
+ * Button add = new Button (shell, SWT.PUSH);
+ * add.setText("add children");
+ * final int[] index = new int[]{0};
+ * add.addListener(SWT.Selection, new Listener() {
+ * public void handleEvent(Event e) {
+ * index[0]++;
+ * Button button = new Button(c1, SWT.PUSH);
+ * button.setText("button "+index[0]);
+ * // reset size of content so children can be seen - method 1
+ * c1.setSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ * c1.layout();
+ *
+ * button = new Button(c2, SWT.PUSH);
+ * button.setText("button "+index[0]);
+ * // reset the minimum width and height so children can be seen - method 2
+ * sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ * c2.layout();
+ * }
+ * });
+ *
+ * shell.open ();
+ * while (!shell.isDisposed ()) {
+ * if (!display.readAndDispatch ()) display.sleep ();
+ * }
+ * display.dispose ();
+ * }
+ *
+ *
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
true
if the content control
+ * will be expanded to fill available horizontal space.
+ *
+ * @return the receiver's horizontal expansion state
+ *
+ * @exception SWTException true
if the content control
+ * will be expanded to fill available vertical space.
+ *
+ * @return the receiver's vertical expansion state
+ *
+ * @exception SWTException true
if the receiver automatically scrolls to a focused child control
+ * to make it visible. Otherwise, returns false
.
+ *
+ * @return a boolean indicating whether focused child controls are automatically scrolled into the viewport
+ *
+ * @exception SWTException + * Note: No Layout can be set on this Control because it already + * manages the size and position of its children. + *
+ * + * @param layout the receiver's new layout or null + * + * @exception SWTExceptionfalse
, show a focused control is off.
+ * By default, show a focused control is off.
+ *
+ * @param show true
to show a focused control.
+ *
+ * @exception SWTException Here is an example which places ten buttons in a stack layout and + * flips between them: + * + *
+ * public static void main(String[] args) {
+ * Display display = new Display();
+ * Shell shell = new Shell(display);
+ * shell.setLayout(new GridLayout());
+ *
+ * final Composite parent = new Composite(shell, SWT.NONE);
+ * parent.setLayoutData(new GridData(GridData.FILL_BOTH));
+ * final StackLayout layout = new StackLayout();
+ * parent.setLayout(layout);
+ * final Button[] bArray = new Button[10];
+ * for (int i = 0; i < 10; i++) {
+ * bArray[i] = new Button(parent, SWT.PUSH);
+ * bArray[i].setText("Button "+i);
+ * }
+ * layout.topControl = bArray[0];
+ *
+ * Button b = new Button(shell, SWT.PUSH);
+ * b.setText("Show Next Button");
+ * final int[] index = new int[1];
+ * b.addListener(SWT.Selection, new Listener(){
+ * public void handleEvent(Event e) {
+ * index[0] = (index[0] + 1) % 10;
+ * layout.topControl = bArray[index[0]];
+ * parent.layout();
+ * }
+ * });
+ *
+ * shell.open();
+ * while (shell != null && !shell.isDisposed()) {
+ * if (!display.readAndDispatch())
+ * display.sleep();
+ * }
+ * }
+ *
+ *
+ * @see StackLayout snippets
+ * @see SWT Example: LayoutExample
+ * @see Sample code and further information
+ */
+
+public class StackLayout extends Layout {
+
+ /**
+ * marginWidth specifies the number of points of horizontal margin
+ * that will be placed along the left and right edges of the layout.
+ *
+ * The default value is 0.
+ */
+ public int marginWidth = 0;
+ /**
+ * marginHeight specifies the number of points of vertical margin
+ * that will be placed along the top and bottom edges of the layout.
+ *
+ * The default value is 0.
+ */
+ public int marginHeight = 0;
+
+ /**
+ * topControl the Control that is displayed at the top of the stack.
+ * All other controls that are children of the parent composite will not be visible.
+ */
+ public Control topControl;
+
+@Override
+protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
+ Control children[] = composite.getChildren();
+ int maxWidth = 0;
+ int maxHeight = 0;
+ for (int i = 0; i < children.length; i++) {
+ Point size = children[i].computeSize(wHint, hHint, flushCache);
+ maxWidth = Math.max(size.x, maxWidth);
+ maxHeight = Math.max(size.y, maxHeight);
+ }
+ int width = maxWidth + 2 * marginWidth;
+ int height = maxHeight + 2 * marginHeight;
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ return new Point(width, height);
+}
+
+@Override
+protected boolean flushCache(Control control) {
+ return true;
+}
+
+@Override
+protected void layout(Composite composite, boolean flushCache) {
+ Control children[] = composite.getChildren();
+ Rectangle rect = composite.getClientArea();
+ rect.x += marginWidth;
+ rect.y += marginHeight;
+ rect.width -= 2 * marginWidth;
+ rect.height -= 2 * marginHeight;
+ for (int i = 0; i < children.length; i++) {
+ children[i].setBounds(rect);
+ children[i].setVisible(children[i] == topControl);
+ }
+}
+
+String getName () {
+ String string = getClass ().getName ();
+ int index = string.lastIndexOf ('.');
+ if (index == -1) return string;
+ return string.substring (index + 1, string.length ());
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the layout
+ */
+@Override
+public String toString () {
+ String string = getName ()+" {";
+ if (marginWidth != 0) string += "marginWidth="+marginWidth+" ";
+ if (marginHeight != 0) string += "marginHeight="+marginHeight+" ";
+ if (topControl != null) string += "topControl="+topControl+" ";
+ string = string.trim();
+ string += "}";
+ return string;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyleRange.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyleRange.java
new file mode 100644
index 000000000..0f8ca2179
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyleRange.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * StyleRange
defines a set of styles for a specified
+ * range of text.
+ * + * The hashCode() method in this class uses the values of the public + * fields to compute the hash value. When storing instances of the + * class in hashed collections, do not modify these fields after the + * object has been inserted. + *
+ * + * @see Sample code and further information + */ +public class StyleRange extends TextStyle implements Cloneable { + + /** + * the start offset of the range, zero-based from the document start + */ + public int start; + + /** + * the length of the range + */ + public int length; + + /** + * the font style of the range. It may be a combination of + * SWT.NORMAL, SWT.ITALIC or SWT.BOLD + * + * Note: the font style is not used if thefont
attribute
+ * is set
+ */
+ public int fontStyle = SWT.NORMAL;
+
+/**
+ * Create a new style range with no styles
+ *
+ * @since 3.2
+ */
+public StyleRange() {
+}
+
+/**
+ * Create a new style range from an existing text style.
+ *
+ * @param style the text style to copy
+ *
+ * @since 3.4
+ */
+public StyleRange(TextStyle style) {
+ super(style);
+}
+
+/**
+ * Create a new style range.
+ *
+ * @param start start offset of the style
+ * @param length length of the style
+ * @param foreground foreground color of the style, null if none
+ * @param background background color of the style, null if none
+ */
+public StyleRange(int start, int length, Color foreground, Color background) {
+ super(null, foreground, background);
+ this.start = start;
+ this.length = length;
+}
+
+/**
+ * Create a new style range.
+ *
+ * @param start start offset of the style
+ * @param length length of the style
+ * @param foreground foreground color of the style, null if none
+ * @param background background color of the style, null if none
+ * @param fontStyle font style of the style, may be SWT.NORMAL, SWT.ITALIC or SWT.BOLD
+ */
+public StyleRange(int start, int length, Color foreground, Color background, int fontStyle) {
+ this(start, length, foreground, background);
+ this.fontStyle = fontStyle;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the same object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals(Object object) {
+ if (object == this) return true;
+ if (object instanceof StyleRange) {
+ StyleRange style = (StyleRange)object;
+ if (start != style.start) return false;
+ if (length != style.length) return false;
+ return similarTo(style);
+ }
+ return false;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+@Override
+public int hashCode() {
+ return super.hashCode() ^ fontStyle;
+}
+boolean isVariableHeight() {
+ return font != null || (metrics != null && (metrics.ascent != 0 || metrics.descent != 0)) || rise != 0;
+}
+/**
+ * Returns whether or not the receiver is unstyled (i.e., does not have any
+ * style attributes specified).
+ *
+ * @return true if the receiver is unstyled, false otherwise.
+ */
+public boolean isUnstyled() {
+ if (font != null) return false;
+ if (rise != 0) return false;
+ if (metrics != null) return false;
+ if (foreground != null) return false;
+ if (background != null) return false;
+ if (fontStyle != SWT.NORMAL) return false;
+ if (underline) return false;
+ if (strikeout) return false;
+ if (borderStyle != SWT.NONE) return false;
+ return true;
+}
+
+/**
+ * Compares the specified object to this StyleRange and answer if the two
+ * are similar. The object must be an instance of StyleRange and have the
+ * same field values for except for start and length.
+ *
+ * @param style the object to compare with this object
+ * @return true if the objects are similar, false otherwise
+ */
+public boolean similarTo(StyleRange style) {
+ if (!super.equals(style)) return false;
+ if (fontStyle != style.fontStyle) return false;
+ return true;
+}
+
+/**
+ * Returns a new StyleRange with the same values as this StyleRange.
+ *
+ * @return a shallow copy of this StyleRange
+ */
+@Override
+public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the StyleRange
+ */
+@Override
+public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("StyleRange {");
+ buffer.append(start);
+ buffer.append(", ");
+ buffer.append(length);
+ buffer.append(", fontStyle=");
+ switch (fontStyle) {
+ case SWT.BOLD:
+ buffer.append("bold");
+ break;
+ case SWT.ITALIC:
+ buffer.append("italic");
+ break;
+ case SWT.BOLD | SWT.ITALIC:
+ buffer.append("bold-italic");
+ break;
+ default:
+ buffer.append("normal");
+ }
+ String str = super.toString();
+ int index = str.indexOf('{');
+ str = str.substring(index + 1);
+ if (str.length() > 1) buffer.append(", ");
+ buffer.append(str);
+ return buffer.toString();
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledText.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledText.java
new file mode 100644
index 000000000..61453a505
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledText.java
@@ -0,0 +1,10923 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Andrey Loskutov + * In addition to text style attributes, the background color of a line may + * be specified. + *
+ * There are two ways to use this widget when specifying text style information. + * You may use the API that is defined for StyledText or you may define your own + * LineStyleListener. If you define your own listener, you will be responsible + * for maintaining the text style information for the widget. IMPORTANT: You may + * not define your own listener and use the StyledText API. The following + * StyledText API is not supported if you have defined a LineStyleListener:
+ *+ * There are two ways to use this widget when specifying line background colors. + * You may use the API that is defined for StyledText or you may define your own + * LineBackgroundListener. If you define your own listener, you will be responsible + * for maintaining the line background color information for the widget. + * IMPORTANT: You may not define your own listener and use the StyledText API. + * The following StyledText API is not supported if you have defined a + * LineBackgroundListener:
+ *+ * The content implementation for this widget may also be user-defined. To do so, + * you must implement the StyledTextContent interface and use the StyledText API + * setContent(StyledTextContent) to initialize the widget. + *
+ *+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see StyledText snippets + * @see SWT Examples: CustomControlExample, TextEditor + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class StyledText extends Canvas { + static final char TAB = '\t'; + static final String PlatformLineDelimiter = System.getProperty("line.separator"); + static final int BIDI_CARET_WIDTH = 3; + static final int DEFAULT_WIDTH = 64; + static final int DEFAULT_HEIGHT = 64; + static final int V_SCROLL_RATE = 50; + static final int H_SCROLL_RATE = 10; + static final int PREVIOUS_OFFSET_TRAILING = 0; + static final int OFFSET_LEADING = 1; + + static final String STYLEDTEXT_KEY = "org.eclipse.swt.internal.cocoa.styledtext"; //$NON-NLS-1$ + + Color selectionBackground; // selection background color + Color selectionForeground; // selection foreground color + StyledTextContent content; // native content (default or user specified) + StyledTextRenderer renderer; + Listener listener; + TextChangeListener textChangeListener; // listener for TextChanging, TextChanged and TextSet events from StyledTextContent + int verticalScrollOffset = 0; // pixel based + int horizontalScrollOffset = 0; // pixel based + boolean alwaysShowScroll = true; + int ignoreResize = 0; + int topIndex = 0; // top visible line + int topIndexY; + int clientAreaHeight = 0; // the client area height. Needed to calculate content width for new visible lines during Resize callback + int clientAreaWidth = 0; // the client area width. Needed during Resize callback to determine if line wrap needs to be recalculated + int tabLength = 4; // number of characters in a tab + int [] tabs; + int leftMargin; + int topMargin; + int rightMargin; + int bottomMargin; + Color marginColor; + int columnX; // keep track of the horizontal caret position when changing lines/pages. Fixes bug 5935 + int caretOffset; + int caretAlignment; + Point selection = new Point(0, 0); // x and y are start and end caret offsets of selection (x <= y) + Point clipboardSelection; // x and y are start and end caret offsets of previous selection + int selectionAnchor; // position of selection anchor. 0 based offset from beginning of text + Point doubleClickSelection; // selection after last mouse double click + boolean editable = true; + boolean wordWrap = false; // text is wrapped automatically + boolean visualWrap = false; // process line breaks inside logical lines (inserted by BidiSegmentEvent) + boolean hasStyleWithVariableHeight = false; + boolean hasVerticalIndent = false; + boolean doubleClickEnabled = true; // see getDoubleClickEnabled + boolean overwrite = false; // insert/overwrite edit mode + int textLimit = -1; // limits the number of characters the user can type in the widget. Unlimited by default. + MapPrinting
is returned in the
+ * StyledText#print(Printer) API. The run() method may be
+ * invoked from any thread.
+ */
+ static class Printing implements Runnable {
+ final static int LEFT = 0; // left aligned header/footer segment
+ final static int CENTER = 1; // centered header/footer segment
+ final static int RIGHT = 2; // right aligned header/footer segment
+
+ Printer printer;
+ StyledTextRenderer printerRenderer;
+ StyledTextPrintOptions printOptions;
+ Rectangle clientArea;
+ FontData fontData;
+ Font printerFont;
+ MapPrinting
.
+ * Copies the widget content and rendering data that needs
+ * to be requested from listeners.
+ *
+ * @param parent StyledText widget to print.
+ * @param printer printer device to print on.
+ * @param printOptions print options
+ */
+ Printing(StyledText styledText, Printer printer, StyledTextPrintOptions printOptions) {
+ this.printer = printer;
+ this.printOptions = printOptions;
+ this.mirrored = (styledText.getStyle() & SWT.MIRRORED) != 0;
+ singleLine = styledText.isSingleLine();
+ startPage = 1;
+ endPage = Integer.MAX_VALUE;
+ PrinterData data = printer.getPrinterData();
+ scope = data.scope;
+ if (scope == PrinterData.PAGE_RANGE) {
+ startPage = data.startPage;
+ endPage = data.endPage;
+ if (endPage < startPage) {
+ int temp = endPage;
+ endPage = startPage;
+ startPage = temp;
+ }
+ } else if (scope == PrinterData.SELECTION) {
+ selection = styledText.getSelectionRange();
+ }
+ printerRenderer = new StyledTextRenderer(printer, null);
+ printerRenderer.setContent(copyContent(styledText.getContent()));
+ cacheLineData(styledText);
+ }
+ /**
+ * Caches all line data that needs to be requested from a listener.
+ *
+ * @param printerContent StyledTextContent
to request
+ * line data for.
+ */
+ void cacheLineData(StyledText styledText) {
+ StyledTextRenderer renderer = styledText.renderer;
+ renderer.copyInto(printerRenderer);
+ fontData = styledText.getFont().getFontData()[0];
+ tabLength = styledText.tabLength;
+ int lineCount = printerRenderer.lineCount;
+ if (styledText.isListening(ST.LineGetBackground) || (styledText.isListening(ST.LineGetSegments)) || styledText.isListening(ST.LineGetStyle)) {
+ StyledTextContent content = printerRenderer.content;
+ for (int i = 0; i < lineCount; i++) {
+ String line = content.getLine(i);
+ int lineOffset = content.getOffsetAtLine(i);
+ StyledTextEvent event = styledText.getLineBackgroundData(lineOffset, line);
+ if (event != null && event.lineBackground != null) {
+ printerRenderer.setLineBackground(i, 1, event.lineBackground);
+ }
+ event = styledText.getBidiSegments(lineOffset, line);
+ if (event != null) {
+ printerRenderer.setLineSegments(i, 1, event.segments);
+ printerRenderer.setLineSegmentChars(i, 1, event.segmentsChars);
+ }
+ event = styledText.getLineStyleData(lineOffset, line);
+ if (event != null) {
+ printerRenderer.setLineIndent(i, 1, event.indent);
+ printerRenderer.setLineAlignment(i, 1, event.alignment);
+ printerRenderer.setLineJustify(i, 1, event.justify);
+ printerRenderer.setLineBullet(i, 1, event.bullet);
+ StyleRange[] styles = event.styles;
+ if (styles != null && styles.length > 0) {
+ printerRenderer.setStyleRanges(event.ranges, styles);
+ }
+ }
+ }
+ }
+ Point screenDPI = styledText.getDisplay().getDPI();
+ Point printerDPI = printer.getDPI();
+ resources = new HashMap<> ();
+ for (int i = 0; i < lineCount; i++) {
+ Color color = printerRenderer.getLineBackground(i, null);
+ if (color != null) {
+ if (printOptions.printLineBackground) {
+ Color printerColor = (Color)resources.get(color);
+ if (printerColor == null) {
+ printerColor = new Color (printer, color.getRGB());
+ resources.put(color, printerColor);
+ }
+ printerRenderer.setLineBackground(i, 1, printerColor);
+ } else {
+ printerRenderer.setLineBackground(i, 1, null);
+ }
+ }
+ int indent = printerRenderer.getLineIndent(i, 0);
+ if (indent != 0) {
+ printerRenderer.setLineIndent(i, 1, indent * printerDPI.x / screenDPI.x);
+ }
+ }
+ StyleRange[] styles = printerRenderer.styles;
+ for (int i = 0; i < printerRenderer.styleCount; i++) {
+ StyleRange style = styles[i];
+ Font font = style.font;
+ if (style.font != null) {
+ Font printerFont = (Font)resources.get(font);
+ if (printerFont == null) {
+ printerFont = new Font (printer, font.getFontData());
+ resources.put(font, printerFont);
+ }
+ style.font = printerFont;
+ }
+ Color color = style.foreground;
+ if (color != null) {
+ Color printerColor = (Color)resources.get(color);
+ if (printOptions.printTextForeground) {
+ if (printerColor == null) {
+ printerColor = new Color (printer, color.getRGB());
+ resources.put(color, printerColor);
+ }
+ style.foreground = printerColor;
+ } else {
+ style.foreground = null;
+ }
+ }
+ color = style.background;
+ if (color != null) {
+ Color printerColor = (Color)resources.get(color);
+ if (printOptions.printTextBackground) {
+ if (printerColor == null) {
+ printerColor = new Color (printer, color.getRGB());
+ resources.put(color, printerColor);
+ }
+ style.background = printerColor;
+ } else {
+ style.background = null;
+ }
+ }
+ if (!printOptions.printTextFontStyle) {
+ style.fontStyle = SWT.NORMAL;
+ }
+ style.rise = style.rise * printerDPI.y / screenDPI.y;
+ GlyphMetrics metrics = style.metrics;
+ if (metrics != null) {
+ metrics.ascent = metrics.ascent * printerDPI.y / screenDPI.y;
+ metrics.descent = metrics.descent * printerDPI.y / screenDPI.y;
+ metrics.width = metrics.width * printerDPI.x / screenDPI.x;
+ }
+ }
+ lineSpacing = styledText.lineSpacing * printerDPI.y / screenDPI.y;
+ if (printOptions.printLineNumbers) {
+ printMargin = 3 * printerDPI.x / screenDPI.x;
+ }
+ }
+ /**
+ * Copies the text of the specified StyledTextContent
.
+ *
+ * @param original the StyledTextContent
to copy.
+ */
+ StyledTextContent copyContent(StyledTextContent original) {
+ StyledTextContent printerContent = new DefaultContent();
+ int insertOffset = 0;
+ for (int i = 0; i < original.getLineCount(); i++) {
+ int insertEndOffset;
+ if (i < original.getLineCount() - 1) {
+ insertEndOffset = original.getOffsetAtLine(i + 1);
+ } else {
+ insertEndOffset = original.getCharCount();
+ }
+ printerContent.replaceTextRange(insertOffset, 0, original.getTextRange(insertOffset, insertEndOffset - insertOffset));
+ insertOffset = insertEndOffset;
+ }
+ return printerContent;
+ }
+ /**
+ * Disposes of the resources and the PrintRenderer
.
+ */
+ void dispose() {
+ if (gc != null) {
+ gc.dispose();
+ gc = null;
+ }
+ if (resources != null) {
+ for (Resource resource : resources.values()) {
+ resource.dispose();
+ }
+ resources = null;
+ }
+ if (printerFont != null) {
+ printerFont.dispose();
+ printerFont = null;
+ }
+ if (printerRenderer != null) {
+ printerRenderer.dispose();
+ printerRenderer = null;
+ }
+ }
+ void init() {
+ Rectangle trim = printer.computeTrim(0, 0, 0, 0);
+ Point dpi = printer.getDPI();
+
+ printerFont = new Font(printer, fontData.getName(), fontData.getHeight(), SWT.NORMAL);
+ clientArea = printer.getClientArea();
+ pageWidth = clientArea.width;
+ // one inch margin around text
+ clientArea.x = dpi.x + trim.x;
+ clientArea.y = dpi.y + trim.y;
+ clientArea.width -= (clientArea.x + trim.width);
+ clientArea.height -= (clientArea.y + trim.height);
+
+ int style = mirrored ? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT;
+ gc = new GC(printer, style);
+ gc.setFont(printerFont);
+ printerRenderer.setFont(printerFont, tabLength);
+ int lineHeight = printerRenderer.getLineHeight();
+ if (printOptions.header != null) {
+ clientArea.y += lineHeight * 2;
+ clientArea.height -= lineHeight * 2;
+ }
+ if (printOptions.footer != null) {
+ clientArea.height -= lineHeight * 2;
+ }
+
+ // TODO not wrapped
+ StyledTextContent content = printerRenderer.content;
+ startLine = 0;
+ endLine = singleLine ? 0 : content.getLineCount() - 1;
+ if (scope == PrinterData.PAGE_RANGE) {
+ int pageSize = clientArea.height / lineHeight;//WRONG
+ startLine = (startPage - 1) * pageSize;
+ } else if (scope == PrinterData.SELECTION) {
+ startLine = content.getLineAtOffset(selection.x);
+ if (selection.y > 0) {
+ endLine = content.getLineAtOffset(selection.x + selection.y - 1);
+ } else {
+ endLine = startLine - 1;
+ }
+ }
+ }
+ /**
+ * Prints the lines in the specified page range.
+ */
+ void print() {
+ Color background = gc.getBackground();
+ Color foreground = gc.getForeground();
+ int paintY = clientArea.y;
+ int paintX = clientArea.x;
+ int width = clientArea.width;
+ int page = startPage;
+ int pageBottom = clientArea.y + clientArea.height;
+ int orientation = gc.getStyle() & (SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT);
+ TextLayout printLayout = null;
+ if (printOptions.printLineNumbers || printOptions.header != null || printOptions.footer != null) {
+ printLayout = new TextLayout(printer);
+ printLayout.setFont(printerFont);
+ }
+ if (printOptions.printLineNumbers) {
+ int numberingWidth = 0;
+ int count = endLine - startLine + 1;
+ String[] lineLabels = printOptions.lineLabels;
+ if (lineLabels != null) {
+ for (int i = startLine; i < Math.min(count, lineLabels.length); i++) {
+ if (lineLabels[i] != null) {
+ printLayout.setText(lineLabels[i]);
+ int lineWidth = printLayout.getBounds().width;
+ numberingWidth = Math.max(numberingWidth, lineWidth);
+ }
+ }
+ } else {
+ StringBuilder buffer = new StringBuilder("0");
+ while ((count /= 10) > 0) buffer.append("0");
+ printLayout.setText(buffer.toString());
+ numberingWidth = printLayout.getBounds().width;
+ }
+ numberingWidth += printMargin;
+ if (numberingWidth > width) numberingWidth = width;
+ paintX += numberingWidth;
+ width -= numberingWidth;
+ }
+ for (int i = startLine; i <= endLine && page <= endPage; i++) {
+ if (paintY == clientArea.y) {
+ printer.startPage();
+ printDecoration(page, true, printLayout);
+ }
+ TextLayout layout = printerRenderer.getTextLayout(i, orientation, width, lineSpacing);
+ Color lineBackground = printerRenderer.getLineBackground(i, background);
+ int paragraphBottom = paintY + layout.getBounds().height;
+ if (paragraphBottom <= pageBottom) {
+ //normal case, the whole paragraph fits in the current page
+ printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
+ paintY = paragraphBottom;
+ } else {
+ int lineCount = layout.getLineCount();
+ while (paragraphBottom > pageBottom && lineCount > 0) {
+ lineCount--;
+ paragraphBottom -= layout.getLineBounds(lineCount).height + layout.getSpacing();
+ }
+ if (lineCount == 0) {
+ //the whole paragraph goes to the next page
+ printDecoration(page, false, printLayout);
+ printer.endPage();
+ page++;
+ if (page <= endPage) {
+ printer.startPage();
+ printDecoration(page, true, printLayout);
+ paintY = clientArea.y;
+ printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
+ paintY += layout.getBounds().height;
+ }
+ } else {
+ //draw paragraph top in the current page and paragraph bottom in the next
+ int height = paragraphBottom - paintY;
+ gc.setClipping(clientArea.x, paintY, clientArea.width, height);
+ printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
+ gc.setClipping((Rectangle)null);
+ printDecoration(page, false, printLayout);
+ printer.endPage();
+ page++;
+ if (page <= endPage) {
+ printer.startPage();
+ printDecoration(page, true, printLayout);
+ paintY = clientArea.y - height;
+ int layoutHeight = layout.getBounds().height;
+ gc.setClipping(clientArea.x, clientArea.y, clientArea.width, layoutHeight - height);
+ printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
+ gc.setClipping((Rectangle)null);
+ paintY += layoutHeight;
+ }
+ }
+ }
+ printerRenderer.disposeTextLayout(layout);
+ }
+ if (page <= endPage && paintY > clientArea.y) {
+ // close partial page
+ printDecoration(page, false, printLayout);
+ printer.endPage();
+ }
+ if (printLayout != null) printLayout.dispose();
+ }
+ /**
+ * Print header or footer decorations.
+ *
+ * @param page page number to print, if specified in the StyledTextPrintOptions header or footer.
+ * @param header true = print the header, false = print the footer
+ */
+ void printDecoration(int page, boolean header, TextLayout layout) {
+ String text = header ? printOptions.header : printOptions.footer;
+ if (text == null) return;
+ int lastSegmentIndex = 0;
+ for (int i = 0; i < 3; i++) {
+ int segmentIndex = text.indexOf(StyledTextPrintOptions.SEPARATOR, lastSegmentIndex);
+ String segment;
+ if (segmentIndex == -1) {
+ segment = text.substring(lastSegmentIndex);
+ printDecorationSegment(segment, i, page, header, layout);
+ break;
+ } else {
+ segment = text.substring(lastSegmentIndex, segmentIndex);
+ printDecorationSegment(segment, i, page, header, layout);
+ lastSegmentIndex = segmentIndex + StyledTextPrintOptions.SEPARATOR.length();
+ }
+ }
+ }
+ /**
+ * Print one segment of a header or footer decoration.
+ * Headers and footers have three different segments.
+ * One each for left aligned, centered, and right aligned text.
+ *
+ * @param segment decoration segment to print
+ * @param alignment alignment of the segment. 0=left, 1=center, 2=right
+ * @param page page number to print, if specified in the decoration segment.
+ * @param header true = print the header, false = print the footer
+ */
+ void printDecorationSegment(String segment, int alignment, int page, boolean header, TextLayout layout) {
+ int pageIndex = segment.indexOf(StyledTextPrintOptions.PAGE_TAG);
+ if (pageIndex != -1) {
+ int pageTagLength = StyledTextPrintOptions.PAGE_TAG.length();
+ StringBuilder buffer = new StringBuilder(segment.substring (0, pageIndex));
+ buffer.append (page);
+ buffer.append (segment.substring(pageIndex + pageTagLength));
+ segment = buffer.toString();
+ }
+ if (segment.length() > 0) {
+ layout.setText(segment);
+ int segmentWidth = layout.getBounds().width;
+ int segmentHeight = printerRenderer.getLineHeight();
+ int drawX = 0, drawY;
+ if (alignment == LEFT) {
+ drawX = clientArea.x;
+ } else if (alignment == CENTER) {
+ drawX = (pageWidth - segmentWidth) / 2;
+ } else if (alignment == RIGHT) {
+ drawX = clientArea.x + clientArea.width - segmentWidth;
+ }
+ if (header) {
+ drawY = clientArea.y - segmentHeight * 2;
+ } else {
+ drawY = clientArea.y + clientArea.height + segmentHeight;
+ }
+ layout.draw(gc, drawX, drawY);
+ }
+ }
+ void printLine(int x, int y, GC gc, Color foreground, Color background, TextLayout layout, TextLayout printLayout, int index) {
+ if (background != null) {
+ Rectangle rect = layout.getBounds();
+ gc.setBackground(background);
+ gc.fillRectangle(x, y, rect.width, rect.height);
+
+// int lineCount = layout.getLineCount();
+// for (int i = 0; i < lineCount; i++) {
+// Rectangle rect = layout.getLineBounds(i);
+// rect.x += paintX;
+// rect.y += paintY + layout.getSpacing();
+// rect.width = width;//layout bounds
+// gc.fillRectangle(rect);
+// }
+ }
+ if (printOptions.printLineNumbers) {
+ FontMetrics metrics = layout.getLineMetrics(0);
+ printLayout.setAscent(metrics.getAscent() + metrics.getLeading());
+ printLayout.setDescent(metrics.getDescent());
+ String[] lineLabels = printOptions.lineLabels;
+ if (lineLabels != null) {
+ if (0 <= index && index < lineLabels.length && lineLabels[index] != null) {
+ printLayout.setText(lineLabels[index]);
+ } else {
+ printLayout.setText("");
+ }
+ } else {
+ printLayout.setText(String.valueOf(index));
+ }
+ int paintX = x - printMargin - printLayout.getBounds().width;
+ printLayout.draw(gc, paintX, y);
+ printLayout.setAscent(-1);
+ printLayout.setDescent(-1);
+ }
+ gc.setForeground(foreground);
+ layout.draw(gc, x, y);
+ }
+ /**
+ * Starts a print job and prints the pages specified in the constructor.
+ */
+ @Override
+ public void run() {
+ String jobName = printOptions.jobName;
+ if (jobName == null) {
+ jobName = "Printing";
+ }
+ if (printer.startJob(jobName)) {
+ init();
+ print();
+ dispose();
+ printer.endJob();
+ }
+ }
+ }
+ /**
+ * The RTFWriter
class is used to write widget content as
+ * rich text. The implementation complies with the RTF specification
+ * version 1.5.
+ * + * toString() is guaranteed to return a valid RTF string only after + * close() has been called. + *
+ * Whole and partial lines and line breaks can be written. Lines will be + * formatted using the styles queried from the LineStyleListener, if + * set, or those set directly in the widget. All styles are applied to + * the RTF stream like they are rendered by the widget. In addition, the + * widget font name and size is used for the whole text. + *
+ */ + class RTFWriter extends TextWriter { + static final int DEFAULT_FOREGROUND = 0; + static final int DEFAULT_BACKGROUND = 1; + Liststart
and length
can be set to specify partial
+ * lines.
+ *
+ * @param start start offset of content to write, 0 based from
+ * beginning of document
+ * @param length length of content to write
+ */
+ public RTFWriter(int start, int length) {
+ super(start, length);
+ colorTable = new ArrayList<>();
+ fontTable = new ArrayList<>();
+ colorTable.add(getForeground());
+ colorTable.add(getBackground());
+ fontTable.add(getFont());
+ }
+ /**
+ * Closes the RTF writer. Once closed no more content can be written.
+ * NOTE: toString()
does not return a valid RTF string until
+ * close()
has been called.
+ */
+ @Override
+ public void close() {
+ if (!isClosed()) {
+ writeHeader();
+ write("\n}}\0");
+ super.close();
+ }
+ }
+ /**
+ * Returns the index of the specified color in the RTF color table.
+ *
+ * @param color the color
+ * @param defaultIndex return value if color is null
+ * @return the index of the specified color in the RTF color table
+ * or "defaultIndex" if "color" is null.
+ */
+ int getColorIndex(Color color, int defaultIndex) {
+ if (color == null) return defaultIndex;
+ int index = colorTable.indexOf(color);
+ if (index == -1) {
+ index = colorTable.size();
+ colorTable.add(color);
+ }
+ return index;
+ }
+ /**
+ * Returns the index of the specified color in the RTF color table.
+ *
+ * @param color the color
+ * @param defaultIndex return value if color is null
+ * @return the index of the specified color in the RTF color table
+ * or "defaultIndex" if "color" is null.
+ */
+ int getFontIndex(Font font) {
+ int index = fontTable.indexOf(font);
+ if (index == -1) {
+ index = fontTable.size();
+ fontTable.add(font);
+ }
+ return index;
+ }
+ /**
+ * Appends the specified segment of "string" to the RTF data.
+ * Copy from start
up to, but excluding, end
.
+ *
+ * @param string string to copy a segment from. Must not contain
+ * line breaks. Line breaks should be written using writeLineDelimiter()
+ * @param start start offset of segment. 0 based.
+ * @param end end offset of segment
+ */
+ void write(String string, int start, int end) {
+ for (int index = start; index < end; index++) {
+ char ch = string.charAt(index);
+ if (ch > 0x7F) {
+ // write the sub string from the last escaped character
+ // to the current one. Fixes bug 21698.
+ if (index > start) {
+ write(string.substring(start, index));
+ }
+ write("\\u");
+ write(Integer.toString((short) ch));
+ write('?'); // ANSI representation (1 byte long, \\uc1)
+ start = index + 1;
+ } else if (ch == '}' || ch == '{' || ch == '\\') {
+ // write the sub string from the last escaped character
+ // to the current one. Fixes bug 21698.
+ if (index > start) {
+ write(string.substring(start, index));
+ }
+ write('\\');
+ write(ch);
+ start = index + 1;
+ }
+ }
+ // write from the last escaped character to the end.
+ // Fixes bug 21698.
+ if (start < end) {
+ write(string.substring(start, end));
+ }
+ }
+ /**
+ * Writes the RTF header including font table and color table.
+ */
+ void writeHeader() {
+ StringBuilder header = new StringBuilder();
+ FontData fontData = getFont().getFontData()[0];
+ header.append("{\\rtf1\\ansi");
+ // specify code page, necessary for copy to work in bidi
+ // systems that don't support Unicode RTF.
+ String cpg = System.getProperty("file.encoding").toLowerCase();
+ if (cpg.startsWith("cp") || cpg.startsWith("ms")) {
+ cpg = cpg.substring(2, cpg.length());
+ header.append("\\ansicpg");
+ header.append(cpg);
+ }
+ header.append("\\uc1\\deff0{\\fonttbl{\\f0\\fnil ");
+ header.append(fontData.getName());
+ header.append(";");
+ for (int i = 1; i < fontTable.size(); i++) {
+ header.append("\\f");
+ header.append(i);
+ header.append(" ");
+ FontData fd = fontTable.get(i).getFontData()[0];
+ header.append(fd.getName());
+ header.append(";");
+ }
+ header.append("}}\n{\\colortbl");
+ for (int i = 0; i < colorTable.size(); i++) {
+ Color color = colorTable.get(i);
+ header.append("\\red");
+ header.append(color.getRed());
+ header.append("\\green");
+ header.append(color.getGreen());
+ header.append("\\blue");
+ header.append(color.getBlue());
+ header.append(";");
+ }
+ // some RTF readers ignore the deff0 font tag. Explicitly
+ // set the font for the whole document to work around this.
+ header.append("}\n{\\f0\\fs");
+ // font size is specified in half points
+ header.append(fontData.getHeight() * 2);
+ header.append(" ");
+ write(header.toString(), 0);
+ }
+ /**
+ * Appends the specified line text to the RTF data. Lines will be formatted
+ * using the styles queried from the LineStyleListener, if set, or those set
+ * directly in the widget.
+ *
+ * @param line line text to write as RTF. Must not contain line breaks
+ * Line breaks should be written using writeLineDelimiter()
+ * @param lineOffset offset of the line. 0 based from the start of the
+ * widget document. Any text occurring before the start offset or after the
+ * end offset specified during object creation is ignored.
+ * @exception SWTException + * Use the colors and font styles specified in "styles" and "lineBackground". + * Formatting is written to reflect the text rendering by the text widget. + * Style background colors take precedence over the line background color. + * Background colors are written using the \chshdng0\chcbpat tag (vs. the \cb tag). + *
+ * + * @param line line text to write as RTF. Must not contain line breaks + * Line breaks should be written using writeLineDelimiter() + * @param lineOffset offset of the line. 0 based from the start of the + * widget document. Any text occurring before the start offset or after the + * end offset specified during object creation is ignored. + * @param styles styles to use for formatting. Must not be null. + * @param lineBackground line background color to use for formatting. + * May be null. + */ + void writeStyledLine(String line, int lineOffset, int ranges[], StyleRange[] styles, Color lineBackground, int indent, int alignment, boolean justify) { + int lineLength = line.length(); + int startOffset = getStart(); + int writeOffset = startOffset - lineOffset; + if (writeOffset >= lineLength) return; + int lineIndex = Math.max(0, writeOffset); + + write("\\fi"); + write(indent); + switch (alignment) { + case SWT.LEFT: write("\\ql"); break; + case SWT.CENTER: write("\\qc"); break; + case SWT.RIGHT: write("\\qr"); break; + } + if (justify) write("\\qj"); + write(" "); + + if (lineBackground != null) { + write("{\\chshdng0\\chcbpat"); + write(getColorIndex(lineBackground, DEFAULT_BACKGROUND)); + write(" "); + } + int endOffset = startOffset + super.getCharCount(); + int lineEndOffset = Math.min(lineLength, endOffset - lineOffset); + for (int i = 0; i < styles.length; i++) { + StyleRange style = styles[i]; + int start, end; + if (ranges != null) { + start = ranges[i << 1] - lineOffset; + end = start + ranges[(i << 1) + 1]; + } else { + start = style.start - lineOffset; + end = start + style.length; + } + // skip over partial first line + if (end < writeOffset) { + continue; + } + // style starts beyond line end or RTF write end + if (start >= lineEndOffset) { + break; + } + // write any unstyled text + if (lineIndex < start) { + // copy to start of style + // style starting beyond end of write range or end of line + // is guarded against above. + write(line, lineIndex, start); + lineIndex = start; + } + // write styled text + write("{\\cf"); + write(getColorIndex(style.foreground, DEFAULT_FOREGROUND)); + int colorIndex = getColorIndex(style.background, DEFAULT_BACKGROUND); + if (colorIndex != DEFAULT_BACKGROUND) { + write("\\chshdng0\\chcbpat"); + write(colorIndex); + } + int fontStyle = style.fontStyle; + Font font = style.font; + if (font != null) { + int fontIndex = getFontIndex(font); + write("\\f"); + write(fontIndex); + FontData fontData = font.getFontData()[0]; + write("\\fs"); + write(fontData.getHeight() * 2); + fontStyle = fontData.getStyle(); + } + if ((fontStyle & SWT.BOLD) != 0) { + write("\\b"); + } + if ((fontStyle & SWT.ITALIC) != 0) { + write("\\i"); + } + if (style.underline) { + write("\\ul"); + } + if (style.strikeout) { + write("\\strike"); + } + write(" "); + // copy to end of style or end of write range or end of line + int copyEnd = Math.min(end, lineEndOffset); + // guard against invalid styles and let style processing continue + copyEnd = Math.max(copyEnd, lineIndex); + write(line, lineIndex, copyEnd); + if ((fontStyle & SWT.BOLD) != 0) { + write("\\b0"); + } + if ((style.fontStyle & SWT.ITALIC) != 0) { + write("\\i0"); + } + if (style.underline) { + write("\\ul0"); + } + if (style.strikeout) { + write("\\strike0"); + } + write("}"); + lineIndex = copyEnd; + } + // write unstyled text at the end of the line + if (lineIndex < lineEndOffset) { + write(line, lineIndex, lineEndOffset); + } + if (lineBackground != null) write("}"); + } + } + /** + * TheTextWriter
class is used to write widget content to
+ * a string. Whole and partial lines and line breaks can be written. To write
+ * partial lines, specify the start and length of the desired segment
+ * during object creation.
+ *
+ * NOTE: toString()
is guaranteed to return a valid string only after close()
+ * has been called.
+ *
start
and length
can be set to specify partial lines.
+ *
+ * @param start start offset of content to write, 0 based from beginning of document
+ * @param length length of content to write
+ */
+ public TextWriter(int start, int length) {
+ buffer = new StringBuilder(length);
+ startOffset = start;
+ endOffset = start + length;
+ }
+ /**
+ * Closes the writer. Once closed no more content can be written.
+ * NOTE: toString()
is not guaranteed to return a valid string unless
+ * the writer is closed.
+ */
+ public void close() {
+ if (!isClosed) {
+ isClosed = true;
+ }
+ }
+ /**
+ * Returns the number of characters to write.
+ * @return the integer number of characters to write
+ */
+ public int getCharCount() {
+ return endOffset - startOffset;
+ }
+ /**
+ * Returns the offset where writing starts. 0 based from the start of
+ * the widget text. Used to write partial lines.
+ * @return the integer offset where writing starts
+ */
+ public int getStart() {
+ return startOffset;
+ }
+ /**
+ * Returns whether the writer is closed.
+ * @return a boolean specifying whether or not the writer is closed
+ */
+ public boolean isClosed() {
+ return isClosed;
+ }
+ /**
+ * Returns the string. close()
must be called before toString()
+ * is guaranteed to return a valid string.
+ *
+ * @return the string
+ */
+ @Override
+ public String toString() {
+ return buffer.toString();
+ }
+ /**
+ * Appends the given string to the data.
+ */
+ void write(String string) {
+ buffer.append(string);
+ }
+ /**
+ * Inserts the given string to the data at the specified offset.
+ * + * Do nothing if "offset" is < 0 or > getCharCount() + *
+ * + * @param string text to insert + * @param offset offset in the existing data to insert "string" at. + */ + void write(String string, int offset) { + if (offset < 0 || offset > buffer.length()) { + return; + } + buffer.insert(offset, string); + } + /** + * Appends the given int to the data. + */ + void write(int i) { + buffer.append(i); + } + /** + * Appends the given character to the data. + */ + void write(char i) { + buffer.append(i); + } + /** + * Appends the specified line text to the data. + * + * @param line line text to write. Must not contain line breaks + * Line breaks should be written using writeLineDelimiter() + * @param lineOffset offset of the line. 0 based from the start of the + * widget document. Any text occurring before the start offset or after the + * end offset specified during object creation is ignored. + * @exception SWTException
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * A BidiSegmentEvent is sent + * whenever a line of text is measured or rendered. You can + * specify text ranges in the line that should be treated as if they + * had a different direction than the surrounding text. + * This may be used when adjacent segments of right-to-left text should + * not be reordered relative to each other. + * E.g., multiple Java string literals in a right-to-left language + * should generally remain in logical order to each other, that is, the + * way they are stored. + *
+ * + * @param listener the listener + * @exception SWTException
+ * When widgetSelected
is called, the event x and y fields contain
+ * the start and end caret indices of the selection. The selection values returned are visual
+ * (i.e., x will always always be <= y).
+ * No event is sent when the caret is moved while the selection length is 0.
+ *
+ * widgetDefaultSelected
is not called for StyledTexts.
+ *
DND.CLIPBOARD
clipboard.
+ *
+ * The text will be put on the clipboard in plain text format and RTF format.
+ * The DND.CLIPBOARD
clipboard is used for data that is
+ * transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V) or
+ * by menu action.
+ *
+ * The clipboardType is one of the clipboard constants defined in class
+ * DND
. The DND.CLIPBOARD
clipboard is
+ * used for data that is transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V)
+ * or by menu action. The DND.SELECTION_CLIPBOARD
+ * clipboard is used for data that is transferred by selecting text and pasting
+ * with the middle mouse button.
+ *
+ * Returns only the first line if the widget has the SWT.SINGLE style. + *
+ * + * @param text the text that may have line delimiters that don't + * match the model line delimiter. Possible line delimiters + * are CR ('\r'), LF ('\n'), CR/LF ("\r\n") + * @return the converted text that only uses the line delimiter + * specified by the model. Returns only the first line if the widget + * has the SWT.SINGLE style. + */ +String getModelDelimitedText(String text) { + int length = text.length(); + if (length == 0) { + return text; + } + int crIndex = 0; + int lfIndex = 0; + int i = 0; + StringBuilder convertedText = new StringBuilder(length); + String delimiter = getLineDelimiter(); + while (i < length) { + if (crIndex != -1) { + crIndex = text.indexOf(SWT.CR, i); + } + if (lfIndex != -1) { + lfIndex = text.indexOf(SWT.LF, i); + } + if (lfIndex == -1 && crIndex == -1) { // no more line breaks? + break; + } else if ((crIndex < lfIndex && crIndex != -1) || lfIndex == -1) { + convertedText.append(text.substring(i, crIndex)); + if (lfIndex == crIndex + 1) { // CR/LF combination? + i = lfIndex + 1; + } else { + i = crIndex + 1; + } + } else { // LF occurs before CR! + convertedText.append(text.substring(i, lfIndex)); + i = lfIndex + 1; + } + if (isSingleLine()) { + break; + } + convertedText.append(delimiter); + } + // copy remaining text if any and if not in single line mode or no + // text copied thus far (because there only is one line) + if (i < length && (!isSingleLine() || convertedText.length() == 0)) { + convertedText.append(text.substring(i)); + } + return convertedText.toString(); +} +boolean checkDragDetect(Event event) { + if (!isListening(SWT.DragDetect)) return false; + if (event.button != 1) return false; + if (blockSelection && blockXLocation != -1) { + Rectangle rect = getBlockSelectionRectangle(); + if (rect.contains(event.x, event.y)) { + return dragDetect(event); + } + } else { + if (selection.x == selection.y) return false; + int offset = getOffsetAtPoint(event.x, event.y, null, true); + if (selection.x <= offset && offset < selection.y) { + return dragDetect(event); + } + + } + return false; +} + +/** + * Creates default key bindings. + */ +void createKeyBindings() { + int nextKey = isMirrored() ? SWT.ARROW_LEFT : SWT.ARROW_RIGHT; + int previousKey = isMirrored() ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT; + + // Navigation + setKeyBinding(SWT.ARROW_UP, ST.LINE_UP); + setKeyBinding(SWT.ARROW_DOWN, ST.LINE_DOWN); + if (IS_MAC) { + setKeyBinding(previousKey | SWT.MOD1, ST.LINE_START); + setKeyBinding(nextKey | SWT.MOD1, ST.LINE_END); + setKeyBinding(SWT.HOME, ST.TEXT_START); + setKeyBinding(SWT.END, ST.TEXT_END); + setKeyBinding(SWT.ARROW_UP | SWT.MOD1, ST.TEXT_START); + setKeyBinding(SWT.ARROW_DOWN | SWT.MOD1, ST.TEXT_END); + setKeyBinding(nextKey | SWT.MOD3, ST.WORD_NEXT); + setKeyBinding(previousKey | SWT.MOD3, ST.WORD_PREVIOUS); + } else { + setKeyBinding(SWT.HOME, ST.LINE_START); + setKeyBinding(SWT.END, ST.LINE_END); + setKeyBinding(SWT.HOME | SWT.MOD1, ST.TEXT_START); + setKeyBinding(SWT.END | SWT.MOD1, ST.TEXT_END); + setKeyBinding(nextKey | SWT.MOD1, ST.WORD_NEXT); + setKeyBinding(previousKey | SWT.MOD1, ST.WORD_PREVIOUS); + } + setKeyBinding(SWT.PAGE_UP, ST.PAGE_UP); + setKeyBinding(SWT.PAGE_DOWN, ST.PAGE_DOWN); + setKeyBinding(SWT.PAGE_UP | SWT.MOD1, ST.WINDOW_START); + setKeyBinding(SWT.PAGE_DOWN | SWT.MOD1, ST.WINDOW_END); + setKeyBinding(nextKey, ST.COLUMN_NEXT); + setKeyBinding(previousKey, ST.COLUMN_PREVIOUS); + + // Selection + setKeyBinding(SWT.ARROW_UP | SWT.MOD2, ST.SELECT_LINE_UP); + setKeyBinding(SWT.ARROW_DOWN | SWT.MOD2, ST.SELECT_LINE_DOWN); + if (IS_MAC) { + setKeyBinding(previousKey | SWT.MOD1 | SWT.MOD2, ST.SELECT_LINE_START); + setKeyBinding(nextKey | SWT.MOD1 | SWT.MOD2, ST.SELECT_LINE_END); + setKeyBinding(SWT.HOME | SWT.MOD2, ST.SELECT_TEXT_START); + setKeyBinding(SWT.END | SWT.MOD2, ST.SELECT_TEXT_END); + setKeyBinding(SWT.ARROW_UP | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_START); + setKeyBinding(SWT.ARROW_DOWN | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_END); + setKeyBinding(nextKey | SWT.MOD2 | SWT.MOD3, ST.SELECT_WORD_NEXT); + setKeyBinding(previousKey | SWT.MOD2 | SWT.MOD3, ST.SELECT_WORD_PREVIOUS); + } else { + setKeyBinding(SWT.HOME | SWT.MOD2, ST.SELECT_LINE_START); + setKeyBinding(SWT.END | SWT.MOD2, ST.SELECT_LINE_END); + setKeyBinding(SWT.HOME | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_START); + setKeyBinding(SWT.END | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_END); + setKeyBinding(nextKey | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_NEXT); + setKeyBinding(previousKey | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_PREVIOUS); + } + setKeyBinding(SWT.PAGE_UP | SWT.MOD2, ST.SELECT_PAGE_UP); + setKeyBinding(SWT.PAGE_DOWN | SWT.MOD2, ST.SELECT_PAGE_DOWN); + setKeyBinding(SWT.PAGE_UP | SWT.MOD1 | SWT.MOD2, ST.SELECT_WINDOW_START); + setKeyBinding(SWT.PAGE_DOWN | SWT.MOD1 | SWT.MOD2, ST.SELECT_WINDOW_END); + setKeyBinding(nextKey | SWT.MOD2, ST.SELECT_COLUMN_NEXT); + setKeyBinding(previousKey | SWT.MOD2, ST.SELECT_COLUMN_PREVIOUS); + + // Modification + // Cut, Copy, Paste + setKeyBinding('X' | SWT.MOD1, ST.CUT); + setKeyBinding('C' | SWT.MOD1, ST.COPY); + setKeyBinding('V' | SWT.MOD1, ST.PASTE); + if (IS_MAC) { + setKeyBinding(SWT.DEL | SWT.MOD2, ST.DELETE_NEXT); + setKeyBinding(SWT.BS | SWT.MOD3, ST.DELETE_WORD_PREVIOUS); + setKeyBinding(SWT.DEL | SWT.MOD3, ST.DELETE_WORD_NEXT); + } else { + // Cut, Copy, Paste Wordstar style + setKeyBinding(SWT.DEL | SWT.MOD2, ST.CUT); + setKeyBinding(SWT.INSERT | SWT.MOD1, ST.COPY); + setKeyBinding(SWT.INSERT | SWT.MOD2, ST.PASTE); + } + setKeyBinding(SWT.BS | SWT.MOD2, ST.DELETE_PREVIOUS); + setKeyBinding(SWT.BS, ST.DELETE_PREVIOUS); + setKeyBinding(SWT.DEL, ST.DELETE_NEXT); + setKeyBinding(SWT.BS | SWT.MOD1, ST.DELETE_WORD_PREVIOUS); + setKeyBinding(SWT.DEL | SWT.MOD1, ST.DELETE_WORD_NEXT); + + // Miscellaneous + setKeyBinding(SWT.INSERT, ST.TOGGLE_OVERWRITE); +} +/** + * Create the bitmaps to use for the caret in bidi mode. This + * method only needs to be called upon widget creation and when the + * font changes (the caret bitmap height needs to match font height). + */ +void createCaretBitmaps() { + int caretWidth = BIDI_CARET_WIDTH; + Display display = getDisplay(); + if (leftCaretBitmap != null) { + if (defaultCaret != null && leftCaretBitmap.equals(defaultCaret.getImage())) { + defaultCaret.setImage(null); + } + leftCaretBitmap.dispose(); + } + int lineHeight = renderer.getLineHeight(); + leftCaretBitmap = new Image(display, caretWidth, lineHeight); + GC gc = new GC (leftCaretBitmap); + gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); + gc.fillRectangle(0, 0, caretWidth, lineHeight); + gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); + gc.drawLine(0,0,0,lineHeight); + gc.drawLine(0,0,caretWidth-1,0); + gc.drawLine(0,1,1,1); + gc.dispose(); + + if (rightCaretBitmap != null) { + if (defaultCaret != null && rightCaretBitmap.equals(defaultCaret.getImage())) { + defaultCaret.setImage(null); + } + rightCaretBitmap.dispose(); + } + rightCaretBitmap = new Image(display, caretWidth, lineHeight); + gc = new GC (rightCaretBitmap); + gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); + gc.fillRectangle(0, 0, caretWidth, lineHeight); + gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); + gc.drawLine(caretWidth-1,0,caretWidth-1,lineHeight); + gc.drawLine(0,0,caretWidth-1,0); + gc.drawLine(caretWidth-1,1,1,1); + gc.dispose(); +} +/** + * Moves the selected text to the clipboard. The text will be put in the + * clipboard in plain text format and RTF format. + * + * @exception SWTException+ * If a carriage return was typed replace it with the line break character + * used by the widget on this platform. + *
+ * + * @param key the character typed by the user + */ +void doContent(char key) { + if (blockSelection && blockXLocation != -1) { + insertBlockSelectionText(key, SWT.NULL); + return; + } + + Event event = new Event(); + event.start = selection.x; + event.end = selection.y; + // replace a CR line break with the widget line break + // CR does not make sense on Windows since most (all?) applications + // don't recognize CR as a line break. + if (key == SWT.CR || key == SWT.LF) { + if (!isSingleLine()) { + event.text = getLineDelimiter(); + } + } else if (selection.x == selection.y && overwrite && key != TAB) { + // no selection and overwrite mode is on and the typed key is not a + // tab character (tabs are always inserted without overwriting)? + int lineIndex = content.getLineAtOffset(event.end); + int lineOffset = content.getOffsetAtLine(lineIndex); + String line = content.getLine(lineIndex); + // replace character at caret offset if the caret is not at the + // end of the line + if (event.end < lineOffset + line.length()) { + event.end++; + } + event.text = new String(new char[] {key}); + } else { + event.text = new String(new char[] {key}); + } + if (event.text != null) { + if (textLimit > 0 && content.getCharCount() - (event.end - event.start) >= textLimit) { + return; + } + sendKeyEvent(event); + } +} +/** + * Moves the caret after the last character of the widget content. + */ +void doContentEnd() { + // place caret at end of first line if receiver is in single + // line mode. fixes 4820. + if (isSingleLine()) { + doLineEnd(); + } else { + int length = content.getCharCount(); + setCaretOffset(length, SWT.DEFAULT); + showCaret(); + } +} +/** + * Moves the caret in front of the first character of the widget content. + */ +void doContentStart() { + setCaretOffset(0, SWT.DEFAULT); + showCaret(); +} +/** + * Moves the caret to the start of the selection if a selection exists. + * Otherwise, if no selection exists move the cursor according to the + * cursor selection rules. + * + * @see #doSelectionCursorPrevious + */ +void doCursorPrevious() { + if (selection.y - selection.x > 0) { + setCaretOffset(selection.x, OFFSET_LEADING); + showCaret(); + } else { + doSelectionCursorPrevious(); + } +} +/** + * Moves the caret to the end of the selection if a selection exists. + * Otherwise, if no selection exists move the cursor according to the + * cursor selection rules. + * + * @see #doSelectionCursorNext + */ +void doCursorNext() { + if (selection.y - selection.x > 0) { + setCaretOffset(selection.y, PREVIOUS_OFFSET_TRAILING); + showCaret(); + } else { + doSelectionCursorNext(); + } +} +/** + * Deletes the next character. Delete the selected text if any. + */ +void doDelete() { + Event event = new Event(); + event.text = ""; + if (selection.x != selection.y) { + event.start = selection.x; + event.end = selection.y; + sendKeyEvent(event); + } else if (caretOffset < content.getCharCount()) { + int line = content.getLineAtOffset(caretOffset); + int lineOffset = content.getOffsetAtLine(line); + int lineLength = content.getLine(line).length(); + if (caretOffset == lineOffset + lineLength) { + event.start = caretOffset; + event.end = content.getOffsetAtLine(line + 1); + } else { + event.start = caretOffset; + event.end = getClusterNext(caretOffset, line); + } + sendKeyEvent(event); + } +} +/** + * Deletes the next word. + */ +void doDeleteWordNext() { + if (selection.x != selection.y) { + // if a selection exists, treat the as if + // only the delete key was pressed + doDelete(); + } else { + Event event = new Event(); + event.text = ""; + event.start = caretOffset; + event.end = getWordNext(caretOffset, SWT.MOVEMENT_WORD); + sendKeyEvent(event); + } +} +/** + * Deletes the previous word. + */ +void doDeleteWordPrevious() { + if (selection.x != selection.y) { + // if a selection exists, treat as if + // only the backspace key was pressed + doBackspace(); + } else { + Event event = new Event(); + event.text = ""; + event.start = getWordPrevious(caretOffset, SWT.MOVEMENT_WORD); + event.end = caretOffset; + sendKeyEvent(event); + } +} +/** + * Moves the caret one line down and to the same character offset relative + * to the beginning of the line. Move the caret to the end of the new line + * if the new line is shorter than the character offset. Moves the caret to + * the end of the text if the caret already is on the last line. + */ +void doLineDown(boolean select) { + int caretLine = getCaretLine(); + int lineCount = content.getLineCount(); + int y = 0; + boolean lastLine = false; + if (isWordWrap()) { + int lineOffset = content.getOffsetAtLine(caretLine); + int offsetInLine = caretOffset - lineOffset; + TextLayout layout = renderer.getTextLayout(caretLine); + int lineIndex = getVisualLineIndex(layout, offsetInLine); + int layoutLineCount = layout.getLineCount(); + if (lineIndex == layoutLineCount - 1) { + lastLine = caretLine == lineCount - 1; + caretLine++; + } else { + y = layout.getLineBounds(lineIndex + 1).y; + y++; // bug 485722: workaround for fractional line heights + } + renderer.disposeTextLayout(layout); + } else { + lastLine = caretLine == lineCount - 1; + caretLine++; + } + if (lastLine) { + setCaretOffset(content.getCharCount(), SWT.DEFAULT); + } else { + int[] alignment = new int[1]; + int offset = getOffsetAtPoint(columnX, y, caretLine, alignment); + setCaretOffset(offset, alignment[0]); + } + int oldColumnX = columnX; + int oldHScrollOffset = horizontalScrollOffset; + if (select) { + setMouseWordSelectionAnchor(); + // select first and then scroll to reduce flash when key + // repeat scrolls lots of lines + doSelection(ST.COLUMN_NEXT); + } + showCaret(); + int hScrollChange = oldHScrollOffset - horizontalScrollOffset; + columnX = oldColumnX + hScrollChange; +} +/** + * Moves the caret to the end of the line. + */ +void doLineEnd() { + int caretLine = getCaretLine(); + int lineOffset = content.getOffsetAtLine(caretLine); + int lineEndOffset; + if (isWordWrap()) { + TextLayout layout = renderer.getTextLayout(caretLine); + int offsetInLine = caretOffset - lineOffset; + int lineIndex = getVisualLineIndex(layout, offsetInLine); + int[] offsets = layout.getLineOffsets(); + lineEndOffset = lineOffset + offsets[lineIndex + 1]; + renderer.disposeTextLayout(layout); + } else { + int lineLength = content.getLine(caretLine).length(); + lineEndOffset = lineOffset + lineLength; + } + setCaretOffset(lineEndOffset, PREVIOUS_OFFSET_TRAILING); + showCaret(); +} +/** + * Moves the caret to the beginning of the line. + */ +void doLineStart() { + int caretLine = getCaretLine(); + int lineOffset = content.getOffsetAtLine(caretLine); + if (isWordWrap()) { + TextLayout layout = renderer.getTextLayout(caretLine); + int offsetInLine = caretOffset - lineOffset; + int lineIndex = getVisualLineIndex(layout, offsetInLine); + int[] offsets = layout.getLineOffsets(); + lineOffset += offsets[lineIndex]; + renderer.disposeTextLayout(layout); + } + setCaretOffset(lineOffset, OFFSET_LEADING); + showCaret(); +} +/** + * Moves the caret one line up and to the same character offset relative + * to the beginning of the line. Move the caret to the end of the new line + * if the new line is shorter than the character offset. Moves the caret to + * the beginning of the document if it is already on the first line. + */ +void doLineUp(boolean select) { + int caretLine = getCaretLine(), y = 0; + boolean firstLine = false; + if (isWordWrap()) { + int lineOffset = content.getOffsetAtLine(caretLine); + int offsetInLine = caretOffset - lineOffset; + TextLayout layout = renderer.getTextLayout(caretLine); + int lineIndex = getVisualLineIndex(layout, offsetInLine); + if (lineIndex == 0) { + firstLine = caretLine == 0; + if (!firstLine) { + caretLine--; + y = renderer.getLineHeight(caretLine) - 1; + y--; // bug 485722: workaround for fractional line heights + } + } else { + y = layout.getLineBounds(lineIndex - 1).y; + y++; // bug 485722: workaround for fractional line heights + } + renderer.disposeTextLayout(layout); + } else { + firstLine = caretLine == 0; + caretLine--; + } + if (firstLine) { + setCaretOffset(0, SWT.DEFAULT); + } else { + int[] alignment = new int[1]; + int offset = getOffsetAtPoint(columnX, y, caretLine, alignment); + setCaretOffset(offset, alignment[0]); + } + int oldColumnX = columnX; + int oldHScrollOffset = horizontalScrollOffset; + if (select) setMouseWordSelectionAnchor(); + showCaret(); + if (select) doSelection(ST.COLUMN_PREVIOUS); + int hScrollChange = oldHScrollOffset - horizontalScrollOffset; + columnX = oldColumnX + hScrollChange; +} +void doMouseLinkCursor() { + Display display = getDisplay(); + Point point = display.getCursorLocation(); + point = display.map(null, this, point); + doMouseLinkCursor(point.x, point.y); +} +void doMouseLinkCursor(int x, int y) { + int offset = getOffsetAtPoint(x, y, null, true); + Display display = getDisplay(); + Cursor newCursor = cursor; + if (renderer.hasLink(offset)) { + newCursor = display.getSystemCursor(SWT.CURSOR_HAND); + } else { + if (cursor == null) { + int type = blockSelection ? SWT.CURSOR_CROSS : SWT.CURSOR_IBEAM; + newCursor = display.getSystemCursor(type); + } + } + if (newCursor != getCursor()) super.setCursor(newCursor); +} +/** + * Moves the caret to the specified location. + * + * @param x x location of the new caret position + * @param y y location of the new caret position + * @param select the location change is a selection operation. + * include the line delimiter in the selection + */ +void doMouseLocationChange(int x, int y, boolean select) { + int line = getLineIndex(y); + + updateCaretDirection = true; + + if (blockSelection) { + x = Math.max(leftMargin, Math.min(x, clientAreaWidth - rightMargin)); + y = Math.max(topMargin, Math.min(y, clientAreaHeight - bottomMargin)); + if (doubleClickEnabled && clickCount > 1) { + boolean wordSelect = (clickCount & 1) == 0; + if (wordSelect) { + Point left = getPointAtOffset(doubleClickSelection.x); + int[] trailing = new int[1]; + int offset = getOffsetAtPoint(x, y, trailing, true); + if (offset != -1) { + if (x > left.x) { + offset = getWordNext(offset + trailing[0], SWT.MOVEMENT_WORD_END); + setBlockSelectionOffset(doubleClickSelection.x, offset, true); + } else { + offset = getWordPrevious(offset + trailing[0], SWT.MOVEMENT_WORD_START); + setBlockSelectionOffset(doubleClickSelection.y, offset, true); + } + } else { + if (x > left.x) { + setBlockSelectionLocation(left.x, left.y, x, y, true); + } else { + Point right = getPointAtOffset(doubleClickSelection.y); + setBlockSelectionLocation(right.x, right.y, x, y, true); + } + } + } else { + setBlockSelectionLocation(blockXLocation, y, true); + } + return; + } else { + if (select) { + if (blockXLocation == -1) { + setBlockSelectionOffset(caretOffset, false); + } + } else { + clearBlockSelection(true, false); + } + int[] trailing = new int[1]; + int offset = getOffsetAtPoint(x, y, trailing, true); + if (offset != -1) { + if (select) { + setBlockSelectionOffset(offset + trailing[0], true); + return; + } + } else { + if (isFixedLineHeight() && renderer.fixedPitch) { + int avg = renderer.averageCharWidth; + x = ((x + avg / 2 - leftMargin + horizontalScrollOffset) / avg * avg) + leftMargin - horizontalScrollOffset; + } + setBlockSelectionLocation(x, y, true); + return; + } + } + } + + // allow caret to be placed below first line only if receiver is + // not in single line mode. fixes 4820. + if (line < 0 || (isSingleLine() && line > 0)) { + return; + } + int[] alignment = new int[1]; + int newCaretOffset = getOffsetAtPoint(x, y, alignment); + int newCaretAlignemnt = alignment[0]; + + if (doubleClickEnabled && clickCount > 1) { + newCaretOffset = doMouseWordSelect(x, newCaretOffset, line); + } + + int newCaretLine = content.getLineAtOffset(newCaretOffset); + + // Is the mouse within the left client area border or on + // a different line? If not the autoscroll selection + // could be incorrectly reset. Fixes 1GKM3XS + boolean vchange = 0 <= y && y < clientAreaHeight || newCaretLine == 0 || newCaretLine == content.getLineCount() - 1; + boolean hchange = 0 <= x && x < clientAreaWidth || wordWrap || newCaretLine != content.getLineAtOffset(caretOffset); + if (vchange && hchange && (newCaretOffset != caretOffset || newCaretAlignemnt != caretAlignment)) { + setCaretOffset(newCaretOffset, newCaretAlignemnt); + if (select) doMouseSelection(); + showCaret(); + } + if (!select) { + setCaretOffset(newCaretOffset, newCaretAlignemnt); + clearSelection(true); + } +} +/** + * Updates the selection based on the caret position + */ +void doMouseSelection() { + if (caretOffset <= selection.x || + (caretOffset > selection.x && + caretOffset < selection.y && selectionAnchor == selection.x)) { + doSelection(ST.COLUMN_PREVIOUS); + } else { + doSelection(ST.COLUMN_NEXT); + } +} +/** + * Returns the offset of the word at the specified offset. + * If the current selection extends from high index to low index + * (i.e., right to left, or caret is at left border of selection on + * non-bidi platforms) the start offset of the word preceding the + * selection is returned. If the current selection extends from + * low index to high index the end offset of the word following + * the selection is returned. + * + * @param x mouse x location + * @param newCaretOffset caret offset of the mouse cursor location + * @param line line index of the mouse cursor location + */ +int doMouseWordSelect(int x, int newCaretOffset, int line) { + // flip selection anchor based on word selection direction from + // base double click. Always do this here (and don't rely on doAutoScroll) + // because auto scroll only does not cover all possible mouse selections + // (e.g., mouse x < 0 && mouse y > caret line y) + if (newCaretOffset < selectionAnchor && selectionAnchor == selection.x) { + selectionAnchor = doubleClickSelection.y; + } else if (newCaretOffset > selectionAnchor && selectionAnchor == selection.y) { + selectionAnchor = doubleClickSelection.x; + } + if (0 <= x && x < clientAreaWidth) { + boolean wordSelect = (clickCount & 1) == 0; + if (caretOffset == selection.x) { + if (wordSelect) { + newCaretOffset = getWordPrevious(newCaretOffset, SWT.MOVEMENT_WORD_START); + } else { + newCaretOffset = content.getOffsetAtLine(line); + } + } else { + if (wordSelect) { + newCaretOffset = getWordNext(newCaretOffset, SWT.MOVEMENT_WORD_END); + } else { + int lineEnd = content.getCharCount(); + if (line + 1 < content.getLineCount()) { + lineEnd = content.getOffsetAtLine(line + 1); + } + newCaretOffset = lineEnd; + } + } + } + return newCaretOffset; +} +/** + * Scrolls one page down so that the last line (truncated or whole) + * of the current page becomes the fully visible top line. + *+ * The caret is scrolled the same number of lines so that its location + * relative to the top line remains the same. The exception is the end + * of the text where a full page scroll is not possible. In this case + * the caret is moved after the last character. + *
+ * + * @param select whether or not to select the page + */ +void doPageDown(boolean select, int height) { + if (isSingleLine()) return; + int oldColumnX = columnX; + int oldHScrollOffset = horizontalScrollOffset; + if (isFixedLineHeight()) { + int lineCount = content.getLineCount(); + int caretLine = getCaretLine(); + if (caretLine < lineCount - 1) { + int lineHeight = renderer.getLineHeight(); + int lines = (height == -1 ? clientAreaHeight : height) / lineHeight; + int scrollLines = Math.min(lineCount - caretLine - 1, lines); + // ensure that scrollLines never gets negative and at least one + // line is scrolled. fixes bug 5602. + scrollLines = Math.max(1, scrollLines); + int[] alignment = new int[1]; + int offset = getOffsetAtPoint(columnX, getLinePixel(caretLine + scrollLines), alignment); + setCaretOffset(offset, alignment[0]); + if (select) { + doSelection(ST.COLUMN_NEXT); + } + // scroll one page down or to the bottom + int verticalMaximum = lineCount * getVerticalIncrement(); + int pageSize = clientAreaHeight; + int verticalScrollOffset = getVerticalScrollOffset(); + int scrollOffset = verticalScrollOffset + scrollLines * getVerticalIncrement(); + if (scrollOffset + pageSize > verticalMaximum) { + scrollOffset = verticalMaximum - pageSize; + } + if (scrollOffset > verticalScrollOffset) { + scrollVertical(scrollOffset - verticalScrollOffset, true); + } + } + } else { + int lineCount = content.getLineCount(); + int caretLine = getCaretLine(); + int lineIndex, lineHeight; + if (height == -1) { + lineIndex = getPartialBottomIndex(); + int topY = getLinePixel(lineIndex); + lineHeight = renderer.getLineHeight(lineIndex); + height = topY; + if (topY + lineHeight <= clientAreaHeight) { + height += lineHeight; + } else { + if (isWordWrap()) { + TextLayout layout = renderer.getTextLayout(lineIndex); + int y = clientAreaHeight - topY; + for (int i = 0; i < layout.getLineCount(); i++) { + Rectangle bounds = layout.getLineBounds(i); + if (bounds.contains(bounds.x, y)) { + height += bounds.y; + break; + } + } + renderer.disposeTextLayout(layout); + } + } + } else { + lineIndex = getLineIndex(height); + int topLineY = getLinePixel(lineIndex); + if (isWordWrap()) { + TextLayout layout = renderer.getTextLayout(lineIndex); + int y = height - topLineY; + for (int i = 0; i < layout.getLineCount(); i++) { + Rectangle bounds = layout.getLineBounds(i); + if (bounds.contains(bounds.x, y)) { + height = topLineY + bounds.y + bounds.height; + break; + } + } + renderer.disposeTextLayout(layout); + } else { + height = topLineY + renderer.getLineHeight(lineIndex); + } + } + int caretHeight = height; + if (isWordWrap()) { + TextLayout layout = renderer.getTextLayout(caretLine); + int offsetInLine = caretOffset - content.getOffsetAtLine(caretLine); + lineIndex = getVisualLineIndex(layout, offsetInLine); + caretHeight += layout.getLineBounds(lineIndex).y; + renderer.disposeTextLayout(layout); + } + lineIndex = caretLine; + lineHeight = renderer.getLineHeight(lineIndex); + while (caretHeight - lineHeight >= 0 && lineIndex < lineCount - 1) { + caretHeight -= lineHeight; + lineHeight = renderer.getLineHeight(++lineIndex); + } + int[] alignment = new int[1]; + int offset = getOffsetAtPoint(columnX, caretHeight, lineIndex, alignment); + setCaretOffset(offset, alignment[0]); + if (select) doSelection(ST.COLUMN_NEXT); + height = getAvailableHeightBellow(height); + scrollVertical(height, true); + if (height == 0) setCaretLocation(); + } + showCaret(); + int hScrollChange = oldHScrollOffset - horizontalScrollOffset; + columnX = oldColumnX + hScrollChange; +} +/** + * Moves the cursor to the end of the last fully visible line. + */ +void doPageEnd() { + // go to end of line if in single line mode. fixes 5673 + if (isSingleLine()) { + doLineEnd(); + } else { + int bottomOffset; + if (isWordWrap()) { + int lineIndex = getPartialBottomIndex(); + TextLayout layout = renderer.getTextLayout(lineIndex); + int y = (clientAreaHeight - bottomMargin) - getLinePixel(lineIndex); + int index = layout.getLineCount() - 1; + while (index >= 0) { + Rectangle bounds = layout.getLineBounds(index); + if (y >= bounds.y + bounds.height) break; + index--; + } + if (index == -1 && lineIndex > 0) { + bottomOffset = content.getOffsetAtLine(lineIndex - 1) + content.getLine(lineIndex - 1).length(); + } else { + bottomOffset = content.getOffsetAtLine(lineIndex) + Math.max(0, layout.getLineOffsets()[index + 1] - 1); + } + renderer.disposeTextLayout(layout); + } else { + int lineIndex = getBottomIndex(); + bottomOffset = content.getOffsetAtLine(lineIndex) + content.getLine(lineIndex).length(); + } + if (caretOffset < bottomOffset) { + setCaretOffset(bottomOffset, OFFSET_LEADING); + showCaret(); + } + } +} +/** + * Moves the cursor to the beginning of the first fully visible line. + */ +void doPageStart() { + int topOffset; + if (isWordWrap()) { + int y, lineIndex; + if (topIndexY > 0) { + lineIndex = topIndex - 1; + y = renderer.getLineHeight(lineIndex) - topIndexY; + } else { + lineIndex = topIndex; + y = -topIndexY; + } + TextLayout layout = renderer.getTextLayout(lineIndex); + int index = 0; + int lineCount = layout.getLineCount(); + while (index < lineCount) { + Rectangle bounds = layout.getLineBounds(index); + if (y <= bounds.y) break; + index++; + } + if (index == lineCount) { + topOffset = content.getOffsetAtLine(lineIndex + 1); + } else { + topOffset = content.getOffsetAtLine(lineIndex) + layout.getLineOffsets()[index]; + } + renderer.disposeTextLayout(layout); + } else { + topOffset = content.getOffsetAtLine(topIndex); + } + if (caretOffset > topOffset) { + setCaretOffset(topOffset, OFFSET_LEADING); + showCaret(); + } +} +/** + * Scrolls one page up so that the first line (truncated or whole) + * of the current page becomes the fully visible last line. + * The caret is scrolled the same number of lines so that its location + * relative to the top line remains the same. The exception is the beginning + * of the text where a full page scroll is not possible. In this case the + * caret is moved in front of the first character. + */ +void doPageUp(boolean select, int height) { + if (isSingleLine()) return; + int oldHScrollOffset = horizontalScrollOffset; + int oldColumnX = columnX; + if (isFixedLineHeight()) { + int caretLine = getCaretLine(); + if (caretLine > 0) { + int lineHeight = renderer.getLineHeight(); + int lines = (height == -1 ? clientAreaHeight : height) / lineHeight; + int scrollLines = Math.max(1, Math.min(caretLine, lines)); + caretLine -= scrollLines; + int[] alignment = new int[1]; + int offset = getOffsetAtPoint(columnX, getLinePixel(caretLine), alignment); + setCaretOffset(offset, alignment[0]); + if (select) { + doSelection(ST.COLUMN_PREVIOUS); + } + int verticalScrollOffset = getVerticalScrollOffset(); + int scrollOffset = Math.max(0, verticalScrollOffset - scrollLines * getVerticalIncrement()); + if (scrollOffset < verticalScrollOffset) { + scrollVertical(scrollOffset - verticalScrollOffset, true); + } + } + } else { + int caretLine = getCaretLine(); + int lineHeight, lineIndex; + if (height == -1) { + if (topIndexY == 0) { + height = clientAreaHeight; + } else { + int y; + if (topIndex > 0) { + lineIndex = topIndex - 1; + lineHeight = renderer.getLineHeight(lineIndex); + height = clientAreaHeight - topIndexY; + y = lineHeight - topIndexY; + } else { + lineIndex = topIndex; + lineHeight = renderer.getLineHeight(lineIndex); + height = clientAreaHeight - (lineHeight + topIndexY); + y = -topIndexY; + } + if (isWordWrap()) { + TextLayout layout = renderer.getTextLayout(lineIndex); + for (int i = 0; i < layout.getLineCount(); i++) { + Rectangle bounds = layout.getLineBounds(i); + if (bounds.contains(bounds.x, y)) { + height += lineHeight - (bounds.y + bounds.height); + break; + } + } + renderer.disposeTextLayout(layout); + } + } + } else { + lineIndex = getLineIndex(clientAreaHeight - height); + int topLineY = getLinePixel(lineIndex); + if (isWordWrap()) { + TextLayout layout = renderer.getTextLayout(lineIndex); + int y = topLineY; + for (int i = 0; i < layout.getLineCount(); i++) { + Rectangle bounds = layout.getLineBounds(i); + if (bounds.contains(bounds.x, y)) { + height = clientAreaHeight - (topLineY + bounds.y); + break; + } + } + renderer.disposeTextLayout(layout); + } else { + height = clientAreaHeight - topLineY; + } + } + int caretHeight = height; + if (isWordWrap()) { + TextLayout layout = renderer.getTextLayout(caretLine); + int offsetInLine = caretOffset - content.getOffsetAtLine(caretLine); + lineIndex = getVisualLineIndex(layout, offsetInLine); + caretHeight += layout.getBounds().height - layout.getLineBounds(lineIndex).y; + renderer.disposeTextLayout(layout); + } + lineIndex = caretLine; + lineHeight = renderer.getLineHeight(lineIndex); + while (caretHeight - lineHeight >= 0 && lineIndex > 0) { + caretHeight -= lineHeight; + lineHeight = renderer.getLineHeight(--lineIndex); + } + lineHeight = renderer.getLineHeight(lineIndex); + int[] alignment = new int[1]; + int offset = getOffsetAtPoint(columnX, lineHeight - caretHeight, lineIndex, alignment); + setCaretOffset(offset, alignment[0]); + if (select) doSelection(ST.COLUMN_PREVIOUS); + height = getAvailableHeightAbove(height); + scrollVertical(-height, true); + if (height == 0) setCaretLocation(); + } + showCaret(); + int hScrollChange = oldHScrollOffset - horizontalScrollOffset; + columnX = oldColumnX + hScrollChange; +} +/** + * Updates the selection to extend to the current caret position. + */ +void doSelection(int direction) { + int redrawStart = -1; + int redrawEnd = -1; + if (selectionAnchor == -1) { + selectionAnchor = selection.x; + } + if (direction == ST.COLUMN_PREVIOUS) { + if (caretOffset < selection.x) { + // grow selection + redrawEnd = selection.x; + redrawStart = selection.x = caretOffset; + // check if selection has reversed direction + if (selection.y != selectionAnchor) { + redrawEnd = selection.y; + selection.y = selectionAnchor; + } + // test whether selection actually changed. Fixes 1G71EO1 + } else if (selectionAnchor == selection.x && caretOffset < selection.y) { + // caret moved towards selection anchor (left side of selection). + // shrink selection + redrawEnd = selection.y; + redrawStart = selection.y = caretOffset; + } + } else { + if (caretOffset > selection.y) { + // grow selection + redrawStart = selection.y; + redrawEnd = selection.y = caretOffset; + // check if selection has reversed direction + if (selection.x != selectionAnchor) { + redrawStart = selection.x; + selection.x = selectionAnchor; + } + // test whether selection actually changed. Fixes 1G71EO1 + } else if (selectionAnchor == selection.y && caretOffset > selection.x) { + // caret moved towards selection anchor (right side of selection). + // shrink selection + redrawStart = selection.x; + redrawEnd = selection.x = caretOffset; + } + } + if (redrawStart != -1 && redrawEnd != -1) { + internalRedrawRange(redrawStart, redrawEnd - redrawStart); + sendSelectionEvent(); + } + sendAccessibleTextCaretMoved(); +} +/** + * Moves the caret to the next character or to the beginning of the + * next line if the cursor is at the end of a line. + */ +void doSelectionCursorNext() { + int caretLine = getCaretLine(); + int lineOffset = content.getOffsetAtLine(caretLine); + int offsetInLine = caretOffset - lineOffset; + int offset, alignment; + if (offsetInLine < content.getLine(caretLine).length()) { + TextLayout layout = renderer.getTextLayout(caretLine); + offsetInLine = layout.getNextOffset(offsetInLine, SWT.MOVEMENT_CLUSTER); + int lineStart = layout.getLineOffsets()[layout.getLineIndex(offsetInLine)]; + renderer.disposeTextLayout(layout); + offset = offsetInLine + lineOffset; + alignment = offsetInLine == lineStart ? OFFSET_LEADING : PREVIOUS_OFFSET_TRAILING; + setCaretOffset(offset, alignment); + showCaret(); + } else if (caretLine < content.getLineCount() - 1 && !isSingleLine()) { + caretLine++; + offset = content.getOffsetAtLine(caretLine); + alignment = PREVIOUS_OFFSET_TRAILING; + setCaretOffset(offset, alignment); + showCaret(); + } +} +/** + * Moves the caret to the previous character or to the end of the previous + * line if the cursor is at the beginning of a line. + */ +void doSelectionCursorPrevious() { + int caretLine = getCaretLine(); + int lineOffset = content.getOffsetAtLine(caretLine); + int offsetInLine = caretOffset - lineOffset; + if (offsetInLine > 0) { + int offset = getClusterPrevious(caretOffset, caretLine); + setCaretOffset(offset, OFFSET_LEADING); + showCaret(); + } else if (caretLine > 0) { + caretLine--; + lineOffset = content.getOffsetAtLine(caretLine); + int offset = lineOffset + content.getLine(caretLine).length(); + setCaretOffset(offset, OFFSET_LEADING); + showCaret(); + } +} +/** + * Moves the caret one line down and to the same character offset relative + * to the beginning of the line. Moves the caret to the end of the new line + * if the new line is shorter than the character offset. + * Moves the caret to the end of the text if the caret already is on the + * last line. + * Adjusts the selection according to the caret change. This can either add + * to or subtract from the old selection, depending on the previous selection + * direction. + */ +void doSelectionLineDown() { + int oldColumnX = columnX = getPointAtOffset(caretOffset).x; + doLineDown(true); + columnX = oldColumnX; +} +/** + * Moves the caret one line up and to the same character offset relative + * to the beginning of the line. Moves the caret to the end of the new line + * if the new line is shorter than the character offset. + * Moves the caret to the beginning of the document if it is already on the + * first line. + * Adjusts the selection according to the caret change. This can either add + * to or subtract from the old selection, depending on the previous selection + * direction. + */ +void doSelectionLineUp() { + int oldColumnX = columnX = getPointAtOffset(caretOffset).x; + doLineUp(true); + columnX = oldColumnX; +} +/** + * Scrolls one page down so that the last line (truncated or whole) + * of the current page becomes the fully visible top line. + *+ * The caret is scrolled the same number of lines so that its location + * relative to the top line remains the same. The exception is the end + * of the text where a full page scroll is not possible. In this case + * the caret is moved after the last character. + *
+ * Adjusts the selection according to the caret change. This can either add + * to or subtract from the old selection, depending on the previous selection + * direction. + *
+ */ +void doSelectionPageDown(int pixels) { + int oldColumnX = columnX = getPointAtOffset(caretOffset).x; + doPageDown(true, pixels); + columnX = oldColumnX; +} +/** + * Scrolls one page up so that the first line (truncated or whole) + * of the current page becomes the fully visible last line. + *+ * The caret is scrolled the same number of lines so that its location + * relative to the top line remains the same. The exception is the beginning + * of the text where a full page scroll is not possible. In this case the + * caret is moved in front of the first character. + *
+ * Adjusts the selection according to the caret change. This can either add + * to or subtract from the old selection, depending on the previous selection + * direction. + *
+ */ +void doSelectionPageUp(int pixels) { + int oldColumnX = columnX = getPointAtOffset(caretOffset).x; + doPageUp(true, pixels); + columnX = oldColumnX; +} +/** + * Moves the caret to the end of the next word . + */ +void doSelectionWordNext() { + int offset = getWordNext(caretOffset, SWT.MOVEMENT_WORD); + // don't change caret position if in single line mode and the cursor + // would be on a different line. fixes 5673 + if (!isSingleLine() || + content.getLineAtOffset(caretOffset) == content.getLineAtOffset(offset)) { + // Force symmetrical movement for word next and previous. Fixes 14536 + setCaretOffset(offset, OFFSET_LEADING); + showCaret(); + } +} +/** + * Moves the caret to the start of the previous word. + */ +void doSelectionWordPrevious() { + int offset = getWordPrevious(caretOffset, SWT.MOVEMENT_WORD); + setCaretOffset(offset, OFFSET_LEADING); + showCaret(); +} +/** + * Moves the caret one character to the left. Do not go to the previous line. + * When in a bidi locale and at a R2L character the caret is moved to the + * beginning of the R2L segment (visually right) and then one character to the + * left (visually left because it's now in a L2R segment). + */ +void doVisualPrevious() { + int offset = getClusterPrevious(caretOffset, getCaretLine()); + setCaretOffset(offset, SWT.DEFAULT); + showCaret(); +} +/** + * Moves the caret one character to the right. Do not go to the next line. + * When in a bidi locale and at a R2L character the caret is moved to the + * end of the R2L segment (visually left) and then one character to the + * right (visually right because it's now in a L2R segment). + */ +void doVisualNext() { + int offset = getClusterNext(caretOffset, getCaretLine()); + setCaretOffset(offset, SWT.DEFAULT); + showCaret(); +} +/** + * Moves the caret to the end of the next word. + * If a selection exists, move the caret to the end of the selection + * and remove the selection. + */ +void doWordNext() { + if (selection.y - selection.x > 0) { + setCaretOffset(selection.y, SWT.DEFAULT); + showCaret(); + } else { + doSelectionWordNext(); + } +} +/** + * Moves the caret to the start of the previous word. + * If a selection exists, move the caret to the start of the selection + * and remove the selection. + */ +void doWordPrevious() { + if (selection.y - selection.x > 0) { + setCaretOffset(selection.x, SWT.DEFAULT); + showCaret(); + } else { + doSelectionWordPrevious(); + } +} +/** + * Ends the autoscroll process. + */ +void endAutoScroll() { + autoScrollDirection = SWT.NULL; +} +@Override +public Color getBackground() { + checkWidget(); + if (background == null) { + return getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); + } + return background; +} +/** + * Returns the baseline, in points. + * + * Note: this API should not be used if a StyleRange attribute causes lines to + * have different heights (i.e. different fonts, rise, etc). + * + * @return baseline the baseline + * @exception SWTException+ * + * @param lineIndex index of the line to return. + * @return the line text without delimiters + * + * @exception SWTException
+ * Note: this API should not be used if a StyleRange attribute causes lines to + * have different heights (i.e. different fonts, rise, etc). + *
+ * + * @return line height in points. + * @exception SWTException+ * If there is a LineStyleListener but it does not set any styles, + * the StyledTextEvent.styles field will be initialized to an empty + * array. + *
+ * + * @param lineOffset offset of the line start relative to the start of + * the content. + * @param line line to get line styles for + * @return line style data for the given line. Styles may start before + * line start and end after line end + */ +StyledTextEvent getLineStyleData(int lineOffset, String line) { + return sendLineEvent(ST.LineGetStyle, lineOffset, line); +} +/** + * Returns the top SWT logical point, relative to the client area, of a given line. + * Clamps out of ranges index. + * + * @param lineIndex the line index, the max value is lineCount. If + * lineIndex == lineCount it returns the bottom SWT logical point of the last line. + * It means this function can be used to retrieve the bottom SWT logical point of any line. + * + * @return the top SWT logical point of a given line index + * + * @since 3.2 + */ +public int getLinePixel(int lineIndex) { + checkWidget(); + int lineCount = content.getLineCount(); + lineIndex = Math.max(0, Math.min(lineCount, lineIndex)); + if (isFixedLineHeight()) { + int lineHeight = renderer.getLineHeight(); + return lineIndex * lineHeight - getVerticalScrollOffset() + topMargin; + } + if (lineIndex == topIndex) return topIndexY + topMargin; + int height = topIndexY; + if (lineIndex > topIndex) { + for (int i = topIndex; i < lineIndex; i++) { + height += renderer.getLineHeight(i); + } + } else { + for (int i = topIndex - 1; i >= lineIndex; i--) { + height -= renderer.getLineHeight(i); + } + } + return height + topMargin; +} +/** + * Returns the line index for a y, relative to the client area. + * The line index returned is always in the range 0..lineCount - 1. + * + * @param y the y-coordinate point + * + * @return the line index for a given y-coordinate point + * + * @since 3.2 + */ +public int getLineIndex(int y) { + checkWidget(); + y -= topMargin; + if (isFixedLineHeight()) { + int lineHeight = renderer.getLineHeight(); + int lineIndex = (y + getVerticalScrollOffset()) / lineHeight; + int lineCount = content.getLineCount(); + lineIndex = Math.max(0, Math.min(lineCount - 1, lineIndex)); + return lineIndex; + } + if (y == topIndexY) return topIndex; + int line = topIndex; + if (y < topIndexY) { + while (y < topIndexY && line > 0) { + y += renderer.getLineHeight(--line); + } + } else { + int lineCount = content.getLineCount(); + int lineHeight = renderer.getLineHeight(line); + while (y - lineHeight >= topIndexY && line < lineCount - 1) { + y -= lineHeight; + lineHeight = renderer.getLineHeight(++line); + } + } + return line; +} +/** + * Returns the tab stops of the line at the givenindex
.
+ *
+ * @param index the index of the line
+ *
+ * @return the tab stops for the line
+ *
+ * @exception SWTException index
.
+ *
+ * @param index the index of the line
+ *
+ * @return the wrap indentation
+ *
+ * @exception SWTException true
if the mouse navigator is enabled.
+ * When mouse navigator is enabled, the user can navigate through the widget by pressing the middle button and moving the cursor
+ *
+ * @return the mouse navigator's enabled state
+ *
+ * @exception SWTException + * The return value reflects the character offset that the caret will + * be placed at if a mouse click occurred at the specified location. + * If the x coordinate of the location is beyond the center of a character + * the returned offset will be behind the character. + *
+ * + * @param point the origin of character bounding box relative to + * the origin of the widget client area. + * @return offset of the character at the given location relative + * to the first character in the document. + * @exception SWTException+ * The return value reflects the character offset that the caret will + * be placed at if a mouse click occurred at the specified point. + * If the x coordinate of the point is beyond the center of a character + * the returned offset will be behind the character. + *
+ * Note: This method is functionally similar to {@link #getOffsetAtLocation(Point)} except that + * it does not throw an exception when no character is found and thus performs faster. + * + * @param point the origin of character bounding box relative to + * the origin of the widget client area. + * @return offset of the character at the given point relative + * to the first character in the document. + * -1 when there is no character at the specified location. + * @exception SWTExceptionnull
+ * The ranges array contains start and length pairs. Each pair refers to
+ * the corresponding style in the styles array. For example, the pair
+ * that starts at ranges[n] with length ranges[n+1] uses the style
+ * at styles[n/2] returned by getStyleRanges(int, int, boolean)
.
+ *
+ * The ranges array contains start and length pairs. Each pair refers to
+ * the corresponding style in the styles array. For example, the pair
+ * that starts at ranges[n] with length ranges[n+1] uses the style
+ * at styles[n/2] returned by getStyleRanges(int, int, boolean)
.
+ *
+ * Text selections are specified in terms of caret positions. In a text + * widget that contains N characters, there are N+1 caret positions, + * ranging from 0..N + *
+ * + * @return start and end of the selection, x is the offset of the first + * selected character, y is the offset after the last selected character. + * The selection values returned are visual (i.e., x will always always be + * <= y). To determine if a selection is right-to-left (RtoL) vs. left-to-right + * (LtoR), compare the caretOffset to the start and end of the selection + * (e.g., caretOffset == start of selection implies that the selection is RtoL). + * @see #getSelectionRange + * @exception SWTException+ * The ranges array contains start and length pairs. When the receiver is not + * in block selection mode the return arrays contains the start and length of + * the regular selection. + * + * @return the ranges array + * + * @exception SWTException
+ * Returns null if a LineStyleListener has been set or if a style is not set + * for the offset. + * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * + * @param offset the offset to return the style for. + * 0 <= offset < getCharCount() must be true. + * @return a StyleRange with start == offset and length == 1, indicating + * the style at the given offset. null if a LineStyleListener has been set + * or if a style is not set for the given offset. + * @exception SWTException+ * Returns an empty array if a LineStyleListener has been set. + * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * Note: Because a StyleRange includes the start and length, the
+ * same instance cannot occur multiple times in the array of styles.
+ * If the same style attributes, such as font and color, occur in
+ * multiple StyleRanges, getStyleRanges(boolean)
+ * can be used to get the styles without the ranges.
+ *
+ * Returns an empty array if a LineStyleListener has been set. + * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * Note: When includeRanges
is true, the start and length
+ * fields of each StyleRange will be valid, however the StyleRange
+ * objects may need to be cloned. When includeRanges
is
+ * false, getRanges(int, int)
can be used to get the
+ * associated ranges.
+ *
+ * Returns an empty array if a LineStyleListener has been set. + * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * Note: Because the StyleRange includes the start and length, the
+ * same instance cannot occur multiple times in the array of styles.
+ * If the same style attributes, such as font and color, occur in
+ * multiple StyleRanges, getStyleRanges(int, int, boolean)
+ * can be used to get the styles without the ranges.
+ *
StyleRange
will have a starting offset >= start
+ * and the last returned StyleRange
will have an ending
+ * offset <= start + length - 1
+ *
+ * @exception SWTException + * Returns an empty array if a LineStyleListener has been set. + * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * Note: When includeRanges
is true, the start and length
+ * fields of each StyleRange will be valid, however the StyleRange
+ * objects may need to be cloned. When includeRanges
is
+ * false, getRanges(int, int)
can be used to get the
+ * associated ranges.
+ *
StyleRange
will have a starting offset >= start
+ * and the last returned StyleRange
will have an ending
+ * offset >= start + length - 1
+ *
+ * @exception SWTException + * The top index is the index of the fully visible line that is currently + * at the top of the widget or the topmost partially visible line if no line is fully visible. + * The top index changes when the widget is scrolled. Indexing is zero based. + *
+ * + * @return the index of the top line + * @exception SWTException+ * The top point is the SWT logical point position of the line that is + * currently at the top of the widget. The text widget can be scrolled by points + * by dragging the scroll thumb so that a partial line may be displayed at the top + * the widget. The top point changes when the widget is scrolled. The top point + * does not include the widget trimming. + *
+ * + * @return SWT logical point position of the top line + * @exception SWTException+ * NOTE: Does not return correct values for true italic fonts (vs. slanted fonts). + *
+ * + * @return location of the character at the given offset in the line. + */ +Point getPointAtOffset(int offset) { + int lineIndex = content.getLineAtOffset(offset); + String line = content.getLine(lineIndex); + int lineOffset = content.getOffsetAtLine(lineIndex); + int offsetInLine = Math.max (0, offset - lineOffset); + int lineLength = line.length(); + if (lineIndex < content.getLineCount() - 1) { + int endLineOffset = content.getOffsetAtLine(lineIndex + 1) - 1; + if (lineLength < offsetInLine && offsetInLine <= endLineOffset) { + offsetInLine = lineLength; + } + } + Point point; + TextLayout layout = renderer.getTextLayout(lineIndex); + if (lineLength != 0 && offsetInLine <= lineLength) { + if (offsetInLine == lineLength) { + offsetInLine = layout.getPreviousOffset(offsetInLine, SWT.MOVEMENT_CLUSTER); + point = layout.getLocation(offsetInLine, true); + } else { + switch (caretAlignment) { + case OFFSET_LEADING: + point = layout.getLocation(offsetInLine, false); + break; + case PREVIOUS_OFFSET_TRAILING: + default: + boolean lineBegin = offsetInLine == 0; + // If word wrap is enabled, we should also consider offsets + // of wrapped line parts as line begin and do NOT go back. + // This prevents clients to jump one line higher than + // expected, see bug 488172. + // Respect caretAlignment at the caretOffset, unless there's + // a non-empty selection, see bug 488172 comment 6. + if (wordWrap && !lineBegin && (offset != caretOffset || selection.x != selection.y)) { + int[] offsets = layout.getLineOffsets(); + for (int i : offsets) { + if (i == offsetInLine) { + lineBegin = true; + break; + } + } + } + if (lineBegin) { + point = layout.getLocation(offsetInLine, false); + } else { + offsetInLine = layout.getPreviousOffset(offsetInLine, SWT.MOVEMENT_CLUSTER); + point = layout.getLocation(offsetInLine, true); + } + break; + } + } + } else { + point = new Point(layout.getIndent(), layout.getVerticalIndent()); + } + renderer.disposeTextLayout(layout); + point.x += leftMargin - horizontalScrollOffset; + point.y += getLinePixel(lineIndex); + return point; +} +/** + * Inserts a string. The old selection is replaced with the new text. + * + * @param string the string + * @see #replaceTextRange(int,int,String) + * @exception SWTExceptiontrue
if any text in the widget is selected,
+ * and false
otherwise.
+ *
+ * @return the text selection state
+ * @exception SWTException DND.CLIPBOARD
+ * clipboard or, if there is no selection, inserts the text at the current
+ * caret offset. If the widget has the SWT.SINGLE style and the
+ * clipboard text contains more than one line, only the first line without
+ * line delimiters is inserted in the widget.
+ *
+ * @exception SWTException + * The runnable may be run in a non-UI thread. + *
+ * + * @param printer the printer to print to + * + * @return aRunnable
for printing the receiver's text
+ *
+ * @exception SWTException + * The runnable may be run in a non-UI thread. + *
+ * + * @param printer the printer to print to + * @param options print options to use during printing + * + * @return aRunnable
for printing the receiver's text
+ *
+ * @exception SWTException
+ * Recalculates the content width for all lines in the bounds.
+ * When a LineStyleListener
is used a redraw call
+ * is the only notification to the widget that styles have changed
+ * and that the content width may have changed.
+ *
all
flag
+ * is true
, any children of the receiver which
+ * intersect with the specified area will also paint their
+ * intersecting areas. If the all
flag is
+ * false
, the children will not be painted.
+ *
+ * Marks the content width of all lines in the specified rectangle
+ * as unknown. Recalculates the content width of all visible lines.
+ * When a LineStyleListener
is used a redraw call
+ * is the only notification to the widget that styles have changed
+ * and that the content width may have changed.
+ *
true
if children should redraw, and false
otherwise
+ *
+ * @exception SWTException
+ * Note: Because a StyleRange includes the start and length, the
+ * same instance cannot occur multiple times in the array of styles.
+ * If the same style attributes, such as font and color, occur in
+ * multiple StyleRanges, setStyleRanges(int, int, int[], StyleRange[])
+ * can be used to share styles and reduce memory usage.
+ *
+ * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * + * @param start offset of first character where styles will be deleted + * @param length length of the range to delete styles in + * @param ranges StyleRange objects containing the new style information. + * The ranges should not overlap and should be within the specified start + * and length. The style rendering is undefined if the ranges do overlap + * or are ill-defined. Must not be null. + * @exception SWTException+ * NOTE: During the replace operation the current selection is + * changed as follows: + *
+ *+ * The specified line may be a visual (wrapped) line if in word + * wrap mode. The returned object will always be for a logical + * (unwrapped) line. + *
+ * + * @param lineOffset offset of the line. This may be the offset of + * a visual line if the widget is in word wrap mode. + * @param line line text. This may be the text of a visual line if + * the widget is in word wrap mode. + * @return StyledTextEvent that can be used to request line data + * for the given line. + */ +StyledTextEvent sendLineEvent(int eventType, int lineOffset, String line) { + StyledTextEvent event = null; + if (isListening(eventType)) { + event = new StyledTextEvent(content); + event.detail = lineOffset; + event.text = line; + event.alignment = alignment; + event.indent = indent; + event.wrapIndent = wrapIndent; + event.justify = justify; + notifyListeners(eventType, event); + } + return event; +} +/** + * Sends the specified selection event. + */ +void sendSelectionEvent() { + getAccessible().textSelectionChanged(); + Event event = new Event(); + event.x = selection.x; + event.y = selection.y; + notifyListeners(SWT.Selection, event); +} +int sendTextEvent(int left, int right, int lineIndex, String text, boolean fillWithSpaces) { + int lineWidth = 0, start, end; + StringBuilder buffer = new StringBuilder(); + if (lineIndex < content.getLineCount()) { + int[] trailing = new int[1]; + start = getOffsetAtPoint(left, getLinePixel(lineIndex), trailing, true); + if (start == -1) { + int lineOffset = content.getOffsetAtLine(lineIndex); + int lineLegth = content.getLine(lineIndex).length(); + start = end = lineOffset + lineLegth; + if (fillWithSpaces) { + TextLayout layout = renderer.getTextLayout(lineIndex); + lineWidth = layout.getBounds().width; + renderer.disposeTextLayout(layout); + } + } else { + start += trailing[0]; + end = left == right ? start : getOffsetAtPoint(right, 0, lineIndex, null); + fillWithSpaces = false; + } + } else { + start = end = content.getCharCount(); + buffer.append(content.getLineDelimiter()); + } + if (start > end) { + int temp = start; + start = end; + end = temp; + } + if (fillWithSpaces) { + int spacesWidth = left - lineWidth + horizontalScrollOffset - leftMargin; + int spacesCount = spacesWidth / renderer.averageCharWidth; + for (int i = 0; i < spacesCount; i++) { + buffer.append(' '); + } + } + buffer.append(text); + Event event = new Event(); + event.start = start; + event.end = end; + event.text = buffer.toString(); + sendKeyEvent(event); + return event.start + event.text.length(); +} +int sendWordBoundaryEvent(int eventType, int movement, int offset, int newOffset, String lineText, int lineOffset) { + if (isListening(eventType)) { + StyledTextEvent event = new StyledTextEvent(content); + event.detail = lineOffset; + event.text = lineText; + event.count = movement; + event.start = offset; + event.end = newOffset; + notifyListeners(eventType, event); + offset = event.end; + if (offset != newOffset) { + int length = getCharCount(); + if (offset < 0) { + offset = 0; + } else if (offset > length) { + offset = length; + } else { + if (isLineDelimiter(offset)) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + } + return offset; + } + return newOffset; +} +void setAlignment() { + if ((getStyle() & SWT.SINGLE) == 0) return; + int alignment = renderer.getLineAlignment(0, this.alignment); + int newAlignmentMargin = 0; + if (alignment != SWT.LEFT) { + renderer.calculate(0, 1); + int width = renderer.getWidth() - alignmentMargin; + newAlignmentMargin = clientAreaWidth - width; + if (newAlignmentMargin < 0) newAlignmentMargin = 0; + if (alignment == SWT.CENTER) newAlignmentMargin /= 2; + } + if (alignmentMargin != newAlignmentMargin) { + leftMargin -= alignmentMargin; + leftMargin += newAlignmentMargin; + alignmentMargin = newAlignmentMargin; + resetCache(0, 1); + setCaretLocation(); + super.redraw(); + } +} +/** + * Sets the alignment of the widget. The argument should be one ofSWT.LEFT
,
+ * SWT.CENTER
or SWT.RIGHT
. The alignment applies for all lines.
+ *
+ * Note that if SWT.MULTI
is set, then SWT.WRAP
must also be set
+ * in order to stabilize the right edge before setting alignment.
+ *
+ * NOTE: Italic fonts are not supported unless they have no overhang + * and the same baseline as regular fonts. + *
+ * + * @param font new font + * @exception SWTException+ * NOTE: The horizontal index is reset to 0 when new text is set in the + * widget. + *
+ * + * @param offset horizontal scroll offset relative to the start + * of the line, measured in character increments starting at 0, if + * equal to 0 the content is not scrolled, if > 0 = the content is scrolled. + * @exception SWTException+ * NOTE: The horizontal SWT logical point offset is reset to 0 when new text + * is set in the widget. + *
+ * + * @param pixel horizontal SWT logical point offset relative to the start + * of the line. + * @exception SWTException+ * It is the amount of blank space, in points, at the beginning of each line. + * When a line wraps in several lines only the first one is indented. + *
+ * + * @param indent the new indent + * + * @exception SWTException+ * One action can be associated with N keys. However, each key can only + * have one action (key:action is N:1 relation). + *
+ * + * @param key a key code defined in SWT.java or a character. + * Optionally ORd with a state mask. Preferred state masks are one or more of + * SWT.MOD1, SWT.MOD2, SWT.MOD3, since these masks account for modifier platform + * differences. However, there may be cases where using the specific state masks + * (i.e., SWT.CTRL, SWT.SHIFT, SWT.ALT, SWT.COMMAND) makes sense. + * @param action one of the predefined actions defined in ST.java. + * Use SWT.NULL to remove a key binding. + * @exception SWTExceptionSWT.LEFT
,
+ * SWT.CENTER
or SWT.RIGHT
.
+ *
+ * Note that if SWT.MULTI
is set, then SWT.WRAP
must also be set
+ * in order to stabilize the right edge before setting alignment.
+ *
+ * Should not be called if a LineStyleListener has been set since the listener + * maintains the line attributes. + *
+ * All line attributes are maintained relative to the line text, not the + * line index that is specified in this method call. + * During text changes, when entire lines are inserted or removed, the line + * attributes that are associated with the lines after the change + * will "move" with their respective text. An entire line is defined as + * extending from the first character on a line to the last and including the + * line delimiter. + *
+ * When two lines are joined by deleting a line delimiter, the top line + * attributes take precedence and the attributes of the bottom line are deleted. + * For all other text changes line attributes will remain unchanged. + * + * @param startLine first line the alignment is applied to, 0 based + * @param lineCount number of lines the alignment applies to. + * @param alignment line alignment + * + * @exception SWTException+ * The background color is drawn for the width of the widget. All + * line background colors are discarded when setText is called. + * The text background color if defined in a StyleRange overlays the + * line background color. + *
+ * Should not be called if a LineBackgroundListener has been set since the + * listener maintains the line backgrounds. + *
+ * All line attributes are maintained relative to the line text, not the + * line index that is specified in this method call. + * During text changes, when entire lines are inserted or removed, the line + * attributes that are associated with the lines after the change + * will "move" with their respective text. An entire line is defined as + * extending from the first character on a line to the last and including the + * line delimiter. + *
+ * When two lines are joined by deleting a line delimiter, the top line + * attributes take precedence and the attributes of the bottom line are deleted. + * For all other text changes line attributes will remain unchanged. + *
+ * + * @param startLine first line the color is applied to, 0 based + * @param lineCount number of lines the color applies to. + * @param background line background color + * @exception SWTException+ * Should not be called if a LineStyleListener has been set since the listener + * maintains the line attributes. + *
+ * All line attributes are maintained relative to the line text, not the + * line index that is specified in this method call. + * During text changes, when entire lines are inserted or removed, the line + * attributes that are associated with the lines after the change + * will "move" with their respective text. An entire line is defined as + * extending from the first character on a line to the last and including the + * line delimiter. + *
+ * When two lines are joined by deleting a line delimiter, the top line + * attributes take precedence and the attributes of the bottom line are deleted. + * For all other text changes line attributes will remain unchanged. + *
+ * + * @param startLine first line the bullet is applied to, 0 based + * @param lineCount number of lines the bullet applies to. + * @param bullet line bullet + * + * @exception SWTException+ * Should not be called if a LineStyleListener has been set since the listener + * maintains the line attributes. + *
+ * All line attributes are maintained relative to the line text, not the + * line index that is specified in this method call. + * During text changes, when entire lines are inserted or removed, the line + * attributes that are associated with the lines after the change + * will "move" with their respective text. An entire line is defined as + * extending from the first character on a line to the last and including the + * line delimiter. + *
+ * When two lines are joined by deleting a line delimiter, the top line + * attributes take precedence and the attributes of the bottom line are deleted. + * For all other text changes line attributes will remain unchanged. + *
+ * + * @param startLine first line the indent is applied to, 0 based + * @param lineCount number of lines the indent applies to. + * @param indent line indent + * + * @exception SWTException+ * Should not be called if a LineStyleListener has been set since the listener + * maintains the line attributes. + *
+ * All line attributes are maintained relative to the line text, not the + * line index that is specified in this method call. + * During text changes, when entire lines are inserted or removed, the line + * attributes that are associated with the lines after the change + * will "move" with their respective text. An entire line is defined as + * extending from the first character on a line to the last and including the + * line delimiter. + *
+ * When two lines are joined by deleting a line delimiter, the top line + * attributes take precedence and the attributes of the bottom line are deleted. + * For all other text changes line attributes will remain unchanged. + *
+ * Setting both line spacing and vertical indent on a line would result in the + * spacing and indent add up for the line. + *
+ * + * @param lineIndex line index the vertical indent is applied to, 0 based + * @param verticalLineIndent vertical line indent + * + * @exception SWTException+ * Should not be called if a LineStyleListener has been set since the listener + * maintains the line attributes. + *
+ * All line attributes are maintained relative to the line text, not the + * line index that is specified in this method call. + * During text changes, when entire lines are inserted or removed, the line + * attributes that are associated with the lines after the change + * will "move" with their respective text. An entire line is defined as + * extending from the first character on a line to the last and including the + * line delimiter. + *
+ * When two lines are joined by deleting a line delimiter, the top line + * attributes take precedence and the attributes of the bottom line are deleted. + * For all other text changes line attributes will remain unchanged. + *
+ * + * @param startLine first line the justify is applied to, 0 based + * @param lineCount number of lines the justify applies to. + * @param justify true if lines should be justified + * + * @exception SWTException
+ * Should not be called if a LineStyleListener
has been set since the listener
+ * maintains the line attributes.
+ *
+ * All line attributes are maintained relative to the line text, not the + * line index that is specified in this method call. + * During text changes, when entire lines are inserted or removed, the line + * attributes that are associated with the lines after the change + * will "move" with their respective text. An entire line is defined as + * extending from the first character on a line to the last and including the + * line delimiter. + *
+ * When two lines are joined by deleting a line delimiter, the top line + * attributes take precedence and the attributes of the bottom line are deleted. + * For all other text changes line attributes will remain unchanged. + *
+ * + * @param startLine first line the justify is applied to, 0 based + * @param lineCount number of lines the justify applies to. + * @param tabStops tab stops + * + * @exception SWTException
+ * Should not be called if a LineStyleListener
has been set since the listener
+ * maintains the line attributes.
+ *
+ * All line attributes are maintained relative to the line text, not the + * line index that is specified in this method call. + * During text changes, when entire lines are inserted or removed, the line + * attributes that are associated with the lines after the change + * will "move" with their respective text. An entire line is defined as + * extending from the first character on a line to the last and including the + * line delimiter. + *
+ * When two lines are joined by deleting a line delimiter, the top line + * attributes take precedence and the attributes of the bottom line are deleted. + * For all other text changes line attributes will remain unchanged. + *
+ * + * @param startLine first line the wrap indent is applied to, 0 based + * @param lineCount number of lines the wrap indent applies to. + * @param wrapIndent line wrap indent + * + * @exception SWTExceptionSWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
+ *
+ * @param orientation new orientation style
+ *
+ * @exception SWTException + * Indexing is zero based. Text selections are specified in terms of + * caret positions. In a text widget that contains N characters, there are + * N+1 caret positions, ranging from 0..N + *
+ * + * @param point x=selection start offset, y=selection end offset + * The caret will be placed at the selection start when x > y. + * @see #setSelection(int,int) + * @exception SWTException+ * Note that this is a HINT. Some platforms do not allow the application + * to change the selection foreground color. + *
+ * @param color the new color (or null) + * + * @exception IllegalArgumentException+ * Indexing is zero based. Text selections are specified in terms of + * caret positions. In a text widget that contains N characters, there are + * N+1 caret positions, ranging from 0..N + *
+ * + * @param start selection start offset. The caret will be placed at the + * selection start when start > end. + * @param end selection end offset + * @see #setSelectionRange(int,int) + * @exception SWTException+ * The new selection may not be visible. Call showSelection to scroll + * the selection into view. + *
+ * + * @param start offset of the first selected character, start >= 0 must be true. + * @param length number of characters to select, 0 <= start + length + * <= getCharCount() must be true. + * A negative length places the caret at the selection start. + * @param sendEvent a Selection event is sent when set to true and when + * the selection is reset. + */ +void setSelection(int start, int length, boolean sendEvent, boolean doBlock) { + int end = start + length; + if (start > end) { + int temp = end; + end = start; + start = temp; + } + // is the selection range different or is the selection direction + // different? + if (selection.x != start || selection.y != end || + (length > 0 && selectionAnchor != selection.x) || + (length < 0 && selectionAnchor != selection.y)) { + if (blockSelection && doBlock) { + if (length < 0) { + setBlockSelectionOffset(end, start, sendEvent); + } else { + setBlockSelectionOffset(start, end, sendEvent); + } + } else { + int oldStart = selection.x; + int oldLength = selection.y - selection.x; + int charCount = content.getCharCount(); + // called internally to remove selection after text is removed + // therefore make sure redraw range is valid. + int redrawX = Math.min(selection.x, charCount); + int redrawY = Math.min(selection.y, charCount); + if (length < 0) { + selectionAnchor = selection.y = end; + selection.x = start; + setCaretOffset(start, PREVIOUS_OFFSET_TRAILING); + } else { + selectionAnchor = selection.x = start; + selection.y = end; + setCaretOffset(end, PREVIOUS_OFFSET_TRAILING); + } + redrawX = Math.min(redrawX, selection.x); + redrawY = Math.max(redrawY, selection.y); + if (redrawY - redrawX > 0) { + internalRedrawRange(redrawX, redrawY - redrawX); + } + if (sendEvent && (oldLength != end - start || (oldLength != 0 && oldStart != start))) { + sendSelectionEvent(); + } + sendAccessibleTextCaretMoved(); + } + } +} +/** + * Sets the selection. + *+ * The new selection may not be visible. Call showSelection to scroll the selection + * into view. A negative length places the caret at the visual start of the selection. + *
+ * + * @param start offset of the first selected character + * @param length number of characters to select + * + * @exception SWTException+ * The new style overwrites existing styles for the specified range. + * Existing style ranges are adjusted if they partially overlap with + * the new style. To clear an individual style, call setStyleRange + * with a StyleRange that has null attributes. + *
+ * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * + * @param range StyleRange object containing the style information. + * Overwrites the old style in the given range. May be null to delete + * all styles. + * @exception SWTExceptionstart
and
+ * length
and adds the new styles.
+ * + * The ranges array contains start and length pairs. Each pair refers to + * the corresponding style in the styles array. For example, the pair + * that starts at ranges[n] with length ranges[n+1] uses the style + * at styles[n/2]. The range fields within each StyleRange are ignored. + * If ranges or styles is null, the specified range is cleared. + *
+ * Note: It is expected that the same instance of a StyleRange will occur + * multiple times within the styles array, reducing memory usage. + *
+ * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * + * @param start offset of first character where styles will be deleted + * @param length length of the range to delete styles in + * @param ranges the array of ranges. The ranges must not overlap and must be in order. + * @param styles the array of StyleRanges. The range fields within the StyleRange are unused. + * + * @exception SWTException+ * All styles in the widget will be replaced with the given set of ranges and styles. + * The ranges array contains start and length pairs. Each pair refers to + * the corresponding style in the styles array. For example, the pair + * that starts at ranges[n] with length ranges[n+1] uses the style + * at styles[n/2]. The range fields within each StyleRange are ignored. + * If either argument is null, the styles are cleared. + *
+ * Note: It is expected that the same instance of a StyleRange will occur + * multiple times within the styles array, reducing memory usage. + *
+ * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * + * @param ranges the array of ranges. The ranges must not overlap and must be in order. + * @param styles the array of StyleRanges. The range fields within the StyleRange are unused. + * + * @exception SWTException
+ * Note: Because a StyleRange includes the start and length, the
+ * same instance cannot occur multiple times in the array of styles.
+ * If the same style attributes, such as font and color, occur in
+ * multiple StyleRanges, setStyleRanges(int[], StyleRange[])
+ * can be used to share styles and reduce memory usage.
+ *
+ * Should not be called if a LineStyleListener has been set since the + * listener maintains the styles. + *
+ * + * @param ranges StyleRange objects containing the style information. + * The ranges should not overlap. The style rendering is undefined if + * the ranges do overlap. Must not be null. The styles need to be in order. + * @exception SWTException+ * Note: Only a single line of text should be set when the SWT.SINGLE + * style is used. + *
+ * + * @param text new widget content. Replaces existing content. Line styles + * that were set using StyledText API are discarded. The + * current selection is also discarded. + * @exception SWTExceptionSWT.LEFT_TO_RIGHT
or
+ * SWT.RIGHT_TO_LEFT
.
+ *
+ * setOrientation
would override this value with the text direction
+ * that is consistent with the new orientation.
+ *
+ * Warning: This API is currently only implemented on Windows. + * It doesn't set the base text direction on GTK and Cocoa. + *
+ * + * @param textDirection the base text direction style + * + * @exception SWTException+ * The text limit specifies the amount of text that + * the user can type into the widget. + *
+ * + * @param limit the new text limit. + * @exception SWTException+ * The top index is the index of the line that is currently at the top + * of the widget. The top index changes when the widget is scrolled. + * Indexing starts from zero. + * Note: The top index is reset to 0 when new text is set in the widget. + *
+ * + * @param topIndex new top index. Must be between 0 and + * getLineCount() - fully visible lines per page. If no lines are fully + * visible the maximum value is getLineCount() - 1. An out of range + * index will be adjusted accordingly. + * @exception SWTException+ * The top point offset is the vertical SWT logical point offset of the widget. The + * widget is scrolled so that the given SWT logical point position is at the top. + * The top index is adjusted to the corresponding top line. + * Note: The top point is reset to 0 when new text is set in the widget. + *
+ * + * @param pixel new top point offset. Must be between 0 and + * (getLineCount() - visible lines per page) / getLineHeight()). An out + * of range offset will be adjusted accordingly. + * @exception SWTException+ * This overrides the creation style bit SWT.WRAP. + *
+ * + * @param wrap true=widget wraps lines, false=widget does not wrap lines + * @since 2.0 + */ +public void setWordWrap(boolean wrap) { + checkWidget(); + if ((getStyle() & SWT.SINGLE) != 0) return; + if (wordWrap == wrap) return; + if (wordWrap && blockSelection) setBlockSelection(false); + wordWrap = wrap; + resetCache(0, content.getLineCount()); + horizontalScrollOffset = 0; + ScrollBar horizontalBar = getHorizontalBar(); + if (horizontalBar != null) { + horizontalBar.setVisible(!wordWrap); + } + setScrollBars(true); + setCaretLocation(); + super.redraw(); +} +/** + * Sets the wrap line indentation of the widget. + *+ * It is the amount of blank space, in points, at the beginning of each wrapped line. + * When a line wraps in several lines all the lines but the first one is indented + * by this amount. + *
+ * + * @param wrapIndent the new wrap indent + * + * @exception SWTException+ * The end of the selection will be scrolled into view. + * Note that if a right-to-left selection exists, the end of the selection is + * the visual beginning of the selection (i.e., where the caret is located). + *
+ * + * @exception SWTException+ * If the selection intersects with the replaced text, the selection is + * reset and the caret moved to the end of the new text. + * If the selection is behind the replaced text it is moved so that the + * same text remains selected. If the selection is before the replaced text + * it is left unchanged. + *
+ * + * @param startOffset offset of the text change + * @param replacedLength length of text being replaced + * @param newLength length of new text + */ +void updateSelection(int startOffset, int replacedLength, int newLength) { + if (selection.y <= startOffset) { + // selection ends before text change + if (isWordWrap()) setCaretLocation(); + return; + } + if (selection.x < startOffset) { + // clear selection fragment before text change + internalRedrawRange(selection.x, startOffset - selection.x); + } + if (selection.y > startOffset + replacedLength && selection.x < startOffset + replacedLength) { + // clear selection fragment after text change. + // do this only when the selection is actually affected by the + // change. Selection is only affected if it intersects the change (1GDY217). + int netNewLength = newLength - replacedLength; + int redrawStart = startOffset + newLength; + internalRedrawRange(redrawStart, selection.y + netNewLength - redrawStart); + } + if (selection.y > startOffset && selection.x < startOffset + replacedLength) { + // selection intersects replaced text. set caret behind text change + setSelection(startOffset + newLength, 0, true, false); + } else { + // move selection to keep same text selected + setSelection(selection.x + newLength - replacedLength, selection.y - selection.x, true, false); + } + setCaretLocation(); +} +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextContent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextContent.java new file mode 100644 index 000000000..72a12b0ac --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextContent.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.custom; + + +/** + * Clients may implement the StyledTextContent interface to provide a + * custom store for the StyledText widget content. The StyledText widget + * interacts with its StyledTextContent in order to access and update + * the text that is being displayed and edited in the widget. + * A custom content implementation can be set in the widget using the + * StyledText.setContent API. + */ +public interface StyledTextContent { + +/** + * Called by StyledText to add itself as an Observer to content changes. + * See TextChangeListener for a description of the listener methods that + * are called when text changes occur. + *+ * + * @param listener the listener + * @exception IllegalArgumentException
+ * + * @return the number of characters in the content. + */ +public int getCharCount(); + +/** + * Return the line at the given line index without delimiters. + *
+ * + * @param lineIndex index of the line to return. Does not include + * delimiters of preceding lines. Index 0 is the first line of the + * content. + * @return the line text without delimiters + * For example, if text = "\r\n\r\n", and delimiter = "\r\n", then: + *
+ * + * @param offset offset of the line to return. The first character of the + * document is at offset 0. An offset of {@link #getCharCount()} is valid + * and should answer the line index of the last line. + * @return the line index. The first line is at index 0. If the character + * at offset is a delimiter character, answer the line index of the line + * that is delimited. + * For example, if text = "\r\n\r\n", and delimiter = "\r\n", then: + *
+ * + * @return the number of lines. For example: + *
+ * + * @return the line delimiter that should be used by the StyledText widget + * when inserting new lines. + */ +public String getLineDelimiter(); + +/** + * Return the character offset of the first character of the given line. + *
+ * NOTE: When there is no text (i.e., no lines), getOffsetAtLine(0) + * is a valid call that should return 0. + *
+ * + * @param lineIndex index of the line. The first line is at index 0. + * @return offset offset of the first character of the line. The first + * character of the document is at offset 0. The return value should + * include line delimiters. + * For example, if text = "\r\ntest\r\n" and delimiter = "\r\n", then: + *+ * + * @param start the start offset of the text to return. Offset 0 is the + * first character of the document. + * @param length the length of the text to return + * @return the text at the given range + */ +public String getTextRange(int start, int length); + +/** + * Remove the specified text changed listener. + *
+ * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException
+ * Implementors have to notify the TextChangeListeners that were added
+ * using addTextChangeListener
before and after the content
+ * is changed. A TextChangingEvent
has to be sent to the
+ * textChanging method before the content is changed and a
+ * TextChangedEvent
has to be sent to the textChanged method
+ * after the content has changed.
+ * The text change that occurs after the TextChangingEvent
+ * has been sent has to be consistent with the data provided in the
+ * TextChangingEvent
.
+ * This data will be cached by the widget and will be used when the
+ * TextChangedEvent
is received.
+ *
+ * The TextChangingEvent
should be set as follows:
+ *
TextChangedEvent
to the
+ * textSet method of the TextChangeListeners that were added using
+ * addTextChangeListener
.
+ *
+ *
+ * @param text the new text
+ * @see TextChangeListener
+ */
+public void setText(String text);
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextDropTargetEffect.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextDropTargetEffect.java
new file mode 100644
index 000000000..675cad903
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextDropTargetEffect.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.dnd.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This adapter class provides a default drag under effect (eg. select and scroll)
+ * when a drag occurs over a StyledText
.
+ *
+ *
Classes that wish to provide their own drag under effect for a StyledText
+ * can extend this class, override the StyledTextDropTargetEffect.dragOver
+ * method and override any other applicable methods in StyledTextDropTargetEffect
to
+ * display their own drag under effect.
super
method to get the default drag under effect implementation.
+ *
+ * The feedback value is either one of the FEEDBACK constants defined in
+ * class DND
which is applicable to instances of this class,
+ * or it must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those DND
effect constants.
+ *
StyledTextDropTargetEffect
to handle the drag under effect on the specified
+ * StyledText
.
+ *
+ * @param styledText the StyledText
over which the user positions the cursor to drop the data
+ */
+ public StyledTextDropTargetEffect(StyledText styledText) {
+ super(styledText);
+ paintListener = event -> {
+ if (currentOffset != -1) {
+ StyledText text = (StyledText) getControl();
+ Point position = text.getLocationAtOffset(currentOffset);
+ int height = text.getLineHeight(currentOffset);
+ event.gc.setBackground(event.display.getSystemColor (SWT.COLOR_BLACK));
+ event.gc.fillRectangle(position.x, position.y, CARET_WIDTH, height);
+ }
+ };
+ }
+
+ /**
+ * This implementation of dragEnter
provides a default drag under effect
+ * for the feedback specified in event.feedback
.
+ *
+ * For additional information see DropTargetAdapter.dragEnter
.
+ *
+ * Subclasses that override this method should call super.dragEnter(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag start event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ @Override
+ public void dragEnter(DropTargetEvent event) {
+ currentOffset = -1;
+ scrollBeginTime = 0;
+ scrollX = -1;
+ scrollY = -1;
+ getControl().removeListener(SWT.Paint, paintListener);
+ getControl().addListener (SWT.Paint, paintListener);
+ }
+
+ /**
+ * This implementation of dragLeave
provides a default drag under effect
+ * for the feedback specified in event.feedback
.
+ *
+ * For additional information see DropTargetAdapter.dragLeave
.
+ *
+ * Subclasses that override this method should call super.dragLeave(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag leave event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ @Override
+ public void dragLeave(DropTargetEvent event) {
+ StyledText text = (StyledText) getControl();
+ if (currentOffset != -1) {
+ refreshCaret(text, currentOffset, -1);
+ }
+ text.removeListener(SWT.Paint, paintListener);
+ scrollBeginTime = 0;
+ scrollX = -1;
+ scrollY = -1;
+ }
+
+ /**
+ * This implementation of dragOver
provides a default drag under effect
+ * for the feedback specified in event.feedback
.
+ *
+ * For additional information see DropTargetAdapter.dragOver
.
+ *
+ * Subclasses that override this method should call super.dragOver(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag over event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ * @see DND#FEEDBACK_SELECT
+ * @see DND#FEEDBACK_SCROLL
+ */
+ @Override
+ public void dragOver(DropTargetEvent event) {
+ int effect = event.feedback;
+ StyledText text = (StyledText) getControl();
+
+ Point pt = text.getDisplay().map(null, text, event.x, event.y);
+ if ((effect & DND.FEEDBACK_SCROLL) == 0) {
+ scrollBeginTime = 0;
+ scrollX = scrollY = -1;
+ } else {
+ if (text.getCharCount() == 0) {
+ scrollBeginTime = 0;
+ scrollX = scrollY = -1;
+ } else {
+ if (scrollX != -1 && scrollY != -1 && scrollBeginTime != 0 &&
+ (pt.x >= scrollX && pt.x <= (scrollX + SCROLL_TOLERANCE) ||
+ pt.y >= scrollY && pt.y <= (scrollY + SCROLL_TOLERANCE))) {
+ if (System.currentTimeMillis() >= scrollBeginTime) {
+ Rectangle area = text.getClientArea();
+ GC gc = new GC(text);
+ FontMetrics fm = gc.getFontMetrics();
+ gc.dispose();
+ double charWidth = fm.getAverageCharacterWidth();
+ int scrollAmount = (int) (10*charWidth);
+ if (pt.x < area.x + 3*charWidth) {
+ int leftPixel = text.getHorizontalPixel();
+ text.setHorizontalPixel(leftPixel - scrollAmount);
+ }
+ if (pt.x > area.width - 3*charWidth) {
+ int leftPixel = text.getHorizontalPixel();
+ text.setHorizontalPixel(leftPixel + scrollAmount);
+ }
+ int lineHeight = text.getLineHeight();
+ if (pt.y < area.y + lineHeight) {
+ int topPixel = text.getTopPixel();
+ text.setTopPixel(topPixel - lineHeight);
+ }
+ if (pt.y > area.height - lineHeight) {
+ int topPixel = text.getTopPixel();
+ text.setTopPixel(topPixel + lineHeight);
+ }
+ scrollBeginTime = 0;
+ scrollX = scrollY = -1;
+ }
+ } else {
+ scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+ scrollX = pt.x;
+ scrollY = pt.y;
+ }
+ }
+ }
+
+ if ((effect & DND.FEEDBACK_SELECT) != 0) {
+ int[] trailing = new int [1];
+ int newOffset = text.getOffsetAtPoint(pt.x, pt.y, trailing, false);
+ newOffset += trailing [0];
+ if (newOffset != currentOffset) {
+ refreshCaret(text, currentOffset, newOffset);
+ currentOffset = newOffset;
+ }
+ }
+ }
+
+ void refreshCaret(StyledText text, int oldOffset, int newOffset) {
+ if (oldOffset != newOffset) {
+ if (oldOffset != -1) {
+ Point oldPos = text.getLocationAtOffset(oldOffset);
+ int oldHeight = text.getLineHeight(oldOffset);
+ text.redraw (oldPos.x, oldPos.y, CARET_WIDTH, oldHeight, false);
+ }
+ if (newOffset != -1) {
+ Point newPos = text.getLocationAtOffset(newOffset);
+ int newHeight = text.getLineHeight(newOffset);
+ text.redraw (newPos.x, newPos.y, CARET_WIDTH, newHeight, false);
+ }
+ }
+ }
+
+ /**
+ * This implementation of dropAccept
provides a default drag under effect
+ * for the feedback specified in event.feedback
.
+ *
+ * For additional information see DropTargetAdapter.dropAccept
.
+ *
+ * Subclasses that override this method should call super.dropAccept(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drop accept event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ @Override
+ public void dropAccept(DropTargetEvent event) {
+ if (currentOffset != -1) {
+ StyledText text = (StyledText) getControl();
+ text.setSelection(currentOffset);
+ currentOffset = -1;
+ }
+ }
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextEvent.java
new file mode 100644
index 000000000..7004d371e
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextEvent.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ *
+ */
+class StyledTextEvent extends Event {
+ // used by LineStyleEvent
+ int[] ranges;
+ StyleRange[] styles;
+ int alignment;
+ int indent;
+ int verticalIndent;
+ int wrapIndent;
+ boolean justify;
+ Bullet bullet;
+ int bulletIndex;
+ int[] tabStops;
+ // used by LineBackgroundEvent
+ Color lineBackground;
+ // used by TextChangedEvent
+ int replaceCharCount;
+ int newCharCount;
+ int replaceLineCount;
+ int newLineCount;
+ // used by PaintObjectEvent
+ int x;
+ int y;
+ int ascent;
+ int descent;
+ StyleRange style;
+
+StyledTextEvent (StyledTextContent content) {
+ super();
+ data = content;
+}
+}
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextLineSpacingProvider.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextLineSpacingProvider.java
new file mode 100644
index 000000000..430a77d6b
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextLineSpacingProvider.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2017 Angelo ZERR.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Angelo Zerr + * The following example prints a right aligned page number in the footer, + * sets the job name to "Example" and prints line background colors but no other + * formatting: + *
+ *+ * StyledTextPrintOptions options = new StyledTextPrintOptions(); + * options.footer = "\t\t<page>"; + * options.jobName = "Example"; + * options.printLineBackground = true; + * + * Runnable runnable = styledText.print(new Printer(), options); + * runnable.run(); + *+ * + * @see Sample code and further information + * + * @since 2.1 + */ +public class StyledTextPrintOptions { + /** + * Page number placeholder constant for use in
header
+ * and footer
. Value is <page>
+ */
+ public static final String PAGE_TAG = "header
and
+ * footer
. Value is \t
+ */
+ public static final String SEPARATOR = "\t";
+ /**
+ * Formatted text to print in the header of each page.
+ * "left '\t' center '\t' right"
+ *left, center, right = <page> | #CDATA
+ *Header and footer are defined as three separate regions for arbitrary
+ * text or the page number placeholder <page>
+ * (StyledTextPrintOptions.PAGE_TAG
). The three regions are
+ * left aligned, centered and right aligned. They are separated by a tab
+ * character (StyledTextPrintOptions.SEPARATOR
).
+ */
+ public String header = null;
+ /**
+ * Formatted text to print in the footer of each page.
+ *
"left '\t' center '\t' right"
+ *left, center, right = <page> | #CDATA
+ *Header and footer are defined as three separate regions for arbitrary
+ * text or the page number placeholder <page>
+ * (
+ * For a detailed example of using a TableCursor to navigate to a cell and then edit it see
+ * http://git.eclipse.org/c/platform/eclipse.platform.swt.git/tree/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet96.java .
+ *
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * When
+ * Note: This operation is a hint and may be overridden by the platform.
+ * For example, on Windows the background of a Button cannot be changed.
+ *
+ * Note: This operation is a hint and may be overridden by the platform.
+ * Here is an example of using a TableEditor: Note: The Control provided as the editor must be created with its parent being the Table control
+* specified in the TableEditor constructor.
+*
+* @param editor the Control that is displayed above the cell being edited
+* @param item the TableItem for the row of the cell being tracked by this editor
+* @param column the zero based index of the column of the cell being tracked by this editor
+*/
+public void setEditor (Control editor, TableItem item, int column) {
+ setItem(item);
+ setColumn(column);
+ setEditor(editor);
+}
+@Override
+public void layout () {
+ if (table == null || table.isDisposed()) return;
+ if (item == null || item.isDisposed()) return;
+ int columnCount = table.getColumnCount();
+ if (columnCount == 0 && column != 0) return;
+ if (columnCount > 0 && (column < 0 || column >= columnCount)) return;
+ super.layout();
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TextChangeListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TextChangeListener.java
new file mode 100644
index 000000000..0585f6ee5
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TextChangeListener.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+
+import org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * The StyledText widget implements this listener to receive
+ * notifications when changes to the model occur.
+ * It is not intended to be implemented by clients or by
+ * implementors of StyledTextContent.
+ * Clients should listen to the ModifyEvent or ExtendedModifyEvent
+ * that is sent by the StyledText widget to receive text change
+ * notifications.
+ * Implementors of StyledTextContent should call the textChanging
+ * and textChanged methods when text changes occur as described
+ * below. If the entire text is replaced the textSet method
+ * should be called instead.
+ */
+public interface TextChangeListener extends SWTEventListener {
+
+/**
+ * This method is called when the content is about to be changed.
+ * Callers also need to call the textChanged method after the
+ * content change has been applied. The widget only updates the
+ * screen properly when it receives both events.
+ *
+ * @param event the text changing event. All event fields need
+ * to be set by the sender.
+ * @see TextChangingEvent
+ */
+public void textChanging(TextChangingEvent event);
+/**
+ * This method is called when the content has changed.
+ * Callers need to have called the textChanging method prior to
+ * applying the content change and calling this method. The widget
+ * only updates the screen properly when it receives both events.
+ *
+ * @param event the text changed event
+ */
+public void textChanged(TextChangedEvent event);
+/**
+ * This method is called instead of the textChanging/textChanged
+ * combination when the entire old content has been replaced
+ * (e.g., by a call to StyledTextContent.setText()).
+ *
+ * @param event the text changed event
+ */
+public void textSet(TextChangedEvent event);
+}
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TextChangedEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TextChangedEvent.java
new file mode 100644
index 000000000..ba38beefa
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TextChangedEvent.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.events.*;
+
+/**
+ * This event is sent by the StyledTextContent implementor when a change to
+ * the text occurs.
+ *
+ * @see Sample code and further information
+ */
+public class TextChangedEvent extends TypedEvent {
+
+ static final long serialVersionUID = 3258696524257835065L;
+
+/**
+ * Create the TextChangedEvent to be used by the StyledTextContent implementor.
+ *
+ *
+ * @param source the object that will be sending the TextChangedEvent,
+ * cannot be null
+ */
+public TextChangedEvent(StyledTextContent source) {
+ super(source);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TextChangingEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TextChangingEvent.java
new file mode 100644
index 000000000..d5ddd64ba
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TextChangingEvent.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+
+import org.eclipse.swt.events.*;
+
+/**
+ * This event is sent by the StyledTextContent implementor when a change
+ * to the text is about to occur.
+ *
+ * @see Sample code and further information
+ */
+public class TextChangingEvent extends TypedEvent {
+ /**
+ * Start offset of the text that is going to be replaced
+ */
+ public int start;
+ /**
+ * Text that is going to be inserted or empty string
+ * if no text will be inserted
+ */
+ public String newText;
+ /**
+ * Length of text that is going to be replaced
+ */
+ public int replaceCharCount;
+ /**
+ * Length of text that is going to be inserted
+ */
+ public int newCharCount;
+ /**
+ * Number of lines that are going to be replaced
+ */
+ public int replaceLineCount;
+ /**
+ * Number of new lines that are going to be inserted
+ */
+ public int newLineCount;
+
+ static final long serialVersionUID = 3257290210114352439L;
+
+/**
+ * Create the TextChangedEvent to be used by the StyledTextContent implementor.
+ *
+ *
+ * @param source the object that will be sending the new TextChangingEvent,
+ * cannot be null
+ */
+public TextChangingEvent(StyledTextContent source) {
+ super(source);
+}
+TextChangingEvent(StyledTextContent source, StyledTextEvent e) {
+ super(source);
+ start = e.start;
+ replaceCharCount = e.replaceCharCount;
+ newCharCount = e.newCharCount;
+ replaceLineCount = e.replaceLineCount;
+ newLineCount = e.newLineCount;
+ newText = e.text;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TreeCursor.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TreeCursor.java
new file mode 100644
index 000000000..051dee6e8
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TreeCursor.java
@@ -0,0 +1,957 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.accessibility.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * A TreeCursor provides a way for the user to navigate around a Tree with columns using the
+ * keyboard. It also provides a mechanism for selecting an individual cell in a tree.
+ *
+ * For a detailed example of using a TreeCursor to navigate to a cell and then edit it see
+ * http://git.eclipse.org/c/platform/eclipse.platform.swt.git/tree/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet360.java .
+ *
+ *
+ * The style value is either one of the style constants defined in class
+ * When
+ * Note: This operation is a hint and may be overridden by the platform.
+ * For example, on Windows the background of a Button cannot be changed.
+ *
+ * Note: This operation is a hint and may be overridden by the platform.
+ * Here is an example of using a TreeEditor: Note: The Control provided as the editor must be created with its parent being the Tree control
+* specified in the TreeEditor constructor.
+*
+* @param editor the Control that is displayed above the cell being edited
+* @param item the TreeItem for the row of the cell being tracked by this editor
+* @param column the zero based index of the column of the cell being tracked by this editor
+*
+* @since 3.1
+*/
+public void setEditor (Control editor, TreeItem item, int column) {
+ setItem(item);
+ setColumn(column);
+ setEditor(editor);
+}
+@Override
+public void setEditor (Control editor) {
+ super.setEditor(editor);
+ resize();
+}
+
+/**
+* Specify the Control that is to be displayed and the cell in the tree that it is to be positioned above.
+*
+* Note: The Control provided as the editor must be created with its parent being the Tree control
+* specified in the TreeEditor constructor.
+*
+* @param editor the Control that is displayed above the cell being edited
+* @param item the TreeItem for the row of the cell being tracked by this editor
+*/
+public void setEditor (Control editor, TreeItem item) {
+ setItem(item);
+ setEditor(editor);
+}
+
+@Override
+public void layout () {
+ if (tree == null || tree.isDisposed()) return;
+ if (item == null || item.isDisposed()) return;
+ int columnCount = tree.getColumnCount();
+ if (columnCount == 0 && column != 0) return;
+ if (columnCount > 0 && (column < 0 || column >= columnCount)) return;
+ super.layout();
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/VerifyKeyListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/VerifyKeyListener.java
new file mode 100644
index 000000000..c2852315a
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/VerifyKeyListener.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.internal.*;
+
+/**
+ * Classes which implement this interface provide a method
+ * that deals with the event that is generated when a
+ * key is pressed.
+ *
+ * @see VerifyEvent
+ * @see Sample code and further information
+ */
+@FunctionalInterface
+public interface VerifyKeyListener extends SWTEventListener {
+/**
+ * The following event fields are used:
+ * Note that although this class is a subclass of
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: No Layout can be set on this Control because it already
+ * manages the size and position of its children.
+ * If the data you are converting does not map to a
+ * The following snippet shows a subclass of ByteArrayTransfer that transfers
+ * data defined by the class IMPORTANT: This class is not intended to be subclassed.
+ * The SWT class library is intended to be subclassed
+ * only at specific, controlled points. This method enforces this
+ * rule unless it is overridden.
+ *
+ * IMPORTANT: By providing an implementation of this
+ * method that allows a subclass of a class which does not
+ * normally allow subclassing to be created, the implementer
+ * agrees to be fully responsible for the fact that any such
+ * subclass will likely fail between SWT releases and will be
+ * strongly platform specific. No support is provided for
+ * user-written classes which are implemented in this fashion.
+ *
+ * The ability to subclass outside of the allowed SWT classes
+ * is intended purely to enable those not on the SWT development
+ * team to implement patches in order to get around specific
+ * limitations in advance of when those limitations can be
+ * addressed by the team. Subclassing should not be attempted
+ * without an intimate and detailed understanding of the hierarchy.
+ *
+ * Currently, it is an error to invoke any method (other than
+ *
+ * In future releases of SWT, there may be more or fewer error
+ * checks and exceptions may be thrown for different reasons.
+ * Note that there are clipboard assistant applications that take ownership
+ * of data or make copies of data when it is placed on the clipboard. In these
+ * cases, it may not be possible to clear the clipboard. The clipboards value is either one of the clipboard constants defined in
+ * class NOTE: On some platforms the data will not be available once the application
+ * has exited or the display has been disposed. The following snippet shows text and RTF text being retrieved from the
+ * clipboard: The following snippet shows text and RTF text being retrieved from the
+ * clipboard: The clipboards value is either one of the clipboard constants defined in
+ * class
+ * This method gets the dispose state for the clipboard.
+ * When a clipboard has been disposed, it is an error to
+ * invoke any other method using the clipboard.
+ * NOTE: On some platforms, the data is immediately copied to the system
+ * clipboard but on other platforms it is provided upon request. As a result,
+ * if the application modifies the data object it has set on the clipboard, that
+ * modification may or may not be available when the data is subsequently
+ * requested. The following snippet shows text and RTF text being set on the copy/paste
+ * clipboard:
+ * NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility. NOTE: On some platforms, the data is immediately copied to the specified
+ * clipboard but on other platforms it is provided upon request. As a result,
+ * if the application modifies the data object it has set on the clipboard, that
+ * modification may or may not be available when the data is subsequently
+ * requested. The clipboards value is either one of the clipboard constants defined in
+ * class The following snippet shows text and RTF text being set on the copy/paste
+ * clipboard:
+ * NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility. The clipboards value is either one of the clipboard constants defined in
+ * class Note:
+ * Warning: Some applications (most notably Firefox, Thunderbird, and Safari) return
+ * {@link DND#DROP_MOVE} even if they just open a dropped file and don't copy
+ * anything, see bug 30543.
+ *
+ * To avoid data loss, you may want to not remove the original data
+ * when you handle a {@link DND#DragEnd} for a {@link FileTransfer} whose
+ * {@link org.eclipse.swt.widgets.Event#detail} is {@link #DROP_MOVE}.
+ *
+ * In DND, errors are reported by throwing one of three exceptions:
+ * This method provides the logic which maps between error codes
+ * and one of the above exceptions.
+ * IMPORTANT: This class is not intended to be subclassed. A drag source is the object which originates a drag and drop operation. For the specified widget,
+ * it defines the type of data that is available for dragging and the set of operations that can
+ * be performed on that data. The operations can be any bit-wise combination of DND.MOVE, DND.COPY or
+ * DND.LINK. The type of data that can be transferred is specified by subclasses of Transfer such as
+ * TextTransfer or FileTransfer. The type of data transferred can be a predefined system type or it
+ * can be a type defined by the application. For instructions on how to define your own transfer type,
+ * refer to You may have several DragSources in an application but you can only have one DragSource
+ * per Control. Data dragged from this DragSource can be dropped on a site within this application
+ * or it can be dropped on another application such as an external Text editor. The application supplies the content of the data being transferred by implementing the
+ * When a successful move operation occurs, the application is required to take the appropriate
+ * action to remove the data from its display and remove any associated operating system resources or
+ * internal references. Typically in a move operation, the drop target makes a copy of the data
+ * and the drag source deletes the original. However, sometimes copying the data can take a long
+ * time (such as copying a large file). Therefore, on some platforms, the drop target may actually
+ * move the data in the operating system rather than make a copy. This is usually only done in
+ * file transfers. In this case, the drag source is informed in the DragEnd event that a
+ * DROP_TARGET_MOVE was performed. It is the responsibility of the drag source at this point to clean
+ * up its displayed information. No action needs to be taken on the operating system resources. The following example shows a Label widget that allows text to be dragged from it. NOTE: ERROR_CANNOT_INIT_DRAG should be an SWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility. Classes that wish to deal with The drag source effect has the same API as the
+ * Classes that wish to provide their own drag source effect such as
+ * displaying a default source image during a drag can extend the
+ * In dragStart: Flag to determine if the drag and drop operation should proceed.
+ * The application can set this value to false to prevent the drag from starting.
+ * Set to true by default. In dragSetData: This will be set to true when the call to dragSetData is made. Set it to
+ * false to cancel the drag. In dragFinished: Flag to indicate if the operation was performed successfully.
+ * True if the operation was performed successfully. A value of null indicates that no drag image will be displayed. The default value is null. When the user drops data on a After the drop has completed successfully or has been aborted, the application which defines the
+ * The following fields in the DragSourceEvent apply: The following fields in the DragSourceEvent apply: The following fields in the DragSourceEvent apply: IMPORTANT: This class is not intended to be subclassed. This class identifies the The application is notified of data being dragged over this control and of when a drop occurs by
+ * implementing the interface NOTE: ERROR_CANNOT_INIT_DROP should be an SWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.
+ * Classes that wish to deal with
+ * Please note, there are subtle difference in DND behavior on different OS's.
+ * For example during a file transfer, Windows will put out the file path
+ * as soon as the drag begins, where as Linux will make it available only
+ * on a drop operation. For correct crossplatform behavior, it is recommended
+ * to delay OS interaction until drop has occurred or verify the correctness of
+ * the operation across platforms.
+ * The drop target effect has the same API as the
+ * Classes that wish to provide their own drag under effect
+ * can extend the The feedback value is either one of the FEEDBACK constants defined in
+ * class A value of DND.FEEDBACK_NONE indicates that no drag under effect will be displayed. Feedback effects will only be applied if they are applicable. The default value is DND.FEEDBACK_SELECT. As the user moves the cursor into, over and out of a Control that has been designated
+ * as a DropTarget, events indicate what operation can be performed and what data can be
+ * transferred if a drop where to occur at that point.
+ * The application can respond to these events and change the type of data that will
+ * be dropped by modifying event.currentDataType, or change the operation that will be performed
+ * by modifying the event.detail field or stop any drop from happening on the current target
+ * by setting the event.detail field to DND_DROP_NONE. When the user causes a drop to happen by releasing the mouse over a valid drop target,
+ * the application has one last chance to change the data type of the drop through the
+ * DropAccept event. If the drop is still allowed, the DropAccept event is immediately
+ * followed by the Drop event. In the Drop event, the application can still change the
+ * operation that is performed but the data type is fixed. The following fields in the DropTargetEvent apply: The The It is possible to get a DragEnter event when the drag source does not provide any matching data.
+ * In this case, the default operation is DND.DROP_NONE and the currentDataType is null. The application can change the operation that will be performed by modifying the
+ * The application can also change the type of data being requested by
+ * modifying the The following fields in the DropTargetEvent apply: The following fields in the DropTargetEvent apply: The The The application can change the operation that will be performed by modifying the
+ * The application can also change the type of data being requested by modifying
+ * the The following fields in the DropTargetEvent apply: The The The application can change the operation that will be performed by modifying the
+ * The application can also change the type of data being requested by modifying the
+ * NOTE: At this point the The following fields in DropTargetEvent apply: The application can refuse to perform the drop operation by setting the detail
+ * field to DND.DROP_NONE. The following fields in the DropTargetEvent apply: The application can veto the drop by setting the The application can change the operation that will be performed by modifying the
+ * The application can also change the type of data being requested by modifying the
+ * An example of a java
+ * For more information on the {@link CIDA} structure see also {@link #resolveCidaToFilepaths(long)}.
+ * An example of a java An example of a java An example of a java Classes that wish to provide their own source image for a Classes that wish to provide their own drag under effect for a The feedback value is either one of the FEEDBACK constants defined in
+ * class An example of a java Note the You should only need to become familiar with this class if you are
+ * implementing a Transfer subclass and you are unable to subclass the
+ * ByteArrayTransfer class. Only the data type fields of the On a successful conversion, the transferData.result field will be set as follows: If this transfer agent is unable to perform the conversion, the transferData.result
+ * field will be set to a failure value as follows: You may register the same type more than once, the same unique identifier
+ * will be returned if the type has been previously registered. Note: On windows, do not call this method with pre-defined
+ * Clipboard Format types such as CF_TEXT or CF_BITMAP because the
+ * pre-defined identifier will not be returned As an application writer, you do not need to know the specifics of
+ * TransferData. TransferData instances are passed to a subclass of Transfer
+ * and the Transfer object manages the platform specific issues.
+ * You can ask a Transfer subclass if it can handle this data by calling
+ * Transfer.isSupportedType(transferData). You should only need to become familiar with the fields in this class if you
+ * are implementing a Transfer subclass and you are unable to subclass the
+ * ByteArrayTransfer class.
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ *
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ *
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ *
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * The value of result is 1 if the conversion was successful.
+ * The value of result is 0 if the conversion failed.
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * Classes that wish to provide their own source image for a Classes that wish to provide their own drag under effect for a The feedback value is either one of the FEEDBACK constants defined in
+ * class
+ * Note: Only one of the styles FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE or
+ * FEEDBACK_INSERT_AFTER may be specified.
+ * An example of a java
+ * After creating an instance of a class that implements
+ * this interface it can be added to a widget using the
+ *
+ * Classes that wish to deal with
+ * An alternative to this class are the static helper methods
+ * {@link ControlListener#controlMovedAdapter(java.util.function.Consumer)}
+ * and
+ * {@link ControlListener#controlResizedAdapter(java.util.function.Consumer)},
+ * which accept a lambda expression or a method reference that implements the event consumer.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a widget using the
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * Classes that wish to deal with
+ * An alternative to this class are the static helper methods
+ * {@link ExpandListener#itemCollapsedAdapter(java.util.function.Consumer)}
+ * and
+ * {@link ExpandListener#itemExpandedAdapter(java.util.function.Consumer)},
+ * which accept a lambda expression or a method reference that implements the event consumer.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a
+ * Classes that wish to deal with
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * If
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * Warning: This API is currently only implemented on Windows and Cocoa.
+ * SWT doesn't send Gesture or Touch events on GTK.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * Classes that wish to deal with
+ * When a key listener is added to a control, the control
+ * will take part in widget traversal. By default, all
+ * traversal keys (such as the tab key and so on) are
+ * delivered to the control. In order for a control to take
+ * part in traversal, it should listen for traversal events.
+ * Otherwise, the user can traverse into a control but not
+ * out. Note that native controls such as table and tree
+ * implement key traversal in the operating system. It is
+ * not necessary to add traversal listeners for these controls,
+ * unless you want to override the default traversal.
+ *
+ * The location field can be used to differentiate key events that have
+ * the same key code and character but are generated by different keys
+ * on the keyboard. For example, a key down event with the key code equal
+ * to SWT.SHIFT can be generated by the left and the right shift keys on
+ * the keyboard.
+ *
+ * The location field can only be used to determine the location of
+ * the key code or character in the current event. It does not include
+ * information about the location of modifiers in the state mask.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * Classes that wish to deal with
+ * An alternative to this class are the static helper methods
+ * {@link MenuListener#menuHiddenAdapter(java.util.function.Consumer)}
+ * and
+ * {@link MenuListener#menuShownAdapter(java.util.function.Consumer)},
+ * which accept a lambda expression or a method reference that implements the event consumer.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control or TrayItem
+ * using the
+ * After creating an instance of a class that implements
+ * this interface it can be added to a menu using the
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a text widget using the
+ *
+ * Classes that wish to deal with
+ * Note: The
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * Classes that wish to deal with
+ * An alternative to this class are the static helper methods
+ * {@link MouseTrackListener#mouseEnterAdapter(java.util.function.Consumer)},
+ * {@link MouseTrackListener#mouseExitAdapter(java.util.function.Consumer)}
+ * and
+ * {@link MouseTrackListener#mouseHoverAdapter(java.util.function.Consumer)},
+ * which accept a lambda expression or a method reference that implements the event consumer.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * The elements in the segments field specify the start offset of a segment
+ * relative to the start of the text. They must follow the following rules:
+ * The segments field may be left null if the entire text content doesn't
+ * require segmentation.
+ *
+ * The segments and segmentsChars fields can be used together to obtain different
+ * types of bidi reordering and text display. The application can use these two fields
+ * to insert Unicode Control Characters in specific offsets in the text, the character
+ * at segmentsChars[i] is inserted at the offset specified by segments[i]. When both fields
+ * are set, the rules for the segments field are less restrictive:
+ *
+ * The following event fields are used:
+ * Classes that wish to deal with
+ * An alternative to this class are the static helper methods
+ * {@link SelectionListener#widgetSelectedAdapter(java.util.function.Consumer)}
+ * and
+ * {@link SelectionListener#widgetDefaultSelectedAdapter(java.util.function.Consumer)},
+ * which accept a lambda expression or a method reference that implements the event consumer.
+ *
+ * Note: The fields that are filled in depend on the widget.
+ * Sash ScrollBar and Slider Table and Tree Text CoolItem and ToolItem
+ * Note: Mouse button states are currently not included consistently
+ * for all widgets on all platforms. Clients should be prepared to receive
+ * button states, but should not rely on getting them everywhere.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * For example, selection occurs in a List when the user selects
+ * an item or items with the keyboard or mouse. On some platforms,
+ * the event occurs when a mouse button or key is pressed. On others,
+ * it happens when the mouse or key is released. The exact key or
+ * mouse gesture that causes this event is platform specific.
+ *
+ * For example, on some platforms default selection occurs in a List
+ * when the user double-clicks an item or types return in a Text.
+ * On some platforms, the event occurs when a mouse button or key is
+ * pressed. On others, it happens when the mouse or key is released.
+ * The exact key or mouse gesture that causes this event is platform
+ * specific.
+ *
+ * Classes that wish to deal with
+ * An alternative to this class are the static helper methods in
+ * {@link ShellListener},
+ * which accept a lambda expression or a method reference that implements the event consumer.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a shell using the
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * Warning: This API is currently only implemented on Windows and Cocoa.
+ * SWT doesn't send Gesture or Touch events on GTK.
+ *
+ * The traversal event allows fine control over keyboard traversal
+ * in a control both to implement traversal and override the default
+ * traversal behavior defined by the system. This is achieved using
+ * two fields,
+ * When a control is traversed, a traverse event is sent. The detail
+ * describes the type of traversal and the doit field indicates the default
+ * behavior of the system. For example, when a right arrow key is pressed
+ * in a text control, the detail field is
+ * How can the traversal event be used to implement traversal?
+ * When a tab key is pressed in a canvas, the detail field will be
+ *
+ * How can the traversal event be used to override system traversal?
+ * When the return key is pressed in a single line text control, the
+ * detail field is
+ * Note: A widget implementor will typically implement traversal using
+ * only the doit flag to either enable or disable system traversal.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ *
+ * A traverse event occurs when the user presses a traversal
+ * key. Traversal keys are typically tab and arrow keys, along
+ * with certain other keys on some platforms. Traversal key
+ * constants beginning with
+ * Classes that wish to deal with
+ * An alternative to this class are the static helper methods
+ * {@link TreeListener#treeCollapsedAdapter(java.util.function.Consumer)}
+ * and
+ * {@link TreeListener#treeExpandedAdapter(java.util.function.Consumer)},
+ * which accept a lambda expression or a method reference that implements the event consumer.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a tree control using the
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to a text control using the
+ *
+ * A verify event occurs after the user has done something
+ * to modify the text (typically typed a key), but before
+ * the text is modified. The doit field in the verify event
+ * indicates whether or not to modify the text.
+ *
+For contrast, see also the untyped listener support provided
+by class
+ * Application code must explicitly invoke the
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ *
+ * You must dispose the color when it is no longer required.
+ *
+ * You must dispose the color when it is no longer required.
+ *
+ * You must dispose the color when it is no longer required.
+ *
+ * You must dispose the color when it is no longer required.
+ *
+ * You must dispose the color when it is no longer required.
+ *
+ * This method gets the dispose state for the color.
+ * When a color has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the color.
+ *
+ * @return
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * Application code must explicitly invoke the
+ * Note: Only one of the above styles may be specified.
+ *
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ *
+ * You must dispose the cursor when it is no longer required.
+ *
+ * The mask data is allowed to be null, but in this case the source
+ * must be an ImageData representing an icon that specifies both
+ * color data and mask data.
+ *
+ * You must dispose the cursor when it is no longer required.
+ *
+ * You must dispose the cursor when it is no longer required.
+ *
+ * This method gets the dispose state for the cursor.
+ * When a cursor has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the cursor.
+ *
+ * @return
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * You must dispose the device when it is no longer required.
+ *
+ * You must dispose the device when it is no longer required.
+ *
+ * Currently, it is an error to invoke any method (other than
+ *
+ * In future releases of SWT, there may be more or fewer error
+ * checks and exceptions may be thrown for different reasons.
+ *
+ * This method is called before
+ * Subclasses are supposed to reimplement this method and not
+ * call the
+ * This method is called after
+ * Subclasses are supposed to reimplement this method and not
+ * call the
+ * Typically, applications which want the default look
+ * should simply not set the font on the widgets they
+ * create. Widgets are always created with the correct
+ * default font for the class of user-interface component
+ * they represent.
+ *
+ * This method is called after
+ * If subclasses reimplement this method, they must
+ * call the
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * This method gets the dispose state for the device.
+ * When a device has been disposed, it is an error to
+ * invoke any other method using the device.
+ *
+ * @return StyledTextPrintOptions.PAGE_TAG
). The three regions are
+ * left aligned, centered and right aligned. They are separated by a tab
+ * character (StyledTextPrintOptions.SEPARATOR
).
+ */
+ public String footer = null;
+ /**
+ * Name of the print job.
+ */
+ public String jobName = null;
+
+ /**
+ * Print the text foreground color. Default value is false
.
+ */
+ public boolean printTextForeground = false;
+ /**
+ * Print the text background color. Default value is false
.
+ */
+ public boolean printTextBackground = false;
+ /**
+ * Print the font styles. Default value is false
.
+ */
+ public boolean printTextFontStyle = false;
+ /**
+ * Print the line background color. Default value is false
.
+ */
+ public boolean printLineBackground = false;
+
+ /**
+ * Print line numbers. Default value is false
.
+ *
+ * @since 3.3
+ */
+ public boolean printLineNumbers = false;
+
+ /**
+ * Labels used for printing line numbers.
+ *
+ * @since 3.4
+ */
+ public String[] lineLabels = null;
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextRenderer.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextRenderer.java
new file mode 100644
index 000000000..d97277766
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/StyledTextRenderer.java
@@ -0,0 +1,1938 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Anton Leherbauer (Wind River Systems) - Bug 439419
+ * Angelo Zerr
+ *
+ *
+ * @since 2.0
+ *
+ * @see TableCursor snippets
+ * @see Sample code and further information
+ */
+public class TableCursor extends Canvas {
+ Table table;
+ TableItem row = null;
+ TableColumn column = null;
+ Listener listener, tableListener, resizeListener, disposeItemListener, disposeColumnListener;
+
+ Color background = null;
+ Color foreground = null;
+
+ /* By default, invert the list selection colors */
+ static final int BACKGROUND = SWT.COLOR_LIST_SELECTION_TEXT;
+ static final int FOREGROUND = SWT.COLOR_LIST_SELECTION;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * table and a style value describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#BORDER
+ * @see Widget#checkSubclass()
+ * @see Widget#getStyle()
+ */
+public TableCursor(Table parent, int style) {
+ super(parent, style);
+ table = parent;
+ setBackground(null);
+ setForeground(null);
+
+ listener = event -> {
+ switch (event.type) {
+ case SWT.Dispose :
+ onDispose(event);
+ break;
+ case SWT.FocusIn :
+ case SWT.FocusOut :
+ redraw();
+ break;
+ case SWT.KeyDown :
+ keyDown(event);
+ break;
+ case SWT.Paint :
+ paint(event);
+ break;
+ case SWT.Traverse : {
+ event.doit = true;
+ switch (event.detail) {
+ case SWT.TRAVERSE_ARROW_NEXT :
+ case SWT.TRAVERSE_ARROW_PREVIOUS :
+ case SWT.TRAVERSE_RETURN :
+ event.doit = false;
+ break;
+ }
+ break;
+ }
+ }
+ };
+ int[] events = new int[] {SWT.Dispose, SWT.FocusIn, SWT.FocusOut, SWT.KeyDown, SWT.Paint, SWT.Traverse};
+ for (int i = 0; i < events.length; i++) {
+ addListener(events[i], listener);
+ }
+
+ tableListener = event -> {
+ switch (event.type) {
+ case SWT.MouseDown :
+ tableMouseDown(event);
+ break;
+ case SWT.FocusIn :
+ tableFocusIn(event);
+ break;
+ }
+ };
+ table.addListener(SWT.FocusIn, tableListener);
+ table.addListener(SWT.MouseDown, tableListener);
+
+ disposeItemListener = event -> {
+ unhookRowColumnListeners();
+ row = null;
+ column = null;
+ _resize();
+ };
+ disposeColumnListener = event -> {
+ unhookRowColumnListeners();
+ row = null;
+ column = null;
+ _resize();
+ };
+ resizeListener = event -> _resize();
+ ScrollBar hBar = table.getHorizontalBar();
+ if (hBar != null) {
+ hBar.addListener(SWT.Selection, resizeListener);
+ }
+ ScrollBar vBar = table.getVerticalBar();
+ if (vBar != null) {
+ vBar.addListener(SWT.Selection, resizeListener);
+ }
+
+ getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() {
+ @Override
+ public void getRole(AccessibleControlEvent e) {
+ e.detail = ACC.ROLE_TABLECELL;
+ }
+ });
+ getAccessible().addAccessibleListener(new AccessibleAdapter() {
+ @Override
+ public void getName(AccessibleEvent e) {
+ if (row == null) return;
+ int columnIndex = column == null ? 0 : table.indexOf(column);
+ e.result = row.getText(columnIndex);
+ }
+ });
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called, the item field of the event object is valid.
+ * If the receiver has SWT.CHECK
style set and the check selection changes,
+ * the event object detail field contains the value SWT.CHECK
.
+ * widgetDefaultSelected
is typically called when an item is double-clicked.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see SelectionEvent
+ * @see #removeSelectionListener(SelectionListener)
+ *
+ */
+public void addSelectionListener(SelectionListener listener) {
+ checkWidget();
+ if (listener == null)
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection, typedListener);
+ addListener(SWT.DefaultSelection, typedListener);
+}
+
+void onDispose(Event event) {
+ removeListener(SWT.Dispose, listener);
+ notifyListeners(SWT.Dispose, event);
+ event.type = SWT.None;
+
+ table.removeListener(SWT.FocusIn, tableListener);
+ table.removeListener(SWT.MouseDown, tableListener);
+ unhookRowColumnListeners();
+ ScrollBar hBar = table.getHorizontalBar();
+ if (hBar != null) {
+ hBar.removeListener(SWT.Selection, resizeListener);
+ }
+ ScrollBar vBar = table.getVerticalBar();
+ if (vBar != null) {
+ vBar.removeListener(SWT.Selection, resizeListener);
+ }
+}
+
+void keyDown(Event event) {
+ if (row == null) return;
+ switch (event.character) {
+ case SWT.CR :
+ notifyListeners(SWT.DefaultSelection, new Event());
+ return;
+ }
+ int rowIndex = table.indexOf(row);
+ int columnIndex = column == null ? 0 : table.indexOf(column);
+ switch (event.keyCode) {
+ case SWT.ARROW_UP :
+ setRowColumn(Math.max(0, rowIndex - 1), columnIndex, true);
+ break;
+ case SWT.ARROW_DOWN :
+ setRowColumn(Math.min(rowIndex + 1, table.getItemCount() - 1), columnIndex, true);
+ break;
+ case SWT.ARROW_LEFT :
+ case SWT.ARROW_RIGHT :
+ {
+ int columnCount = table.getColumnCount();
+ if (columnCount == 0) break;
+ int[] order = table.getColumnOrder();
+ int index = 0;
+ while (index < order.length) {
+ if (order[index] == columnIndex) break;
+ index++;
+ }
+ if (index == order.length) index = 0;
+ int leadKey = (getStyle() & SWT.RIGHT_TO_LEFT) != 0 ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT;
+ if (event.keyCode == leadKey) {
+ setRowColumn(rowIndex, order[Math.max(0, index - 1)], true);
+ } else {
+ setRowColumn(rowIndex, order[Math.min(columnCount - 1, index + 1)], true);
+ }
+ break;
+ }
+ case SWT.HOME :
+ setRowColumn(0, columnIndex, true);
+ break;
+ case SWT.END :
+ {
+ int i = table.getItemCount() - 1;
+ setRowColumn(i, columnIndex, true);
+ break;
+ }
+ case SWT.PAGE_UP :
+ {
+ int index = table.getTopIndex();
+ if (index == rowIndex) {
+ Rectangle rect = table.getClientArea();
+ TableItem item = table.getItem(index);
+ Rectangle itemRect = item.getBounds(0);
+ rect.height -= itemRect.y;
+ int height = table.getItemHeight();
+ int page = Math.max(1, rect.height / height);
+ index = Math.max(0, index - page + 1);
+ }
+ setRowColumn(index, columnIndex, true);
+ break;
+ }
+ case SWT.PAGE_DOWN :
+ {
+ int index = table.getTopIndex();
+ Rectangle rect = table.getClientArea();
+ TableItem item = table.getItem(index);
+ Rectangle itemRect = item.getBounds(0);
+ rect.height -= itemRect.y;
+ int height = table.getItemHeight();
+ int page = Math.max(1, rect.height / height);
+ int end = table.getItemCount() - 1;
+ index = Math.min(end, index + page - 1);
+ if (index == rowIndex) {
+ index = Math.min(end, index + page - 1);
+ }
+ setRowColumn(index, columnIndex, true);
+ break;
+ }
+ }
+}
+
+void paint(Event event) {
+ if (row == null) return;
+ int columnIndex = column == null ? 0 : table.indexOf(column);
+ GC gc = event.gc;
+ gc.setBackground(getBackground());
+ gc.setForeground(getForeground());
+ gc.fillRectangle(event.x, event.y, event.width, event.height);
+ int x = 0;
+ Point size = getSize();
+ Image image = row.getImage(columnIndex);
+ if (image != null) {
+ Rectangle imageSize = image.getBounds();
+ int imageY = (size.y - imageSize.height) / 2;
+ gc.drawImage(image, x, imageY);
+ x += imageSize.width;
+ }
+ String text = row.getText(columnIndex);
+ if (text.length() > 0) {
+ Rectangle bounds = row.getBounds(columnIndex);
+ Point extent = gc.stringExtent(text);
+ // Temporary code - need a better way to determine table trim
+ String platform = SWT.getPlatform();
+ if ("win32".equals(platform)) { //$NON-NLS-1$
+ if (table.getColumnCount() == 0 || columnIndex == 0) {
+ x += 2;
+ } else {
+ int alignmnent = column.getAlignment();
+ switch (alignmnent) {
+ case SWT.LEFT:
+ x += 6;
+ break;
+ case SWT.RIGHT:
+ x = bounds.width - extent.x - 6;
+ break;
+ case SWT.CENTER:
+ x += (bounds.width - x - extent.x) / 2;
+ break;
+ }
+ }
+ } else {
+ if (table.getColumnCount() == 0) {
+ x += 5;
+ } else {
+ int alignmnent = column.getAlignment();
+ switch (alignmnent) {
+ case SWT.LEFT:
+ x += 5;
+ break;
+ case SWT.RIGHT:
+ x = bounds.width- extent.x - 2;
+ break;
+ case SWT.CENTER:
+ x += (bounds.width - x - extent.x) / 2 + 2;
+ break;
+ }
+ }
+ }
+ int textY = (size.y - extent.y) / 2;
+ gc.drawString(text, x, textY);
+ }
+ if (isFocusControl()) {
+ Display display = getDisplay();
+ gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
+ gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
+ gc.drawFocus(0, 0, size.x, size.y);
+ }
+}
+
+void tableFocusIn(Event event) {
+ if (isDisposed()) return;
+ if (isVisible()) {
+ if (row == null && column == null) return;
+ setFocus();
+ }
+}
+
+void tableMouseDown(Event event) {
+ if (isDisposed() || !isVisible()) return;
+ Point pt = new Point(event.x, event.y);
+ int lineWidth = table.getLinesVisible() ? table.getGridLineWidth() : 0;
+ TableItem item = table.getItem(pt);
+ if ((table.getStyle() & SWT.FULL_SELECTION) != 0) {
+ if (item == null) return;
+ } else {
+ int start = item != null ? table.indexOf(item) : table.getTopIndex();
+ int end = table.getItemCount();
+ Rectangle clientRect = table.getClientArea();
+ for (int i = start; i < end; i++) {
+ TableItem nextItem = table.getItem(i);
+ Rectangle rect = nextItem.getBounds(0);
+ if (pt.y >= rect.y && pt.y < rect.y + rect.height + lineWidth) {
+ item = nextItem;
+ break;
+ }
+ if (rect.y > clientRect.y + clientRect.height) return;
+ }
+ if (item == null) return;
+ }
+ TableColumn newColumn = null;
+ int columnCount = table.getColumnCount();
+ if (columnCount == 0) {
+ if ((table.getStyle() & SWT.FULL_SELECTION) == 0) {
+ Rectangle rect = item.getBounds(0);
+ rect.width += lineWidth;
+ rect.height += lineWidth;
+ if (!rect.contains(pt)) return;
+ }
+ } else {
+ for (int i = 0; i < columnCount; i++) {
+ Rectangle rect = item.getBounds(i);
+ rect.width += lineWidth;
+ rect.height += lineWidth;
+ if (rect.contains(pt)) {
+ newColumn = table.getColumn(i);
+ break;
+ }
+ }
+ if (newColumn == null) {
+ if ((table.getStyle() & SWT.FULL_SELECTION) == 0) return;
+ newColumn = table.getColumn(0);
+ }
+ }
+ setRowColumn(item, newColumn, true);
+ setFocus();
+ return;
+}
+void setRowColumn(int row, int column, boolean notify) {
+ TableItem item = row == -1 ? null : table.getItem(row);
+ TableColumn col = column == -1 || table.getColumnCount() == 0 ? null : table.getColumn(column);
+ setRowColumn(item, col, notify);
+}
+void setRowColumn(TableItem row, TableColumn column, boolean notify) {
+ if (this.row == row && this.column == column) {
+ return;
+ }
+ if (this.row != null && this.row != row) {
+ this.row.removeListener(SWT.Dispose, disposeItemListener);
+ this.row = null;
+ }
+ if (this.column != null && this.column != column) {
+ this.column.removeListener(SWT.Dispose, disposeColumnListener);
+ this.column.removeListener(SWT.Move, resizeListener);
+ this.column.removeListener(SWT.Resize, resizeListener);
+ this.column = null;
+ }
+ if (row != null) {
+ if (this.row != row) {
+ this.row = row;
+ row.addListener(SWT.Dispose, disposeItemListener);
+ table.showItem(row);
+ }
+ if (this.column != column && column != null) {
+ this.column = column;
+ column.addListener(SWT.Dispose, disposeColumnListener);
+ column.addListener(SWT.Move, resizeListener);
+ column.addListener(SWT.Resize, resizeListener);
+ table.showColumn(column);
+ }
+ int columnIndex = column == null ? 0 : table.indexOf(column);
+ setBounds(row.getBounds(columnIndex));
+ redraw();
+ if (notify) {
+ notifyListeners(SWT.Selection, new Event());
+ }
+ }
+ getAccessible().setFocus(ACC.CHILDID_SELF);
+}
+
+@Override
+public void setVisible(boolean visible) {
+ checkWidget();
+ if (visible) _resize();
+ super.setVisible(visible);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener(SelectionListener)
+ *
+ * @since 3.0
+ */
+public void removeSelectionListener(SelectionListener listener) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ removeListener(SWT.Selection, listener);
+ removeListener(SWT.DefaultSelection, listener);
+}
+
+void _resize() {
+ if (row == null) {
+ setBounds(-200, -200, 0, 0);
+ } else {
+ int columnIndex = column == null ? 0 : table.indexOf(column);
+ setBounds(row.getBounds(columnIndex));
+ }
+}
+/**
+ * Returns the index of the column over which the TableCursor is positioned.
+ *
+ * @return the column index for the current position
+ *
+ * @exception SWTException
+ *
+ */
+public int getColumn() {
+ checkWidget();
+ return column == null ? 0 : table.indexOf(column);
+}
+/**
+ * Returns the background color that the receiver will use to draw.
+ *
+ * @return the receiver's background color
+ */
+@Override
+public Color getBackground() {
+ checkWidget();
+ if (background == null) {
+ return getDisplay().getSystemColor(BACKGROUND);
+ }
+ return background;
+}
+/**
+ * Returns the foreground color that the receiver will use to draw.
+ *
+ * @return the receiver's foreground color
+ */
+@Override
+public Color getForeground() {
+ checkWidget();
+ if (foreground == null) {
+ return getDisplay().getSystemColor(FOREGROUND);
+ }
+ return foreground;
+}
+/**
+ * Returns the row over which the TableCursor is positioned.
+ *
+ * @return the item for the current position, or null
if none
+ *
+ * @exception SWTException
+ *
+ */
+public TableItem getRow() {
+ checkWidget();
+ return row;
+}
+/**
+ * Sets the receiver's background color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+@Override
+public void setBackground (Color color) {
+ background = color;
+ super.setBackground(getBackground());
+ redraw();
+}
+/**
+ * Sets the receiver's foreground color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+@Override
+public void setForeground (Color color) {
+ foreground = color;
+ super.setForeground(getForeground());
+ redraw();
+}
+/**
+ * Positions the TableCursor over the cell at the given row and column in the parent table.
+ *
+ * @param row the index of the row for the cell to select
+ * @param column the index of column for the cell to select
+ *
+ * @exception SWTException
+ *
+ *
+ */
+public void setSelection(int row, int column) {
+ checkWidget();
+ int columnCount = table.getColumnCount();
+ int maxColumnIndex = columnCount == 0 ? 0 : columnCount - 1;
+ if (row < 0
+ || row >= table.getItemCount()
+ || column < 0
+ || column > maxColumnIndex)
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ setRowColumn(row, column, false);
+}
+/**
+ * Positions the TableCursor over the cell at the given row and column in the parent table.
+ *
+ * @param row the TableItem of the row for the cell to select
+ * @param column the index of column for the cell to select
+ *
+ * @exception SWTException
+ *
+ *
+ */
+public void setSelection(TableItem row, int column) {
+ checkWidget();
+ int columnCount = table.getColumnCount();
+ int maxColumnIndex = columnCount == 0 ? 0 : columnCount - 1;
+ if (row == null
+ || row.isDisposed()
+ || column < 0
+ || column > maxColumnIndex)
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ setRowColumn(table.indexOf(row), column, false);
+}
+void unhookRowColumnListeners() {
+ if (column != null) {
+ column.removeListener(SWT.Dispose, disposeColumnListener);
+ column.removeListener(SWT.Move, resizeListener);
+ column.removeListener(SWT.Resize, resizeListener);
+ column = null;
+ }
+ if (row != null) {
+ row.removeListener(SWT.Dispose, disposeItemListener);
+ row = null;
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TableEditor.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TableEditor.java
new file mode 100644
index 000000000..7692fbd46
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TableEditor.java
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+*
+* A TableEditor is a manager for a Control that appears above a cell in a Table and tracks with the
+* moving and resizing of that cell. It can be used to display a text widget above a cell
+* in a Table so that the user can edit the contents of that cell. It can also be used to display
+* a button that can launch a dialog for modifying the contents of the associated cell.
+*
+*
+*
+* @see TableEditor snippets
+* @see Sample code and further information
+*/
+public class TableEditor extends ControlEditor {
+ Table table;
+ TableItem item;
+ int column = -1;
+ ControlListener columnListener;
+ Runnable timer;
+ static final int TIMEOUT = 1500;
+/**
+* Creates a TableEditor for the specified Table.
+*
+* @param table the Table Control above which this editor will be displayed
+*
+*/
+public TableEditor (Table table) {
+ super(table);
+ this.table = table;
+
+ columnListener = new ControlListener() {
+ @Override
+ public void controlMoved(ControlEvent e){
+ layout ();
+ }
+ @Override
+ public void controlResized(ControlEvent e){
+ layout ();
+ }
+ };
+ timer = () -> layout ();
+
+ // To be consistent with older versions of SWT, grabVertical defaults to true
+ grabVertical = true;
+}
+@Override
+Rectangle computeBounds () {
+ if (item == null || column == -1 || item.isDisposed()) return new Rectangle(0, 0, 0, 0);
+ Rectangle cell = item.getBounds(column);
+ Rectangle rect = item.getImageBounds(column);
+ if (rect.width != 0) {
+ int imageGap = Math.max(rect.x - cell.x, 0);
+ cell.x = rect.x + rect.width;
+ cell.width -= (imageGap + rect.width);
+ }
+ Rectangle area = table.getClientArea();
+ if (cell.x < area.x + area.width) {
+ if (cell.x + cell.width > area.x + area.width) {
+ cell.width = area.x + area.width - cell.x;
+ }
+ }
+ Rectangle editorRect = new Rectangle(cell.x, cell.y, minimumWidth, minimumHeight);
+
+ if (grabHorizontal) {
+ editorRect.width = Math.max(cell.width, minimumWidth);
+ }
+
+ if (grabVertical) {
+ editorRect.height = Math.max(cell.height, minimumHeight);
+ }
+
+ if (horizontalAlignment == SWT.RIGHT) {
+ editorRect.x += cell.width - editorRect.width;
+ } else if (horizontalAlignment == SWT.LEFT) {
+ // do nothing - cell.x is the right answer
+ } else { // default is CENTER
+ editorRect.x += (cell.width - editorRect.width)/2;
+ }
+
+ if (verticalAlignment == SWT.BOTTOM) {
+ editorRect.y += cell.height - editorRect.height;
+ } else if (verticalAlignment == SWT.TOP) {
+ // do nothing - cell.y is the right answer
+ } else { // default is CENTER
+ editorRect.y += (cell.height - editorRect.height)/2;
+ }
+ return editorRect;
+}
+/**
+ * Removes all associations between the TableEditor and the cell in the table. The
+ * Table and the editor Control are not disposed.
+ */
+@Override
+public void dispose () {
+ if (table != null && !table.isDisposed()) {
+ if (this.column > -1 && this.column < table.getColumnCount()){
+ TableColumn tableColumn = table.getColumn(this.column);
+ tableColumn.removeControlListener(columnListener);
+ }
+ }
+ columnListener = null;
+ table = null;
+ item = null;
+ column = -1;
+ timer = null;
+ super.dispose();
+}
+/**
+* Returns the zero based index of the column of the cell being tracked by this editor.
+*
+* @return the zero based index of the column of the cell being tracked by this editor
+*/
+public int getColumn () {
+ return column;
+}
+/**
+* Returns the TableItem for the row of the cell being tracked by this editor.
+*
+* @return the TableItem for the row of the cell being tracked by this editor
+*/
+public TableItem getItem () {
+ return item;
+}
+void resize () {
+ layout();
+ /*
+ * On some platforms, the table scrolls when an item that
+ * is partially visible at the bottom of the table is
+ * selected. Ensure that the correct row is edited by
+ * laying out one more time in a timerExec().
+ */
+ if (table != null) {
+ Display display = table.getDisplay();
+ display.timerExec(-1, timer);
+ display.timerExec(TIMEOUT, timer);
+ }
+}
+/**
+* Sets the zero based index of the column of the cell being tracked by this editor.
+*
+* @param column the zero based index of the column of the cell being tracked by this editor
+*/
+public void setColumn(int column) {
+ int columnCount = table.getColumnCount();
+ // Separately handle the case where the table has no TableColumns.
+ // In this situation, there is a single default column.
+ if (columnCount == 0) {
+ this.column = (column == 0) ? 0 : -1;
+ resize();
+ return;
+ }
+ if (this.column > -1 && this.column < columnCount){
+ TableColumn tableColumn = table.getColumn(this.column);
+ tableColumn.removeControlListener(columnListener);
+ this.column = -1;
+ }
+
+ if (column < 0 || column >= table.getColumnCount()) return;
+
+ this.column = column;
+ TableColumn tableColumn = table.getColumn(this.column);
+ tableColumn.addControlListener(columnListener);
+ resize();
+}
+/**
+* Specifies the
+* final Table table = new Table(shell, SWT.FULL_SELECTION | SWT.HIDE_SELECTION);
+* TableColumn column1 = new TableColumn(table, SWT.NONE);
+* TableColumn column2 = new TableColumn(table, SWT.NONE);
+* for (int i = 0; i < 10; i++) {
+* TableItem item = new TableItem(table, SWT.NONE);
+* item.setText(new String[] {"item " + i, "edit this value"});
+* }
+* column1.pack();
+* column2.pack();
+*
+* final TableEditor editor = new TableEditor(table);
+* //The editor must have the same size as the cell and must
+* //not be any smaller than 50 pixels.
+* editor.horizontalAlignment = SWT.LEFT;
+* editor.grabHorizontal = true;
+* editor.minimumWidth = 50;
+* // editing the second column
+* final int EDITABLECOLUMN = 1;
+*
+* table.addSelectionListener(new SelectionAdapter() {
+* public void widgetSelected(SelectionEvent e) {
+* // Clean up any previous editor control
+* Control oldEditor = editor.getEditor();
+* if (oldEditor != null) oldEditor.dispose();
+*
+* // Identify the selected row
+* TableItem item = (TableItem)e.item;
+* if (item == null) return;
+*
+* // The control that will be the editor must be a child of the Table
+* Text newEditor = new Text(table, SWT.NONE);
+* newEditor.setText(item.getText(EDITABLECOLUMN));
+* newEditor.addModifyListener(new ModifyListener() {
+* public void modifyText(ModifyEvent e) {
+* Text text = (Text)editor.getEditor();
+* editor.getItem().setText(EDITABLECOLUMN, text.getText());
+* }
+* });
+* newEditor.selectAll();
+* newEditor.setFocus();
+* editor.setEditor(newEditor, item, EDITABLECOLUMN);
+* }
+* });
+*
TableItem
that is to be edited.
+*
+* @param item the item to be edited
+*/
+public void setItem (TableItem item) {
+ this.item = item;
+ resize();
+}
+@Override
+public void setEditor (Control editor) {
+ super.setEditor(editor);
+ resize();
+}
+/**
+* Specify the Control that is to be displayed and the cell in the table that it is to be positioned above.
+*
+*
+ *
+ *
+ * @since 3.8
+ */
+public class TreeCursor extends Canvas {
+ Tree tree;
+ TreeItem row;
+ TreeColumn column;
+ Listener listener, treeListener, resizeListener, disposeItemListener, disposeColumnListener;
+
+ Color background = null;
+ Color foreground = null;
+
+ /* By default, invert the list selection colors */
+ static final int BACKGROUND = SWT.COLOR_LIST_SELECTION_TEXT;
+ static final int FOREGROUND = SWT.COLOR_LIST_SELECTION;
+
+/**
+ * Constructs a new instance of this class given its parent tree and a style value describing
+ * its behavior and appearance.
+ * SWT
which
+ * is applicable to instances of this class, or must be built by bitwise OR'ing
+ * together (that is, using the int
"|" operator) two or more of those
+ * SWT
style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#BORDER
+ * @see Widget#checkSubclass()
+ * @see Widget#getStyle()
+ */
+public TreeCursor(Tree parent, int style) {
+ super(parent, style);
+ tree = parent;
+ setBackground(null);
+ setForeground(null);
+
+ listener = event -> {
+ if (row != null) {
+ /*
+ * Detect cases where the cursor position has become invalid and fix it.
+ * The typical cause of this is programmatic tree changes, such as
+ * expanding/collapsing and item and creating/disposing items.
+ */
+ if (row.isDisposed()) {
+ unhookRowColumnListeners();
+ _resize();
+ tree.setFocus();
+ return;
+ }
+ TreeItem current = row;
+ TreeItem parentItem = row.getParentItem();
+ while (parentItem != null && !parentItem.getExpanded()) {
+ current = parentItem;
+ parentItem = current.getParentItem();
+ }
+ if (current != row) {
+ setRowColumn(current, column, false);
+ }
+ }
+ switch (event.type) {
+ case SWT.Dispose:
+ onDispose(event);
+ break;
+ case SWT.FocusIn:
+ case SWT.FocusOut:
+ redraw();
+ break;
+ case SWT.KeyDown:
+ keyDown(event);
+ break;
+ case SWT.Paint:
+ paint(event);
+ break;
+ case SWT.Traverse:
+ event.doit = true;
+ switch (event.detail) {
+ case SWT.TRAVERSE_ARROW_NEXT:
+ case SWT.TRAVERSE_ARROW_PREVIOUS:
+ case SWT.TRAVERSE_RETURN:
+ event.doit = false;
+ break;
+ }
+ break;
+ }
+ };
+ int[] events = new int[] { SWT.Dispose, SWT.FocusIn, SWT.FocusOut, SWT.KeyDown, SWT.Paint, SWT.Traverse };
+ for (int i = 0; i < events.length; i++) {
+ addListener(events[i], listener);
+ }
+
+ treeListener = event -> {
+ switch (event.type) {
+ case SWT.Collapse:
+ treeCollapse(event);
+ break;
+ case SWT.Expand:
+ treeExpand(event);
+ break;
+ case SWT.FocusIn:
+ treeFocusIn(event);
+ break;
+ case SWT.MouseDown:
+ treeMouseDown(event);
+ break;
+ }
+ };
+ tree.addListener(SWT.Collapse, treeListener);
+ tree.addListener(SWT.Expand, treeListener);
+ tree.addListener(SWT.FocusIn, treeListener);
+ tree.addListener(SWT.MouseDown, treeListener);
+
+ disposeItemListener = event -> {
+ TreeItem currentItem = row;
+ while (currentItem != null) {
+ currentItem.removeListener(SWT.Dispose, disposeItemListener);
+ currentItem = currentItem.getParentItem();
+ }
+ TreeItem disposedItem = (TreeItem)event.widget;
+ TreeItem parentItem = disposedItem.getParentItem();
+ if (parentItem != null) {
+ setRowColumn(parentItem, column, true);
+ } else {
+ if (tree.getItemCount() == 1) {
+ unhookRowColumnListeners();
+ } else {
+ TreeItem newFocus = null;
+ int rowIndex = tree.indexOf(disposedItem);
+ if (rowIndex != 0) {
+ TreeItem previousItem = tree.getItem(rowIndex - 1);
+ if (!previousItem.isDisposed()) {
+ newFocus = previousItem;
+ }
+ }
+ if (newFocus == null && rowIndex + 1 < tree.getItemCount()) {
+ TreeItem nextItem = tree.getItem(rowIndex + 1);
+ if (!nextItem.isDisposed()) {
+ newFocus = nextItem;
+ }
+ }
+ if (newFocus != null) {
+ setRowColumn(newFocus, column, true);
+ } else {
+ unhookRowColumnListeners();
+ }
+ }
+ }
+ _resize();
+ };
+ disposeColumnListener = event -> {
+ if (column != null) {
+ if (tree.getColumnCount() == 1) {
+ column = null;
+ } else {
+ int columnIndex = tree.indexOf(column);
+ int positionIndex = columnIndex;
+ int[] columnOrder = tree.getColumnOrder();
+ for (int i = 0; i < columnOrder.length; i++) {
+ if (columnOrder[i] == columnIndex) {
+ positionIndex = i;
+ break;
+ }
+ }
+ if (positionIndex == columnOrder.length - 1) {
+ setRowColumn(row, tree.getColumn(columnOrder[positionIndex - 1]), true);
+ } else {
+ setRowColumn(row, tree.getColumn(columnOrder[positionIndex + 1]), true);
+ }
+ }
+ }
+ _resize();
+ };
+ resizeListener = event -> _resize();
+ ScrollBar hBar = tree.getHorizontalBar();
+ if (hBar != null) {
+ hBar.addListener(SWT.Selection, resizeListener);
+ }
+ ScrollBar vBar = tree.getVerticalBar();
+ if (vBar != null) {
+ vBar.addListener(SWT.Selection, resizeListener);
+ }
+
+ getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() {
+ @Override
+ public void getRole(AccessibleControlEvent e) {
+ e.detail = ACC.ROLE_TABLECELL;
+ }
+ });
+ getAccessible().addAccessibleListener(new AccessibleAdapter() {
+ @Override
+ public void getName(AccessibleEvent e) {
+ if (row == null) return;
+ int columnIndex = column == null ? 0 : tree.indexOf(column);
+ e.result = row.getText(columnIndex);
+ }
+ });
+}
+
+/**
+ * Adds the listener to the collection of listeners who will be notified when the receiver's
+ * selection changes, by sending it one of the messages defined in the
+ * SelectionListener
interface.
+ * widgetSelected
is called, the item field of the event object is valid. If
+ * the receiver has SWT.CHECK
style set and the check selection changes, the event
+ * object detail field contains the value SWT.CHECK
.
+ * widgetDefaultSelected
is typically called when an item is double-clicked.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see SelectionEvent
+ * @see #removeSelectionListener(SelectionListener)
+ */
+public void addSelectionListener(SelectionListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection, typedListener);
+ addListener(SWT.DefaultSelection, typedListener);
+}
+
+int countSubTreePages(TreeItem root) {
+ int pages = 1;
+ if (root == null) return 0;
+ if (root.getItemCount() == 0) return 1;
+ if (!root.getExpanded()) return 1;
+ TreeItem[] items = root.getItems();
+ for (int i = 0; i < items.length; i++) {
+ pages += countSubTreePages(items[i]);
+ }
+ return pages;
+}
+
+int findIndex(TreeItem[] items, TreeItem treeItem) {
+ if (items == null || treeItem == null) return -1;
+ Rectangle rect = treeItem.getBounds();
+ int index = 0;
+ for (int i = 0; i < items.length; i++) {
+ TreeItem previousItem = null;
+ TreeItem currentItem = items[i];
+ if (i > 0) previousItem = items[i - 1];
+ Rectangle rect1 = currentItem.getBounds();
+ if (rect.y == rect1.y) return index;
+ if (rect.y < rect1.y) {
+ return index - 1 + findIndex(previousItem.getItems(), treeItem);
+ }
+ if (rect.y > rect1.y && i == items.length - 1) {
+ return index + findIndex(currentItem.getItems(), treeItem);
+ }
+ if (rect.y >= rect1.y + (1 + currentItem.getItemCount()) * tree.getItemHeight() && currentItem.getExpanded()) {
+ index += countSubTreePages(currentItem);
+ continue;
+ }
+ index++;
+ }
+ return -1;
+}
+
+TreeItem findItem(TreeItem[] items, Point pt) {
+ int start = 0, end = items.length - 1;
+ int index = end / 2;
+ while (end - start > 1) {
+ TreeItem currentItem = items[index];
+ Rectangle bounds = currentItem.getBounds();
+ if (pt.y < bounds.y) {
+ end = index;
+ index = (end - start) / 2;
+ } else {
+ start = index;
+ index = start + ((end - start) / 2);
+ }
+ }
+
+ Rectangle endBounds = items[end].getBounds();
+ if (endBounds.y < pt.y) {
+ if (endBounds.y + endBounds.height < pt.y) {
+ if (!items[end].getExpanded()) return null;
+ return findItem(items[end].getItems(), pt);
+ }
+ int[] columnOrder = tree.getColumnOrder();
+ Rectangle bounds = null;
+ if (columnOrder.length > 0) {
+ Rectangle rect1 = items[end].getBounds(columnOrder[0]);
+ Rectangle rect2 = items[end].getBounds(columnOrder[columnOrder.length - 1]);
+ bounds = rect1.union(rect2);
+ bounds.height += tree.getLinesVisible() ? tree.getGridLineWidth() : 0;
+ } else {
+ bounds = items[end].getBounds();
+ }
+ return bounds.contains(pt) ? items[end] : null;
+ }
+
+ Rectangle startBounds = items[start].getBounds();
+ if (startBounds.y + startBounds.height < pt.y) {
+ return findItem(items[start].getItems(), pt);
+ }
+ int[] columnOrder = tree.getColumnOrder();
+ Rectangle bounds = null;
+ if (columnOrder.length > 0) {
+ Rectangle rect1 = items[start].getBounds(columnOrder[0]);
+ Rectangle rect2 = items[start].getBounds(columnOrder[columnOrder.length - 1]);
+ bounds = rect1.union(rect2);
+ bounds.height += tree.getLinesVisible() ? tree.getGridLineWidth() : 0;
+ } else {
+ bounds = items[start].getBounds();
+ }
+ return bounds.contains(pt) ? items[start] : null;
+}
+
+/**
+ * Returns the background color that the receiver will use to draw.
+ *
+ * @return the receiver's background color
+ */
+@Override
+public Color getBackground() {
+ checkWidget();
+ if (background == null) {
+ return getDisplay().getSystemColor(BACKGROUND);
+ }
+ return background;
+}
+
+/**
+ * Returns the index of the column over which the TreeCursor is positioned.
+ *
+ * @return the column index for the current position
+ *
+ * @exception SWTException
+ *
+ */
+public int getColumn() {
+ checkWidget();
+ return column == null ? 0 : tree.indexOf(column);
+}
+
+/**
+ * Returns the foreground color that the receiver will use to draw.
+ *
+ * @return the receiver's foreground color
+ */
+@Override
+public Color getForeground() {
+ checkWidget();
+ if (foreground == null) {
+ return getDisplay().getSystemColor(FOREGROUND);
+ }
+ return foreground;
+}
+
+TreeItem getLastVisibleItem(TreeItem[] items) {
+ if (items == null) return null;
+ TreeItem last = items[items.length - 1];
+ if (last.getExpanded() && last.getItemCount() > 0) {
+ return getLastVisibleItem(last.getItems());
+ }
+ return last;
+}
+
+TreeItem getNextItem(TreeItem item) {
+ if (item == null) return null;
+ if (item.getExpanded() && item.getItemCount() > 0) {
+ return item.getItem(0);
+ }
+
+ TreeItem parentItem = item.getParentItem();
+ while (parentItem != null) {
+ int index = parentItem.indexOf(item);
+ if (index == -1) return null;
+ if (index < parentItem.getItemCount() - 1) {
+ return parentItem.getItem(index + 1);
+ }
+ item = parentItem;
+ parentItem = item.getParentItem();
+ }
+ int index = tree.indexOf(item);
+ if (index == -1) return null;
+ if (index == tree.getItemCount() - 1) return null;
+ return tree.getItem(index + 1);
+}
+
+TreeItem getPreviousItem(TreeItem item) {
+ if (item == null) return null;
+ TreeItem parentItem = item.getParentItem();
+ if (parentItem == null) {
+ int index = tree.indexOf(item);
+ if (index == -1 || index == 0) return null;
+ item = tree.getItem(index - 1);
+ if (item.getExpanded() && item.getItemCount() > 0) {
+ return getLastVisibleItem(item.getItems());
+ }
+ return item;
+ }
+ int index = parentItem.indexOf(item);
+ if (index == -1) return null;
+ if (index == 0) return parentItem;
+ item = parentItem.getItem(index - 1);
+ if (item.getExpanded() && item.getItemCount() > 0) {
+ return getLastVisibleItem(item.getItems());
+ }
+ return item;
+}
+
+/**
+ * Returns the row over which the TreeCursor is positioned.
+ *
+ * @return the item for the current position, or null
if none
+ *
+ * @exception SWTException
+ *
+ */
+public TreeItem getRow() {
+ checkWidget();
+ return row;
+}
+
+void keyDown(Event event) {
+ if (row == null) return;
+ switch (event.character) {
+ case SWT.CR:
+ notifyListeners(SWT.DefaultSelection, new Event());
+ return;
+ }
+ switch (event.keyCode) {
+ case SWT.ARROW_UP:
+ TreeItem previousItem = getPreviousItem(row);
+ if (previousItem != null) {
+ setRowColumn(previousItem, column, true);
+ }
+ break;
+ case SWT.ARROW_DOWN:
+ TreeItem nextItem = getNextItem(row);
+ if (nextItem != null) {
+ setRowColumn(nextItem, column, true);
+ }
+ break;
+ case SWT.ARROW_LEFT:
+ case SWT.ARROW_RIGHT: {
+ if ((event.stateMask & SWT.MOD1) != 0) {
+ row.setExpanded (event.keyCode == SWT.ARROW_RIGHT);
+ break;
+ }
+ int columnCount = tree.getColumnCount();
+ if (columnCount == 0) break;
+ int columnIndex = column == null ? 0 : tree.indexOf(column);
+ int[] columnOrder = tree.getColumnOrder();
+ int index = 0;
+ while (index < columnOrder.length) {
+ if (columnOrder[index] == columnIndex) break;
+ index++;
+ }
+ if (index == columnOrder.length) index = 0;
+ int leadKey = (getStyle() & SWT.RIGHT_TO_LEFT) != 0 ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT;
+ TreeItem parentRow = row.getParentItem();
+ int rowIndex = tree.indexOf(row);
+ if (event.keyCode == leadKey) {
+ if (parentRow != null) {
+ setRowColumn(row, tree.getColumn(columnOrder[Math.max(0, index - 1)]), true);
+ } else {
+ setRowColumn(rowIndex, columnOrder[Math.max(0, index - 1)], true);
+ }
+ } else {
+ if (parentRow != null) {
+ setRowColumn(row, tree.getColumn(columnOrder[Math.min(columnCount - 1, index + 1)]), true);
+ } else {
+ setRowColumn(rowIndex, columnOrder[Math.min(columnCount - 1, index + 1)], true);
+ }
+ }
+ break;
+ }
+ case SWT.HOME:
+ int columnIndex = column == null ? 0 : tree.indexOf(column);
+ setRowColumn(0, columnIndex, true);
+ break;
+ case SWT.END: {
+ TreeItem[] items = tree.getItems();
+ setRowColumn(getLastVisibleItem(items), column, true);
+ break;
+ }
+ case SWT.PAGE_UP: {
+ Rectangle rect = tree.getClientArea();
+ Rectangle itemRect = tree.getTopItem().getBounds();
+ TreeItem item = row;
+ int index = findIndex(tree.getItems(), item);
+ int itemHeight = tree.getItemHeight();
+ rect.height -= itemRect.y;
+ int page = Math.max(1, rect.height / itemHeight);
+ if (index - page <= 0) {
+ TreeItem first = tree.getItem(0);
+ setRowColumn(first, column, true);
+ break;
+ }
+ for (int i = 0; i < page; i++) {
+ item = getPreviousItem(item);
+ }
+ setRowColumn(item, column, true);
+ break;
+ }
+ case SWT.PAGE_DOWN: {
+ Rectangle rect = tree.getClientArea();
+ Rectangle itemRect = tree.getTopItem().getBounds();
+ TreeItem item = row;
+ int index = findIndex(tree.getItems(), item);
+ int height = tree.getItemHeight();
+ rect.height -= itemRect.y;
+ TreeItem last = getLastVisibleItem(tree.getItems());
+ int page = Math.max(1, rect.height / height);
+ int end = findIndex(tree.getItems(), last);
+ if (end <= index + page) {
+ setRowColumn(last, column, true);
+ break;
+ }
+ for (int i = 0; i < page; i++) {
+ item = getNextItem(item);
+ }
+ setRowColumn(item, column, true);
+ break;
+ }
+ }
+}
+
+void onDispose(Event event) {
+ removeListener(SWT.Dispose, listener);
+ notifyListeners(SWT.Dispose, event);
+ event.type = SWT.None;
+
+ tree.removeListener(SWT.Collapse, treeListener);
+ tree.removeListener(SWT.Expand, treeListener);
+ tree.removeListener(SWT.FocusIn, treeListener);
+ tree.removeListener(SWT.MouseDown, treeListener);
+ unhookRowColumnListeners();
+ ScrollBar hBar = tree.getHorizontalBar();
+ if (hBar != null) {
+ hBar.removeListener(SWT.Selection, resizeListener);
+ }
+ ScrollBar vBar = tree.getVerticalBar();
+ if (vBar != null) {
+ vBar.removeListener(SWT.Selection, resizeListener);
+ }
+}
+
+void paint(Event event) {
+ if (row == null) return;
+ int columnIndex = column == null ? 0 : tree.indexOf(column);
+ int orderedIndex = columnIndex;
+ int[] columnOrder = tree.getColumnOrder();
+ for (int i = 0; i < columnOrder.length; i++) {
+ if (columnOrder[i] == columnIndex) {
+ orderedIndex = i;
+ break;
+ }
+ }
+ GC gc = event.gc;
+ gc.setBackground(getBackground());
+ gc.setForeground(getForeground());
+ gc.fillRectangle(event.x, event.y, event.width, event.height);
+ Image image = row.getImage(columnIndex);
+ int x = 0;
+ // Temporary code - need a better way to determine trim
+ String platform = SWT.getPlatform();
+ if (image != null) {
+ if ("win32".equals(platform)) { //$NON-NLS-1$
+ if (orderedIndex > 0) {
+ x += 2;
+ }
+ } else {
+ x += 2;
+ }
+ }
+ Point size = getSize();
+ if (image != null) {
+ Rectangle imageSize = image.getBounds();
+ int imageY = (size.y - imageSize.height) / 2;
+ gc.drawImage(image, x, imageY);
+ x += imageSize.width;
+ }
+ String text = row.getText(columnIndex);
+ if (text.length() > 0) {
+ Rectangle bounds = row.getBounds(columnIndex);
+ Point extent = gc.stringExtent(text);
+ // Temporary code - need a better way to determine trim
+ if ("win32".equals(platform)) { //$NON-NLS-1$
+ if (tree.getColumnCount() == 0 || orderedIndex == 0) {
+ x += image == null ? 2 : 5;
+ } else {
+ int alignmnent = column.getAlignment();
+ switch (alignmnent) {
+ case SWT.LEFT:
+ x += image == null ? 5 : 3;
+ break;
+ case SWT.RIGHT:
+ x = bounds.width - extent.x - 2;
+ break;
+ case SWT.CENTER:
+ x += Math.ceil((bounds.width - x - extent.x) / 2.0);
+ break;
+ }
+ }
+ } else {
+ if (tree.getColumnCount() == 0) {
+ x += image == null ? 4 : 3;
+ } else {
+ int alignmnent = column.getAlignment();
+ switch (alignmnent) {
+ case SWT.LEFT:
+ x += image == null ? 5 : 3;
+ break;
+ case SWT.RIGHT:
+ x = bounds.width - extent.x - 2;
+ break;
+ case SWT.CENTER:
+ x += (bounds.width - x - extent.x) / 2 + 2;
+ break;
+ }
+ }
+ }
+ int textY = (size.y - extent.y) / 2;
+ gc.drawString(text, x, textY);
+ }
+ if (isFocusControl()) {
+ Display display = getDisplay();
+ gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
+ gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
+ gc.drawFocus(0, 0, size.x, size.y);
+ }
+}
+
+/**
+ * Removes the listener from the collection of listeners who will be notified when the
+ * receiver's selection changes.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener(SelectionListener)
+ */
+public void removeSelectionListener(SelectionListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ removeListener(SWT.Selection, listener);
+ removeListener(SWT.DefaultSelection, listener);
+}
+
+void _resize() {
+ if (row == null) {
+ setBounds(-200, -200, 0, 0);
+ } else {
+ int columnIndex = column == null ? 0 : tree.indexOf(column);
+ setBounds(row.getBounds(columnIndex));
+ }
+}
+
+/**
+ * Sets the receiver's background color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+@Override
+public void setBackground (Color color) {
+ background = color;
+ super.setBackground(getBackground());
+ redraw();
+}
+/**
+ * Sets the receiver's foreground color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+@Override
+public void setForeground (Color color) {
+ foreground = color;
+ super.setForeground(getForeground());
+ redraw();
+}
+
+void setRowColumn(int row, int column, boolean notify) {
+ TreeItem item = row == -1 ? null : tree.getItem(row);
+ TreeColumn col = column == -1 || tree.getColumnCount() == 0 ? null : tree.getColumn(column);
+ setRowColumn(item, col, notify);
+}
+
+void setRowColumn(TreeItem row, TreeColumn column, boolean notify) {
+ if (this.row != null && this.row != row) {
+ TreeItem currentItem = this.row;
+ while (currentItem != null) {
+ currentItem.removeListener(SWT.Dispose, disposeItemListener);
+ currentItem = currentItem.getParentItem();
+ }
+ this.row = null;
+ }
+ if (this.column != null && this.column != column) {
+ this.column.removeListener(SWT.Dispose, disposeColumnListener);
+ this.column.removeListener(SWT.Move, resizeListener);
+ this.column.removeListener(SWT.Resize, resizeListener);
+ this.column = null;
+ }
+ if (row != null) {
+ if (this.row != row) {
+ this.row = row;
+ TreeItem currentItem = row;
+ while (currentItem != null) {
+ currentItem.addListener(SWT.Dispose, disposeItemListener);
+ currentItem = currentItem.getParentItem();
+ }
+ tree.showItem(row);
+ }
+ if (this.column != column && column != null) {
+ this.column = column;
+ column.addListener(SWT.Dispose, disposeColumnListener);
+ column.addListener(SWT.Move, resizeListener);
+ column.addListener(SWT.Resize, resizeListener);
+ tree.showColumn(column);
+ }
+ int columnIndex = column == null ? 0 : tree.indexOf(column);
+ setBounds(row.getBounds(columnIndex));
+ redraw();
+ if (notify) notifyListeners(SWT.Selection, new Event());
+ }
+}
+
+/**
+ * Positions the TreeCursor over the root-level cell at the given row and column in the parent tree.
+ *
+ * @param row the index of the root-level row for the cell to select
+ * @param column the index of column for the cell to select
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection(int row, int column) {
+ checkWidget();
+ int columnCount = tree.getColumnCount();
+ int maxColumnIndex = columnCount == 0 ? 0 : columnCount - 1;
+ if (row < 0 || row >= tree.getItemCount() || column < 0 || column > maxColumnIndex) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ setRowColumn(row, column, false);
+}
+
+/**
+ * Positions the TreeCursor over the cell at the given row and column in the parent tree.
+ *
+ * @param row the TreeItem of the row for the cell to select
+ * @param column the index of column for the cell to select
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection(TreeItem row, int column) {
+ checkWidget();
+ int columnCount = tree.getColumnCount();
+ int maxColumnIndex = columnCount == 0 ? 0 : columnCount - 1;
+ if (row == null || row.isDisposed() || column < 0 || column > maxColumnIndex) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ TreeColumn col = tree.getColumnCount() == 0 ? null : tree.getColumn(column);
+ setRowColumn(row, col, false);
+}
+
+@Override
+public void setVisible(boolean visible) {
+ checkWidget();
+ if (visible) {
+ _resize();
+ }
+ super.setVisible(visible);
+}
+
+void treeCollapse(Event event) {
+ if (row == null) return;
+ TreeItem root = (TreeItem)event.item;
+ TreeItem parentItem = row.getParentItem();
+ while (parentItem != null) {
+ if (parentItem == root) {
+ setRowColumn(root, column, true);
+ return;
+ }
+ parentItem = parentItem.getParentItem();
+ }
+
+ getDisplay().asyncExec(() -> {
+ if (isDisposed()) return;
+ setRowColumn(row, column, true);
+ });
+}
+
+void treeExpand(Event event) {
+ getDisplay().asyncExec(() -> {
+ if (isDisposed()) return;
+ setRowColumn(row, column, true);
+ });
+}
+
+void treeFocusIn(Event event) {
+ if (isVisible()) {
+ if (row == null && column == null) return;
+ setFocus();
+ }
+}
+
+void treeMouseDown(Event event) {
+ if (tree.getItemCount() == 0) return;
+ Point pt = new Point(event.x, event.y);
+ TreeItem item = tree.getItem(pt);
+ if (item == null && (tree.getStyle() & SWT.FULL_SELECTION) == 0) {
+ TreeItem currentItem = tree.getTopItem();
+ TreeItem parentItem = currentItem.getParentItem();
+ while (parentItem != null) {
+ currentItem = parentItem;
+ parentItem = currentItem.getParentItem();
+ }
+ int start = tree.indexOf(currentItem);
+ int viewportItemCount = tree.getClientArea().height / tree.getItemHeight();
+ int end = Math.min(start + viewportItemCount, tree.getItemCount() - 1);
+ TreeItem[] allItems = tree.getItems();
+ TreeItem[] items = new TreeItem[end - start + 1];
+ System.arraycopy(allItems, start, items, 0, end - start + 1);
+ item = findItem(items, pt);
+ }
+ if (item == null) return;
+
+ TreeColumn newColumn = null;
+ int lineWidth = tree.getLinesVisible() ? tree.getGridLineWidth() : 0;
+ int columnCount = tree.getColumnCount();
+ if (columnCount > 0) {
+ for (int i = 0; i < columnCount; i++) {
+ Rectangle rect = item.getBounds(i);
+ rect.width += lineWidth;
+ rect.height += lineWidth;
+ if (rect.contains(pt)) {
+ newColumn = tree.getColumn(i);
+ break;
+ }
+ }
+ if (newColumn == null) {
+ newColumn = tree.getColumn(0);
+ }
+ }
+ setRowColumn(item, newColumn, true);
+ setFocus();
+}
+
+void unhookRowColumnListeners() {
+ if (column != null && !column.isDisposed()) {
+ column.removeListener(SWT.Dispose, disposeColumnListener);
+ column.removeListener(SWT.Move, resizeListener);
+ column.removeListener(SWT.Resize, resizeListener);
+ }
+ column = null;
+ if (row != null && !row.isDisposed()) {
+ TreeItem currentItem = row;
+ while (currentItem != null) {
+ currentItem.removeListener(SWT.Dispose, disposeItemListener);
+ currentItem = currentItem.getParentItem();
+ }
+ }
+ row = null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TreeEditor.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TreeEditor.java
new file mode 100644
index 000000000..5ec8f9503
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/TreeEditor.java
@@ -0,0 +1,324 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+*
+* A TreeEditor is a manager for a Control that appears above a cell in a Tree and tracks with the
+* moving and resizing of that cell. It can be used to display a text widget above a cell
+* in a Tree so that the user can edit the contents of that cell. It can also be used to display
+* a button that can launch a dialog for modifying the contents of the associated cell.
+*
+*
+*
+* @see TreeEditor snippets
+* @see Sample code and further information
+*/
+public class TreeEditor extends ControlEditor {
+ Tree tree;
+ TreeItem item;
+ int column = 0;
+ ControlListener columnListener;
+ TreeListener treeListener;
+ Runnable timer;
+ static final int TIMEOUT = 1500;
+
+/**
+* Creates a TreeEditor for the specified Tree.
+*
+* @param tree the Tree Control above which this editor will be displayed
+*
+*/
+public TreeEditor (Tree tree) {
+ super(tree);
+ this.tree = tree;
+
+ columnListener = new ControlListener() {
+ @Override
+ public void controlMoved(ControlEvent e){
+ layout();
+ }
+ @Override
+ public void controlResized(ControlEvent e){
+ layout();
+ }
+ };
+ timer = () -> layout ();
+ treeListener = new TreeListener () {
+ final Runnable runnable = () -> {
+ if (editor == null || editor.isDisposed()) return;
+ if (TreeEditor.this.tree.isDisposed()) return;
+ layout();
+ editor.setVisible(true);
+ };
+ @Override
+ public void treeCollapsed(TreeEvent e) {
+ if (editor == null || editor.isDisposed ()) return;
+ editor.setVisible(false);
+ e.display.asyncExec(runnable);
+ }
+ @Override
+ public void treeExpanded(TreeEvent e) {
+ if (editor == null || editor.isDisposed ()) return;
+ editor.setVisible(false);
+ e.display.asyncExec(runnable);
+ }
+ };
+ tree.addTreeListener(treeListener);
+
+ // To be consistent with older versions of SWT, grabVertical defaults to true
+ grabVertical = true;
+}
+
+@Override
+Rectangle computeBounds () {
+ if (item == null || column == -1 || item.isDisposed()) return new Rectangle(0, 0, 0, 0);
+ Rectangle cell = item.getBounds(column);
+ Rectangle rect = item.getImageBounds(column);
+ cell.x = rect.x + rect.width;
+ cell.width -= rect.width;
+ Rectangle area = tree.getClientArea();
+ if (cell.x < area.x + area.width) {
+ if (cell.x + cell.width > area.x + area.width) {
+ cell.width = area.x + area.width - cell.x;
+ }
+ }
+ Rectangle editorRect = new Rectangle(cell.x, cell.y, minimumWidth, minimumHeight);
+
+ if (grabHorizontal) {
+ if (tree.getColumnCount() == 0) {
+ // Bounds of tree item only include the text area - stretch out to include
+ // entire client area
+ cell.width = area.x + area.width - cell.x;
+ }
+ editorRect.width = Math.max(cell.width, minimumWidth);
+ }
+
+ if (grabVertical) {
+ editorRect.height = Math.max(cell.height, minimumHeight);
+ }
+
+ if (horizontalAlignment == SWT.RIGHT) {
+ editorRect.x += cell.width - editorRect.width;
+ } else if (horizontalAlignment == SWT.LEFT) {
+ // do nothing - cell.x is the right answer
+ } else { // default is CENTER
+ editorRect.x += (cell.width - editorRect.width)/2;
+ }
+ // don't let the editor overlap with the +/- of the tree
+ editorRect.x = Math.max(cell.x, editorRect.x);
+
+ if (verticalAlignment == SWT.BOTTOM) {
+ editorRect.y += cell.height - editorRect.height;
+ } else if (verticalAlignment == SWT.TOP) {
+ // do nothing - cell.y is the right answer
+ } else { // default is CENTER
+ editorRect.y += (cell.height - editorRect.height)/2;
+ }
+ return editorRect;
+}
+
+/**
+ * Removes all associations between the TreeEditor and the row in the tree. The
+ * tree and the editor Control are not disposed.
+ */
+@Override
+public void dispose () {
+ if (tree != null && !tree.isDisposed()) {
+ if (this.column > -1 && this.column < tree.getColumnCount()){
+ TreeColumn treeColumn = tree.getColumn(this.column);
+ treeColumn.removeControlListener(columnListener);
+ }
+ if (treeListener != null) tree.removeTreeListener(treeListener);
+ }
+ columnListener = null;
+ treeListener = null;
+ tree = null;
+ item = null;
+ column = 0;
+ timer = null;
+ super.dispose();
+}
+
+/**
+* Returns the zero based index of the column of the cell being tracked by this editor.
+*
+* @return the zero based index of the column of the cell being tracked by this editor
+*
+* @since 3.1
+*/
+public int getColumn () {
+ return column;
+}
+
+/**
+* Returns the TreeItem for the row of the cell being tracked by this editor.
+*
+* @return the TreeItem for the row of the cell being tracked by this editor
+*/
+public TreeItem getItem () {
+ return item;
+}
+
+void resize () {
+ layout();
+ /*
+ * On some platforms, the table scrolls when an item that
+ * is partially visible at the bottom of the table is
+ * selected. Ensure that the correct row is edited by
+ * laying out one more time in a timerExec().
+ */
+ if (tree != null) {
+ Display display = tree.getDisplay();
+ display.timerExec(-1, timer);
+ display.timerExec(TIMEOUT, timer);
+ }
+}
+
+/**
+* Sets the zero based index of the column of the cell being tracked by this editor.
+*
+* @param column the zero based index of the column of the cell being tracked by this editor
+*
+* @since 3.1
+*/
+public void setColumn(int column) {
+ int columnCount = tree.getColumnCount();
+ // Separately handle the case where the tree has no TreeColumns.
+ // In this situation, there is a single default column.
+ if (columnCount == 0) {
+ this.column = (column == 0) ? 0 : -1;
+ resize();
+ return;
+ }
+ if (this.column > -1 && this.column < columnCount){
+ TreeColumn treeColumn = tree.getColumn(this.column);
+ treeColumn.removeControlListener(columnListener);
+ this.column = -1;
+ }
+
+ if (column < 0 || column >= tree.getColumnCount()) return;
+
+ this.column = column;
+ TreeColumn treeColumn = tree.getColumn(this.column);
+ treeColumn.addControlListener(columnListener);
+ resize();
+}
+
+/**
+* Specifies the
+* final Tree tree = new Tree(shell, SWT.BORDER);
+* for (int i = 0; i < 3; i++) {
+* TreeItem item = new TreeItem(tree, SWT.NONE);
+* item.setText("item " + i);
+* for (int j = 0; j < 3; j++) {
+* TreeItem subItem = new TreeItem(item, SWT.NONE);
+* subItem.setText("item " + i + " " + j);
+* }
+* }
+*
+* final TreeEditor editor = new TreeEditor(tree);
+* //The editor must have the same size as the cell and must
+* //not be any smaller than 50 pixels.
+* editor.horizontalAlignment = SWT.LEFT;
+* editor.grabHorizontal = true;
+* editor.minimumWidth = 50;
+*
+* tree.addSelectionListener(new SelectionAdapter() {
+* public void widgetSelected(SelectionEvent e) {
+* // Clean up any previous editor control
+* Control oldEditor = editor.getEditor();
+* if (oldEditor != null) oldEditor.dispose();
+*
+* // Identify the selected row
+* TreeItem item = (TreeItem)e.item;
+* if (item == null) return;
+*
+* // The control that will be the editor must be a child of the Tree
+* Text newEditor = new Text(tree, SWT.NONE);
+* newEditor.setText(item.getText());
+* newEditor.addModifyListener(new ModifyListener() {
+* public void modifyText(ModifyEvent e) {
+* Text text = (Text)editor.getEditor();
+* editor.getItem().setText(text.getText());
+* }
+* });
+* newEditor.selectAll();
+* newEditor.setFocus();
+* editor.setEditor(newEditor, item);
+* }
+* });
+*
TreeItem
that is to be edited.
+*
+* @param item the item to be edited
+*/
+public void setItem (TreeItem item) {
+ this.item = item;
+ resize();
+}
+
+/**
+* Specify the Control that is to be displayed and the cell in the tree that it is to be positioned above.
+*
+*
+ *
+ * @param event the verify event
+ * @see VerifyEvent
+ */
+public void verifyKey (VerifyEvent event);
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ViewForm.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ViewForm.java
new file mode 100644
index 000000000..af2dde8b8
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ViewForm.java
@@ -0,0 +1,499 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Instances of this class implement a Composite that positions and sizes
+ * children and allows programmatic control of layout and border parameters.
+ * ViewForm is used in the workbench to lay out a view's label/menu/toolbar
+ * local bar.
+ * Composite
,
+ * it does not make sense to set a layout on it.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#BORDER
+ * @see SWT#FLAT
+ * @see #getStyle()
+ */
+public ViewForm(Composite parent, int style) {
+ super(parent, checkStyle(style));
+ super.setLayout(new ViewFormLayout());
+
+ setBorderVisible((style & SWT.BORDER) != 0);
+
+ listener = e -> {
+ switch (e.type) {
+ case SWT.Dispose: onDispose(e); break;
+ case SWT.Paint: onPaint(e.gc); break;
+ case SWT.Resize: onResize(); break;
+ }
+ };
+
+ int[] events = new int[] {SWT.Dispose, SWT.Paint, SWT.Resize};
+
+ for (int i = 0; i < events.length; i++) {
+ addListener(events[i], listener);
+ }
+}
+
+static int checkStyle (int style) {
+ int mask = SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+ return style & mask | SWT.NO_REDRAW_RESIZE;
+}
+
+//protected void checkSubclass () {
+// String name = getClass().getName ();
+// String validName = ViewForm.class.getName();
+// if (!validName.equals(name)) {
+// SWT.error (SWT.ERROR_INVALID_SUBCLASS);
+// }
+//}
+
+@Override
+public Rectangle computeTrim (int x, int y, int width, int height) {
+ checkWidget ();
+ int trimX = x - borderLeft - highlight;
+ int trimY = y - borderTop - highlight;
+ int trimWidth = width + borderLeft + borderRight + 2*highlight;
+ int trimHeight = height + borderTop + borderBottom + 2*highlight;
+ return new Rectangle(trimX, trimY, trimWidth, trimHeight);
+}
+@Override
+public Rectangle getClientArea() {
+ checkWidget();
+ Rectangle clientArea = super.getClientArea();
+ clientArea.x += borderLeft;
+ clientArea.y += borderTop;
+ clientArea.width -= borderLeft + borderRight;
+ clientArea.height -= borderTop + borderBottom;
+ return clientArea;
+}
+/**
+* Returns the content area.
+*
+* @return the control in the content area of the pane or null
+*/
+public Control getContent() {
+ /*
+ * This call is intentionally commented out, to allow this getter method to be
+ * called from a thread which is different from one that created the parent.
+ */
+ //checkWidget();
+ return content;
+}
+/**
+* Returns Control that appears in the top center of the pane.
+* Typically this is a toolbar.
+*
+* @return the control in the top center of the pane or null
+*/
+public Control getTopCenter() {
+ /*
+ * This call is intentionally commented out, to allow this getter method to be
+ * called from a thread which is different from one that created the widget.
+ */
+ //checkWidget();
+ return topCenter;
+}
+/**
+* Returns the Control that appears in the top left corner of the pane.
+* Typically this is a label such as CLabel.
+*
+* @return the control in the top left corner of the pane or null
+*/
+public Control getTopLeft() {
+ /*
+ * This call is intentionally commented out, to allow this getter method to be
+ * called from a thread which is different from one that created the widget.
+ */
+ //checkWidget();
+ return topLeft;
+}
+/**
+* Returns the control in the top right corner of the pane.
+* Typically this is a Close button or a composite with a Menu and Close button.
+*
+* @return the control in the top right corner of the pane or null
+*/
+public Control getTopRight() {
+ /*
+ * This call is intentionally commented out, to allow this getter method to be
+ * called from a thread which is different from one that created the widget.
+ */
+ //checkWidget();
+ return topRight;
+}
+void onDispose(Event event) {
+ removeListener(SWT.Dispose, listener);
+ notifyListeners(SWT.Dispose, event);
+ event.type = SWT.None;
+
+ topLeft = null;
+ topCenter = null;
+ topRight = null;
+ content = null;
+ oldSize = null;
+ selectionBackground = null;
+}
+void onPaint(GC gc) {
+ Color gcForeground = gc.getForeground();
+ Point size = getSize();
+ Color border = getDisplay().getSystemColor(BORDER1_COLOR);
+ if (showBorder) {
+ gc.setForeground(border);
+ gc.drawRectangle(0, 0, size.x - 1, size.y - 1);
+ if (highlight > 0) {
+ int x1 = 1;
+ int y1 = 1;
+ int x2 = size.x - 1;
+ int y2 = size.y - 1;
+ int[] shape = new int[] {x1,y1, x2,y1, x2,y2, x1,y2, x1,y1+highlight,
+ x1+highlight,y1+highlight, x1+highlight,y2-highlight,
+ x2-highlight,y2-highlight, x2-highlight,y1+highlight, x1,y1+highlight};
+ Color highlightColor = getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION);
+ gc.setBackground(highlightColor);
+ gc.fillPolygon(shape);
+ }
+ }
+ if (separator > -1) {
+ gc.setForeground(border);
+ gc.drawLine(borderLeft + highlight, separator, size.x - borderLeft - borderRight - highlight, separator);
+ }
+ gc.setForeground(gcForeground);
+}
+void onResize() {
+ Point size = getSize();
+ if (oldSize == null || oldSize.x == 0 || oldSize.y == 0) {
+ redraw();
+ } else {
+ int width = 0;
+ if (oldSize.x < size.x) {
+ width = size.x - oldSize.x + borderRight + highlight;
+ } else if (oldSize.x > size.x) {
+ width = borderRight + highlight;
+ }
+ redraw(size.x - width, 0, width, size.y, false);
+
+ int height = 0;
+ if (oldSize.y < size.y) {
+ height = size.y - oldSize.y + borderBottom + highlight;
+ }
+ if (oldSize.y > size.y) {
+ height = borderBottom + highlight;
+ }
+ redraw(0, size.y - height, size.x, height, false);
+ }
+ oldSize = size;
+}
+/**
+* Sets the content.
+* Setting the content to null will remove it from
+* the pane - however, the creator of the content must dispose of the content.
+*
+* @param content the control to be displayed in the content area or null
+*
+* @exception SWTException
+*
+*/
+public void setContent(Control content) {
+ checkWidget();
+ if (content != null && content.getParent() != this) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (this.content != null && !this.content.isDisposed()) {
+ this.content.setBounds(OFFSCREEN, OFFSCREEN, 0, 0);
+ }
+ this.content = content;
+ layout(false);
+}
+/**
+ * Sets the layout which is associated with the receiver to be
+ * the argument which may be null.
+ *
+ *
+ */
+@Override
+public void setLayout (Layout layout) {
+ checkWidget();
+ return;
+}
+void setSelectionBackground (Color color) {
+ checkWidget();
+ if (selectionBackground == color) return;
+ if (color == null) color = getDisplay().getSystemColor(SELECTION_BACKGROUND);
+ selectionBackground = color;
+ redraw();
+}
+/**
+* Set the control that appears in the top center of the pane.
+* Typically this is a toolbar.
+* The topCenter is optional. Setting the topCenter to null will remove it from
+* the pane - however, the creator of the topCenter must dispose of the topCenter.
+*
+* @param topCenter the control to be displayed in the top center or null
+*
+* @exception SWTException
+*
+*/
+public void setTopCenter(Control topCenter) {
+ checkWidget();
+ if (topCenter != null && topCenter.getParent() != this) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (this.topCenter != null && !this.topCenter.isDisposed()) {
+ Point size = this.topCenter.getSize();
+ this.topCenter.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
+ }
+ this.topCenter = topCenter;
+ layout(false);
+}
+/**
+* Set the control that appears in the top left corner of the pane.
+* Typically this is a label such as CLabel.
+* The topLeft is optional. Setting the top left control to null will remove it from
+* the pane - however, the creator of the control must dispose of the control.
+*
+* @param c the control to be displayed in the top left corner or null
+*
+* @exception SWTException
+*
+*/
+public void setTopLeft(Control c) {
+ checkWidget();
+ if (c != null && c.getParent() != this) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (this.topLeft != null && !this.topLeft.isDisposed()) {
+ Point size = this.topLeft.getSize();
+ this.topLeft.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
+ }
+ this.topLeft = c;
+ layout(false);
+}
+/**
+* Set the control that appears in the top right corner of the pane.
+* Typically this is a Close button or a composite with a Menu and Close button.
+* The topRight is optional. Setting the top right control to null will remove it from
+* the pane - however, the creator of the control must dispose of the control.
+*
+* @param c the control to be displayed in the top right corner or null
+*
+* @exception SWTException
+*
+*/
+public void setTopRight(Control c) {
+ checkWidget();
+ if (c != null && c.getParent() != this) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (this.topRight != null && !this.topRight.isDisposed()) {
+ Point size = this.topRight.getSize();
+ this.topRight.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
+ }
+ this.topRight = c;
+ layout(false);
+}
+/**
+* Specify whether the border should be displayed or not.
+*
+* @param show true if the border should be displayed
+*
+* @exception SWTException
+*
+*/
+public void setBorderVisible(boolean show) {
+ checkWidget();
+ if (showBorder == show) return;
+
+ showBorder = show;
+ if (showBorder) {
+ borderLeft = borderTop = borderRight = borderBottom = 1;
+ if ((getStyle() & SWT.FLAT)== 0) highlight = 2;
+ } else {
+ borderBottom = borderTop = borderLeft = borderRight = 0;
+ highlight = 0;
+ }
+ layout(false);
+ redraw();
+}
+/**
+* If true, the topCenter will always appear on a separate line by itself, otherwise the
+* topCenter will appear in the top row if there is room and will be moved to the second row if
+* required.
+*
+* @param show true if the topCenter will always appear on a separate line by itself
+*
+* @exception SWTException
+*
+*/
+public void setTopCenterSeparate(boolean show) {
+ checkWidget();
+ separateTopCenter = show;
+ layout(false);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ViewFormLayout.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ViewFormLayout.java
new file mode 100644
index 000000000..c9245b49b
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/ViewFormLayout.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.custom;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides the layout for ViewForm
+ *
+ * @see ViewForm
+ */
+class ViewFormLayout extends Layout {
+
+@Override
+protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
+ ViewForm form = (ViewForm)composite;
+ Control left = form.topLeft;
+ Control center = form.topCenter;
+ Control right = form.topRight;
+ Control content = form.content;
+
+ Point leftSize = new Point(0, 0);
+ if (left != null) {
+ leftSize = computeChildSize(left, SWT.DEFAULT, SWT.DEFAULT, flushCache);
+ }
+ Point centerSize = new Point(0, 0);
+ if (center != null) {
+ centerSize = computeChildSize(center, SWT.DEFAULT, SWT.DEFAULT, flushCache);
+ }
+ Point rightSize = new Point(0, 0);
+ if (right != null) {
+ rightSize = computeChildSize(right, SWT.DEFAULT, SWT.DEFAULT, flushCache);
+ }
+ Point size = new Point(0, 0);
+ // calculate width of title bar
+ if (form.separateTopCenter ||
+ (wHint != SWT.DEFAULT && leftSize.x + centerSize.x + rightSize.x > wHint)) {
+ size.x = leftSize.x + rightSize.x;
+ if (leftSize.x > 0 && rightSize.x > 0) size.x += form.horizontalSpacing;
+ size.x = Math.max(centerSize.x, size.x);
+ size.y = Math.max(leftSize.y, rightSize.y);
+ if (center != null){
+ size.y += centerSize.y;
+ if (left != null ||right != null)size.y += form.verticalSpacing;
+ }
+ } else {
+ size.x = leftSize.x + centerSize.x + rightSize.x;
+ int count = -1;
+ if (leftSize.x > 0) count++;
+ if (centerSize.x > 0) count++;
+ if (rightSize.x > 0) count++;
+ if (count > 0) size.x += count * form.horizontalSpacing;
+ size.y = Math.max(leftSize.y, Math.max(centerSize.y, rightSize.y));
+ }
+
+ if (content != null) {
+ if (left != null || right != null || center != null) size.y += 1; // allow space for a vertical separator
+ Point contentSize = new Point(0, 0);
+ contentSize = computeChildSize(content, SWT.DEFAULT, SWT.DEFAULT, flushCache);
+ size.x = Math.max (size.x, contentSize.x);
+ size.y += contentSize.y;
+ if (size.y > contentSize.y) size.y += form.verticalSpacing;
+ }
+
+ size.x += 2*form.marginWidth;
+ size.y += 2*form.marginHeight;
+
+ if (wHint != SWT.DEFAULT) size.x = wHint;
+ if (hHint != SWT.DEFAULT) size.y = hHint;
+
+ return size;
+}
+
+Point computeChildSize(Control control, int wHint, int hHint, boolean flushCache) {
+ Object data = control.getLayoutData();
+ if (data == null || !(data instanceof CLayoutData)) {
+ data = new CLayoutData();
+ control.setLayoutData(data);
+ }
+ return ((CLayoutData)data).computeSize(control, wHint, hHint, flushCache);
+}
+
+int computeTrim(Control c) {
+ if (c instanceof Scrollable) {
+ Rectangle rect = ((Scrollable) c).computeTrim (0, 0, 0, 0);
+ return rect.width;
+ }
+ return c.getBorderWidth () * 2;
+}
+
+@Override
+protected boolean flushCache(Control control) {
+ Object data = control.getLayoutData();
+ if (data != null && data instanceof CLayoutData) ((CLayoutData)data).flushCache();
+ return true;
+}
+
+@Override
+protected void layout(Composite composite, boolean flushCache) {
+ ViewForm form = (ViewForm)composite;
+ Control left = form.topLeft;
+ Control center = form.topCenter;
+ Control right = form.topRight;
+ Control content = form.content;
+
+ Rectangle rect = composite.getClientArea();
+
+ Point leftSize = new Point(0, 0);
+ if (left != null && !left.isDisposed()) {
+ leftSize = computeChildSize(left, SWT.DEFAULT, SWT.DEFAULT, flushCache);
+ }
+ Point centerSize = new Point(0, 0);
+ if (center != null && !center.isDisposed()) {
+ centerSize = computeChildSize(center, SWT.DEFAULT, SWT.DEFAULT, flushCache);
+ }
+ Point rightSize = new Point(0, 0);
+ if (right != null && !right.isDisposed()) {
+ rightSize = computeChildSize(right, SWT.DEFAULT, SWT.DEFAULT, flushCache);
+ }
+
+ int minTopWidth = leftSize.x + centerSize.x + rightSize.x + 2*form.marginWidth + 2*form.highlight;
+ int count = -1;
+ if (leftSize.x > 0) count++;
+ if (centerSize.x > 0) count++;
+ if (rightSize.x > 0) count++;
+ if (count > 0) minTopWidth += count * form.horizontalSpacing;
+
+ int x = rect.x + rect.width - form.marginWidth - form.highlight;
+ int y = rect.y + form.marginHeight + form.highlight;
+
+ boolean top = false;
+ if (form.separateTopCenter || minTopWidth > rect.width) {
+ int topHeight = Math.max(rightSize.y, leftSize.y);
+ if (right != null && !right.isDisposed()) {
+ top = true;
+ x -= rightSize.x;
+ right.setBounds(x, y, rightSize.x, topHeight);
+ x -= form.horizontalSpacing;
+ }
+ if (left != null && !left.isDisposed()) {
+ top = true;
+ int trim = computeTrim(left);
+ int leftW = x - rect.x - form.marginWidth - form.highlight - trim;
+ leftSize = computeChildSize(left, leftW, SWT.DEFAULT, false);
+ left.setBounds(rect.x + form.marginWidth + form.highlight, y, leftSize.x, topHeight);
+ }
+ if (top) y += topHeight + form.verticalSpacing;
+ if (center != null && !center.isDisposed()) {
+ top = true;
+ int trim = computeTrim(center);
+ int w = rect.width - 2*form.marginWidth - 2*form.highlight - trim;
+ Point size = computeChildSize(center, w, SWT.DEFAULT, false);
+ if (size.x < centerSize.x) {
+ centerSize = size;
+ }
+ center.setBounds(rect.x + rect.width - form.marginWidth - form.highlight - centerSize.x, y, centerSize.x, centerSize.y);
+ y += centerSize.y + form.verticalSpacing;
+ }
+ } else {
+ int topHeight = Math.max(rightSize.y, Math.max(centerSize.y, leftSize.y));
+ if (right != null && !right.isDisposed()) {
+ top = true;
+ x -= rightSize.x;
+ right.setBounds(x, y, rightSize.x, topHeight);
+ x -= form.horizontalSpacing;
+ }
+ if (center != null && !center.isDisposed()) {
+ top = true;
+ x -= centerSize.x;
+ center.setBounds(x, y, centerSize.x, topHeight);
+ x -= form.horizontalSpacing;
+ }
+ if (left != null && !left.isDisposed()) {
+ top = true;
+ Rectangle trim = left instanceof Composite ? ((Composite)left).computeTrim(0, 0, 0, 0) : new Rectangle(0, 0, 0, 0);
+ int w = x - rect.x - form.marginWidth - form.highlight - trim.width;
+ int h = topHeight - trim.height;
+ leftSize = computeChildSize(left, w, h, false);
+ left.setBounds(rect.x + form.marginWidth + form.highlight, y, leftSize.x, topHeight);
+ }
+ if (top)y += topHeight + form.verticalSpacing;
+ }
+ int oldSeperator = form.separator;
+ form.separator = -1;
+ if (content != null && !content.isDisposed()) {
+ if (left != null || right!= null || center != null){
+ form.separator = y;
+ y++;
+ }
+ content.setBounds(rect.x + form.marginWidth + form.highlight, y, rect.width - 2 * form.marginWidth - 2*form.highlight, rect.y + rect.height - y - form.marginHeight - form.highlight);
+ }
+ if (oldSeperator != form.separator) {
+ int t, b;
+ if (oldSeperator == -1) {
+ t = form.separator;
+ b = form.separator + 1;
+ } else if (form.separator == -1) {
+ t = oldSeperator;
+ b = oldSeperator + 1;
+ } else {
+ t = Math.min(form.separator, oldSeperator);
+ b = Math.max(form.separator, oldSeperator);
+ }
+ form.redraw(form.borderLeft, t, form.getSize().x - form.borderLeft - form.borderRight, b - t, false);
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/package.html b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/package.html
new file mode 100644
index 000000000..3011a3fee
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/package.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+Package Specification
+This package contains the custom widgets which were written to provide the
+standard look and feel of the Eclipse platform.
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/ByteArrayTransfer.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/ByteArrayTransfer.java
new file mode 100644
index 000000000..3dee95c0e
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/ByteArrayTransfer.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * The class ByteArrayTransfer
provides a platform specific
+ * mechanism for converting a java byte[]
to a platform
+ * specific representation of the byte array and vice versa.
+ *
+ * ByteArrayTransfer
is never used directly but is sub-classed
+ * by transfer agents that convert between data in a java format such as a
+ * String
and a platform specific byte array.
+ *
+ * byte[]
, you should sub-class Transfer
directly
+ * and do your own mapping to a platform data type.MyType
.
+ *
+ *
+ * public class MyType {
+ * public String fileName;
+ * public long fileLength;
+ * public long lastModified;
+ * }
+ *
+ *
+ * @see Transfer
+ */
+public abstract class ByteArrayTransfer extends Transfer {
+
+@Override
+public TransferData[] getSupportedTypes() {
+ int[] types = getTypeIds();
+ TransferData[] data = new TransferData[types.length];
+ for (int i = 0; i < types.length; i++) {
+ data[i] = new TransferData();
+ data[i].type = types[i];
+ data[i].formatetc = new FORMATETC();
+ data[i].formatetc.cfFormat = types[i];
+ data[i].formatetc.dwAspect = COM.DVASPECT_CONTENT;
+ data[i].formatetc.lindex = -1;
+ data[i].formatetc.tymed = COM.TYMED_HGLOBAL;
+ }
+ return data;
+}
+
+@Override
+public boolean isSupportedType(TransferData transferData){
+ if (transferData == null) return false;
+ int[] types = getTypeIds();
+ for (int i = 0; i < types.length; i++) {
+ FORMATETC format = transferData.formatetc;
+ if (format.cfFormat == types[i] &&
+ (format.dwAspect & COM.DVASPECT_CONTENT) == COM.DVASPECT_CONTENT &&
+ (format.tymed & COM.TYMED_HGLOBAL) == COM.TYMED_HGLOBAL )
+ return true;
+ }
+ return false;
+}
+
+/**
+ * This implementation of
+ * public class MyTypeTransfer extends ByteArrayTransfer {
+ *
+ * private static final String MYTYPENAME = "my_type_name";
+ * private static final int MYTYPEID = registerType(MYTYPENAME);
+ * private static MyTypeTransfer _instance = new MyTypeTransfer();
+ *
+ * private MyTypeTransfer() {}
+ *
+ * public static MyTypeTransfer getInstance () {
+ * return _instance;
+ * }
+ * public void javaToNative (Object object, TransferData transferData) {
+ * if (object == null || !(object instanceof MyType[])) return;
+ *
+ * if (isSupportedType(transferData)) {
+ * MyType[] myTypes = (MyType[]) object;
+ * try {
+ * // write data to a byte array and then ask super to convert to pMedium
+ * ByteArrayOutputStream out = new ByteArrayOutputStream();
+ * DataOutputStream writeOut = new DataOutputStream(out);
+ * for (int i = 0, length = myTypes.length; i < length; i++){
+ * byte[] buffer = myTypes[i].fileName.getBytes();
+ * writeOut.writeInt(buffer.length);
+ * writeOut.write(buffer);
+ * writeOut.writeLong(myTypes[i].fileLength);
+ * writeOut.writeLong(myTypes[i].lastModified);
+ * }
+ * byte[] buffer = out.toByteArray();
+ * writeOut.close();
+ *
+ * super.javaToNative(buffer, transferData);
+ *
+ * } catch (IOException e) {
+ * }
+ * }
+ * }
+ * public Object nativeToJava(TransferData transferData){
+ *
+ * if (isSupportedType(transferData)) {
+ *
+ * byte[] buffer = (byte[])super.nativeToJava(transferData);
+ * if (buffer == null) return null;
+ *
+ * MyType[] myData = new MyType[0];
+ * try {
+ * ByteArrayInputStream in = new ByteArrayInputStream(buffer);
+ * DataInputStream readIn = new DataInputStream(in);
+ * while(readIn.available() > 20) {
+ * MyType datum = new MyType();
+ * int size = readIn.readInt();
+ * byte[] name = new byte[size];
+ * readIn.read(name);
+ * datum.fileName = new String(name);
+ * datum.fileLength = readIn.readLong();
+ * datum.lastModified = readIn.readLong();
+ * MyType[] newMyData = new MyType[myData.length + 1];
+ * System.arraycopy(myData, 0, newMyData, 0, myData.length);
+ * newMyData[myData.length] = datum;
+ * myData = newMyData;
+ * }
+ * readIn.close();
+ * } catch (IOException ex) {
+ * return null;
+ * }
+ * return myData;
+ * }
+ *
+ * return null;
+ * }
+ * protected String[] getTypeNames(){
+ * return new String[]{MYTYPENAME};
+ * }
+ * protected int[] getTypeIds(){
+ * return new int[] {MYTYPEID};
+ * }
+ * }
+ *
javaToNative
converts a java
+ * byte[]
to a platform specific representation.
+ *
+ * @param object a java byte[]
containing the data to be converted
+ * @param transferData an empty TransferData
object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+@Override
+protected void javaToNative (Object object, TransferData transferData) {
+ if (!checkByteArray(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ // Allocate the memory because the caller (DropTarget) has not handed it in
+ // The caller of this method must release the data when it is done with it.
+ byte[] data = (byte[])object;
+ int size = data.length;
+ long newPtr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, size);
+ OS.MoveMemory(newPtr, data, size);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = newPtr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+}
+
+/**
+ * This implementation of nativeToJava
converts a platform specific
+ * representation of a byte array to a java byte[]
.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java byte[]
containing the converted data if the conversion was
+ * successful; otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+@Override
+protected Object nativeToJava(TransferData transferData) {
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ FORMATETC formatetc = transferData.formatetc;
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ long hMem = stgmedium.unionField;
+ int size = OS.GlobalSize(hMem);
+ byte[] buffer = new byte[size];
+ long ptr = OS.GlobalLock(hMem);
+ OS.MoveMemory(buffer, ptr, size);
+ OS.GlobalUnlock(hMem);
+ OS.GlobalFree(hMem);
+ return buffer;
+}
+
+boolean checkByteArray(Object object) {
+ return (object != null && object instanceof byte[] && ((byte[])object).length > 0);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/Clipboard.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/Clipboard.java
new file mode 100644
index 000000000..67b9b4b7e
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/Clipboard.java
@@ -0,0 +1,808 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * The Clipboard
provides a mechanism for transferring data from one
+ * application to another or within an application.
+ *
+ *
+ *
+ *
+ * @see Clipboard#dispose
+ * @see Clipboard#checkSubclass
+ */
+public Clipboard(Display display) {
+ checkSubclass ();
+ if (display == null) {
+ display = Display.getCurrent();
+ if (display == null) {
+ display = Display.getDefault();
+ }
+ }
+ if (display.getThread() != Thread.currentThread()) {
+ DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
+ }
+ this.display = display;
+ TCHAR chFormatName = new TCHAR(0, "Preferred DropEffect", true); //$NON-NLS-1$
+ CFSTR_PREFERREDDROPEFFECT = OS.RegisterClipboardFormat(chFormatName);
+ createCOMInterfaces();
+ this.AddRef();
+}
+
+/**
+ * Checks that this class can be subclassed.
+ *
+ *
+ */
+protected void checkSubclass () {
+ String name = getClass().getName ();
+ String validName = Clipboard.class.getName();
+ if (!validName.equals(name)) {
+ DND.error (SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+
+/**
+ * Throws an SWTException
if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method should be called by
+ * widget implementors to enforce the standard SWT invariants.
+ * isDisposed()
) on a widget that has had its
+ * dispose()
method called. It is also an error
+ * to call widget methods from any thread that is different
+ * from the thread that created the widget.
+ *
+ *
+ */
+protected void checkWidget () {
+ Display display = this.display;
+ if (display == null) DND.error (SWT.ERROR_WIDGET_DISPOSED);
+ if (display.getThread() != Thread.currentThread ()) DND.error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ if (display.isDisposed()) DND.error(SWT.ERROR_WIDGET_DISPOSED);
+}
+
+/**
+ * If this clipboard is currently the owner of the data on the system clipboard,
+ * clear the contents. If this clipboard is not the owner, then nothing is done.
+ * Note that there are clipboard assistant applications that take ownership of
+ * data or make copies of data when it is placed on the clipboard. In these
+ * cases, it may not be possible to clear the clipboard.
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.1
+ */
+public void clearContents() {
+ clearContents(DND.CLIPBOARD);
+}
+
+/**
+ * If this clipboard is currently the owner of the data on the specified
+ * clipboard, clear the contents. If this clipboard is not the owner, then
+ * nothing is done.
+ *
+ * DND
, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those DND
clipboard constants.
+ *
+ *
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public void clearContents(int clipboards) {
+ checkWidget();
+ if ((clipboards & DND.CLIPBOARD) != 0) {
+ /* OleIsCurrentClipboard([in] pDataObject)
+ * The argument pDataObject is owned by the caller so reference count does not
+ * need to be incremented.
+ */
+ if (COM.OleIsCurrentClipboard(this.iDataObject.getAddress()) == COM.S_OK) {
+ /* OleSetClipboard([in] pDataObject)
+ * The argument pDataObject is owned by the caller so reference count does not
+ * need to be incremented.
+ */
+ COM.OleSetClipboard(0);
+ }
+ }
+}
+
+/**
+ * Disposes of the operating system resources associated with the clipboard.
+ * The data will still be available on the system clipboard after the dispose
+ * method is called.
+ *
+ *
+ *
+ */
+public void dispose () {
+ if (isDisposed()) return;
+ if (display.getThread() != Thread.currentThread()) DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
+ /* OleIsCurrentClipboard([in] pDataObject)
+ * The argument pDataObject is owned by the caller so reference count does not
+ * need to be incremented.
+ */
+ if (COM.OleIsCurrentClipboard(this.iDataObject.getAddress()) == COM.S_OK) {
+ COM.OleFlushClipboard();
+ }
+ this.Release();
+ display = null;
+}
+
+/**
+ * Retrieve the data of the specified type currently available on the system
+ * clipboard. Refer to the specific subclass of Transfer
to
+ * determine the type of object returned.
+ *
+ *
+ *
+ * @param transfer the transfer agent for the type of data being requested
+ * @return the data obtained from the clipboard or null if no data of this type is available
+ *
+ * @exception SWTException
+ * Clipboard clipboard = new Clipboard(display);
+ * TextTransfer textTransfer = TextTransfer.getInstance();
+ * String textData = (String)clipboard.getContents(textTransfer);
+ * if (textData != null) System.out.println("Text is "+textData);
+ * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ * String rtfData = (String)clipboard.getContents(rtfTransfer);
+ * if (rtfData != null) System.out.println("RTF Text is "+rtfData);
+ * clipboard.dispose();
+ *
+ *
+ * @exception IllegalArgumentException
+ *
+ *
+ * @see Transfer
+ */
+public Object getContents(Transfer transfer) {
+ return getContents(transfer, DND.CLIPBOARD);
+}
+/**
+ * Retrieve the data of the specified type currently available on the specified
+ * clipboard. Refer to the specific subclass of Transfer
to
+ * determine the type of object returned.
+ *
+ *
+ *
+ *
+ * Clipboard clipboard = new Clipboard(display);
+ * TextTransfer textTransfer = TextTransfer.getInstance();
+ * String textData = (String)clipboard.getContents(textTransfer);
+ * if (textData != null) System.out.println("Text is "+textData);
+ * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ * String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD);
+ * if (rtfData != null) System.out.println("RTF Text is "+rtfData);
+ * clipboard.dispose();
+ *
DND
, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those DND
clipboard constants.
+ *
+ * @exception IllegalArgumentException
+ *
+ *
+ * @see Transfer
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public Object getContents(Transfer transfer, int clipboards) {
+ checkWidget();
+ if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
+ if ((clipboards & DND.CLIPBOARD) == 0) return null;
+ /*
+ * Bug in Windows. When a new application takes control
+ * of the clipboard, other applications may open the
+ * clipboard to determine if they want to record the
+ * clipboard updates. When this happens, the clipboard
+ * can not be accessed until the other application is
+ * finished. To allow the other applications to release
+ * the clipboard, use PeekMessage() to enable cross thread
+ * message sends.
+ */
+ long[] ppv = new long[1];
+ int retryCount = 0;
+ /* OleGetClipboard([out] ppDataObject).
+ * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
+ */
+ int result = COM.OleGetClipboard(ppv);
+ while (result != COM.S_OK && retryCount++ < RETRY_LIMIT) {
+ try {Thread.sleep(50);} catch (Throwable t) {}
+ MSG msg = new MSG();
+ OS.PeekMessage(msg, 0, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
+ result = COM.OleGetClipboard(ppv);
+ }
+ if (result != COM.S_OK) return null;
+ IDataObject dataObject = new IDataObject(ppv[0]);
+ try {
+ TransferData[] allowed = transfer.getSupportedTypes();
+ for (int i = 0; i < allowed.length; i++) {
+ if (dataObject.QueryGetData(allowed[i].formatetc) == COM.S_OK) {
+ TransferData data = allowed[i];
+ data.pIDataObject = ppv[0];
+ return transfer.nativeToJava(data);
+ }
+ }
+ } finally {
+ dataObject.Release();
+ }
+ return null; // No data available for this transfer
+}
+/**
+ * Returns true
if the clipboard has been disposed,
+ * and false
otherwise.
+ * true
when the widget is disposed and false
otherwise
+ *
+ * @since 3.0
+ */
+public boolean isDisposed () {
+ return (display == null);
+}
+
+/**
+ * Place data of the specified type on the system clipboard. More than one type
+ * of data can be placed on the system clipboard at the same time. Setting the
+ * data clears any previous data from the system clipboard, regardless of type.
+ *
+ *
+ *
+ * @param data the data to be set in the clipboard
+ * @param dataTypes the transfer agents that will convert the data to its
+ * platform specific format; each entry in the data array must have a
+ * corresponding dataType
+ *
+ * @exception IllegalArgumentException
+ * Clipboard clipboard = new Clipboard(display);
+ * String textData = "Hello World";
+ * String rtfData = "{\\rtf1\\b\\i Hello World}";
+ * TextTransfer textTransfer = TextTransfer.getInstance();
+ * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
+ * Object[] data = new Object[]{textData, rtfData};
+ * clipboard.setContents(data, transfers);
+ * clipboard.dispose();
+ *
+ *
+ * @exception SWTException
+ *
+ * @exception SWTError
+ *
+ *
+ * DND
, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those DND
clipboard constants.
+ *
+ * @param data the data to be set in the clipboard
+ * @param dataTypes the transfer agents that will convert the data to its
+ * platform specific format; each entry in the data array must have a
+ * corresponding dataType
+ * @param clipboards on which to set the data
+ *
+ * @exception IllegalArgumentException
+ * Clipboard clipboard = new Clipboard(display);
+ * String textData = "Hello World";
+ * String rtfData = "{\\rtf1\\b\\i Hello World}";
+ * TextTransfer textTransfer = TextTransfer.getInstance();
+ * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
+ * Object[] data = new Object[]{textData, rtfData};
+ * clipboard.setContents(data, transfers, DND.CLIPBOARD);
+ * clipboard.dispose();
+ *
+ *
+ * @exception SWTException
+ *
+ * @exception SWTError
+ *
+ *
+ *
+ *
+ *
+ * @see Transfer#isSupportedType
+ *
+ * @since 3.0
+ */
+public TransferData[] getAvailableTypes() {
+ return getAvailableTypes(DND.CLIPBOARD);
+}
+
+/**
+ * Returns an array of the data types currently available on the specified
+ * clipboard. Use with Transfer.isSupportedType.
+ *
+ * DND
, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those DND
clipboard constants.
+ *
+ *
+ * @see Transfer#isSupportedType
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public TransferData[] getAvailableTypes(int clipboards) {
+ checkWidget();
+ if ((clipboards & DND.CLIPBOARD) == 0) return new TransferData[0];
+ FORMATETC[] types = _getAvailableTypes();
+ TransferData[] data = new TransferData[types.length];
+ for (int i = 0; i < types.length; i++) {
+ data[i] = new TransferData();
+ data[i].type = types[i].cfFormat;
+ data[i].formatetc = types[i];
+ }
+ return data;
+}
+
+/**
+ * Returns a platform specific list of the data types currently available on the
+ * system clipboard.
+ *
+ * getAvailableTypeNames
is a utility for writing a Transfer
+ * sub-class. It should NOT be used within an application because it provides
+ * platform specific information.
+ *
+ */
+public String[] getAvailableTypeNames() {
+ checkWidget();
+ FORMATETC[] types = _getAvailableTypes();
+ String[] names = new String[types.length];
+ int maxSize = 128;
+ for (int i = 0; i < types.length; i++){
+ char [] buffer = new char [maxSize];
+ int size = OS.GetClipboardFormatName(types[i].cfFormat, buffer, maxSize);
+ if (size != 0) {
+ names[i] = new String (buffer, 0, size);
+ } else {
+ switch (types[i].cfFormat) {
+ case COM.CF_HDROP: names[i] = "CF_HDROP"; break; //$NON-NLS-1$
+ case COM.CF_TEXT: names[i] = "CF_TEXT"; break; //$NON-NLS-1$
+ case COM.CF_BITMAP: names[i] = "CF_BITMAP"; break; //$NON-NLS-1$
+ case COM.CF_METAFILEPICT: names[i] = "CF_METAFILEPICT"; break; //$NON-NLS-1$
+ case COM.CF_SYLK: names[i] = "CF_SYLK"; break; //$NON-NLS-1$
+ case COM.CF_DIF: names[i] = "CF_DIF"; break; //$NON-NLS-1$
+ case COM.CF_TIFF: names[i] = "CF_TIFF"; break; //$NON-NLS-1$
+ case COM.CF_OEMTEXT: names[i] = "CF_OEMTEXT"; break; //$NON-NLS-1$
+ case COM.CF_DIB: names[i] = "CF_DIB"; break; //$NON-NLS-1$
+ case COM.CF_PALETTE: names[i] = "CF_PALETTE"; break; //$NON-NLS-1$
+ case COM.CF_PENDATA: names[i] = "CF_PENDATA"; break; //$NON-NLS-1$
+ case COM.CF_RIFF: names[i] = "CF_RIFF"; break; //$NON-NLS-1$
+ case COM.CF_WAVE: names[i] = "CF_WAVE"; break; //$NON-NLS-1$
+ case COM.CF_UNICODETEXT: names[i] = "CF_UNICODETEXT"; break; //$NON-NLS-1$
+ case COM.CF_ENHMETAFILE: names[i] = "CF_ENHMETAFILE"; break; //$NON-NLS-1$
+ case COM.CF_LOCALE: names[i] = "CF_LOCALE"; break; //$NON-NLS-1$
+ case COM.CF_MAX: names[i] = "CF_MAX"; break; //$NON-NLS-1$
+ default: names[i] = "UNKNOWN"; //$NON-NLS-1$
+ }
+ }
+ }
+ return names;
+}
+
+private FORMATETC[] _getAvailableTypes() {
+ FORMATETC[] types = new FORMATETC[0];
+ long[] ppv = new long[1];
+ /* OleGetClipboard([out] ppDataObject).
+ * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
+ */
+ if (COM.OleGetClipboard(ppv) != COM.S_OK) return types;
+ IDataObject dataObject = new IDataObject(ppv[0]);
+ long[] ppFormatetc = new long[1];
+ /* EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
+ * AddRef has already been called on ppenumFormatetc by the callee and must be released by the caller.
+ */
+ int rc = dataObject.EnumFormatEtc(COM.DATADIR_GET, ppFormatetc);
+ dataObject.Release();
+ if (rc != COM.S_OK)return types;
+ IEnumFORMATETC enumFormatetc = new IEnumFORMATETC(ppFormatetc[0]);
+ // Loop over enumerator and save any types that match what we are looking for
+ long rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof);
+ int[] pceltFetched = new int[1];
+ enumFormatetc.Reset();
+ while (enumFormatetc.Next(1, rgelt, pceltFetched) == COM.S_OK && pceltFetched[0] == 1) {
+ FORMATETC formatetc = new FORMATETC();
+ COM.MoveMemory(formatetc, rgelt, FORMATETC.sizeof);
+ FORMATETC[] newTypes = new FORMATETC[types.length + 1];
+ System.arraycopy(types, 0, newTypes, 0, types.length);
+ newTypes[types.length] = formatetc;
+ types = newTypes;
+ }
+ OS.GlobalFree(rgelt);
+ enumFormatetc.Release();
+ return types;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DND.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DND.java
new file mode 100644
index 000000000..9363386d7
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DND.java
@@ -0,0 +1,299 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2013 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+import org.eclipse.swt.*;
+
+/**
+ * Class DND contains all the constants used in defining a
+ * DragSource or a DropTarget.
+ *
+ * @see Sample code and further information
+ */
+public class DND {
+
+ /**
+ * The transfer mechanism for data that is being cut
+ * and then pasted or copied and then pasted (value is 1).
+ *
+ * @see Clipboard
+ *
+ * @since 3.1
+ */
+ public final static int CLIPBOARD = 1 << 0;
+
+ /**
+ * The transfer mechanism for clients that use the selection
+ * mechanism (value is 2).
+ *
+ * @see Clipboard
+ *
+ * @since 3.1
+ */
+ public final static int SELECTION_CLIPBOARD = 1 << 1;
+
+ /**
+ * Drag and Drop Operation: no drag/drop operation performed
+ * (value is 0).
+ */
+ public final static int DROP_NONE = 0;
+
+ /**
+ * Drag and Drop Operation: a copy of the data in the drag source is
+ * added to the drop target (value is 1 << 0).
+ */
+ public final static int DROP_COPY = 1 << 0;
+
+ /**
+ * Drag and Drop Operation: a copy of the data is added to the drop target and
+ * the drag source removes the original data and any references to the data,
+ * and updates its display (value is 1 << 1).
+ * getData(String)
. When a drop target
+ * is created for a control, it is stored as a property in the control
+ * using setData(String, Object)
.
+ *
+ * @since 3.4
+ */
+ public static final String DROP_TARGET_KEY = "DropTarget"; //$NON-NLS-1$
+
+ /**
+ * DragSource Key: The string constant for looking up the drag source
+ * for a control using getData(String)
. When a drag source
+ * is created for a control, it is stored as a property in the control
+ * using setData(String, Object)
.
+ *
+ * @since 3.4
+ */
+ public static final String DRAG_SOURCE_KEY = "DragSource"; //$NON-NLS-1$
+
+ static final String INIT_DRAG_MESSAGE = "Cannot initialize Drag"; //$NON-NLS-1$
+ static final String INIT_DROP_MESSAGE = "Cannot initialize Drop"; //$NON-NLS-1$
+ static final String CANNOT_SET_CLIPBOARD_MESSAGE = "Cannot set data in clipboard"; //$NON-NLS-1$
+ static final String INVALID_DATA_MESSAGE = "Data does not have correct format for type"; //$NON-NLS-1$
+
+/**
+ * Throws an appropriate exception based on the passed in error code.
+ *
+ * @param code the DND error code
+ */
+public static void error (int code) {
+ error (code, 0);
+}
+
+/**
+ * Throws an appropriate exception based on the passed in error code.
+ * The hresult
argument should be either 0, or the
+ * platform specific error code.
+ *
+ *
+ * DragSource
defines the source object for a drag and drop transfer.
+ *
+ * ByteArrayTransfer
.DragSourceListener
and associating it with the DragSource via DragSource#addDragListener.
+ *
+ *
+ *
+ * // Enable a label as a Drag Source
+ * Label label = new Label(shell, SWT.NONE);
+ * // This example will allow text to be dragged
+ * Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
+ * // This example will allow the text to be copied or moved to the drop target
+ * int operations = DND.DROP_MOVE | DND.DROP_COPY;
+ *
+ * DragSource source = new DragSource(label, operations);
+ * source.setTransfer(types);
+ * source.addDragListener(new DragSourceListener() {
+ * public void dragStart(DragSourceEvent e) {
+ * // Only start the drag if there is actually text in the
+ * // label - this text will be what is dropped on the target.
+ * if (label.getText().length() == 0) {
+ * event.doit = false;
+ * }
+ * };
+ * public void dragSetData(DragSourceEvent event) {
+ * // A drop has been performed, so provide the data of the
+ * // requested type.
+ * // (Checking the type of the requested data is only
+ * // necessary if the drag source supports more than
+ * // one data type but is shown here as an example).
+ * if (TextTransfer.getInstance().isSupportedType(event.dataType)){
+ * event.data = label.getText();
+ * }
+ * }
+ * public void dragFinished(DragSourceEvent event) {
+ * // A Move operation has been performed so remove the data
+ * // from the source
+ * if (event.detail == DND.DROP_MOVE)
+ * label.setText("");
+ * }
+ * });
+ *
+ *
+ *
+ * @see Drag and Drop snippets
+ * @see SWT Example: DNDExample
+ * @see Sample code and further information
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class DragSource extends Widget {
+
+ // info for registering as a drag source
+ Control control;
+ Listener controlListener;
+ Transfer[] transferAgents = new Transfer[0];
+ DragSourceEffect dragEffect;
+ Composite topControl;
+ long hwndDrag;
+
+ // ole interfaces
+ COMIDropSource iDropSource;
+ COMIDataObject iDataObject;
+
+ //workaround - track the operation performed by the drop target for DragEnd event
+ int dataEffect = DND.DROP_NONE;
+
+ static final String DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$
+ static final int CFSTR_PERFORMEDDROPEFFECT = Transfer.registerType("Performed DropEffect"); //$NON-NLS-1$
+ static final TCHAR WindowClass = new TCHAR (0, "#32770", true);
+
+ private class COMIDropSource extends COMObject {
+
+ private long refCount = 0;
+
+ /**
+ * Create a new IDropSource COM object. Object is created with one active
+ * reference. (see {@link #Release()})
+ */
+ public COMIDropSource() {
+ super(new int[]{2, 0, 0, 2, 1});
+ AddRef();
+ }
+
+ @Override
+ public long method0(long[] args) {return QueryInterface(this, args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ @Override
+ public long method3(long[] args) {return QueryContinueDrag((int)args[0], (int)args[1]);}
+ @Override
+ public long method4(long[] args) {return GiveFeedback((int)args[0]);}
+
+ public long AddRef() {
+ refCount++;
+ return refCount;
+ }
+
+ public long Release() {
+ refCount--;
+ if (refCount == 0) {
+ if (DragSource.this.iDropSource == this) {
+ DragSource.this.iDropSource = null;
+ }
+ this.dispose();
+ if (COM.FreeUnusedLibraries) {
+ COM.CoFreeUnusedLibraries();
+ }
+ }
+ return refCount;
+ }
+ }
+
+ private class COMIDataObject extends COMObject {
+ /*
+ * A SWT application is used to provide the data to drag in an event callback
+ * which is called while the DND operation is performed. However Windows expects
+ * the data to passed around in an object whose lifetime is managed through
+ * reference counting. The drop target can keep a reference on the IDataObject
+ * and even try to query the data long after the DND operation is finished. One
+ * such case is Windows Explorer when showing a Portal Device (see bug 549661).
+ * SWT does two things to support this case:
+ * 1. Implement reference counting as intended. I.e. do not force release the
+ * object after DND is finished but trust that all involved applications are
+ * able to count correctly and will release the object at some point.
+ * 2. Cache the data which was last transfered/generated from the DragSource
+ * to be able to send it again after the DND operation is finished.
+ */
+
+ private long refCount = 0;
+
+ private final Transfer[] transferAgents;
+
+ /**
+ * The most recent data send in a GetData request (or GetDataHere if
+ * implemented). Or from another perspective the data the application returned
+ * in the most recent {@link DND#DragSetData} event.
+ */
+ private Object lastData = null;
+
+ /**
+ * Create a new IDataObject COM object. Objects are created with one active
+ * reference. (see {@link #Release()})
+ *
+ * @param transferAgents should be the transfer agents which are set on
+ * DragSource at the time this object is created.
+ */
+ public COMIDataObject(Transfer[] transferAgents) {
+ super(new int[]{2, 0, 0, 2, 2, 1, 2, 3, 2, 4, 1, 1});
+ AddRef();
+ this.transferAgents = transferAgents;
+ }
+
+ @Override
+ public long method0(long[] args) {return QueryInterface(this, args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ @Override
+ public long method3(long[] args) {return GetData(args[0], args[1]);}
+ // method4 GetDataHere - not implemented
+ @Override
+ public long method5(long[] args) {return QueryGetData(transferAgents, args[0]);}
+ // method6 GetCanonicalFormatEtc - not implemented
+ @Override
+ public long method7(long[] args) {return SetData(args[0], args[1], (int)args[2]);}
+ @Override
+ public long method8(long[] args) {return EnumFormatEtc(transferAgents, (int)args[0], args[1]);}
+ // method9 DAdvise - not implemented
+ // method10 DUnadvise - not implemented
+ // method11 EnumDAdvise - not implemented
+
+ public long AddRef() {
+ refCount++;
+ return refCount;
+ }
+
+ public long Release() {
+ refCount--;
+ if (refCount == 0) {
+ if (DragSource.this.iDataObject == this) {
+ DragSource.this.iDataObject = null;
+ }
+ this.dispose();
+ if (COM.FreeUnusedLibraries) {
+ COM.CoFreeUnusedLibraries();
+ }
+ }
+ return refCount;
+ }
+
+ /**
+ * Check if this IDataObject is currently used in a DND operation.
+ *
+ * @return true if this object currently used for DND
+ */
+ private boolean isActive() {
+ return DragSource.this.iDataObject == this;
+ }
+
+ private int GetData(long pFormatetc, long pmedium) {
+ /* Called by a data consumer to obtain data from a source data object.
+ The GetData method renders the data described in the specified FORMATETC
+ structure and transfers it through the specified STGMEDIUM structure.
+ The caller then assumes responsibility for releasing the STGMEDIUM structure.
+ */
+ if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
+
+ if (QueryGetData(transferAgents, pFormatetc) != COM.S_OK) return COM.DV_E_FORMATETC;
+
+ TransferData transferData = new TransferData();
+ transferData.formatetc = new FORMATETC();
+ COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+ transferData.type = transferData.formatetc.cfFormat;
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.E_FAIL;
+
+ final Object data;
+ if (isActive()) {
+ DNDEvent event = new DNDEvent();
+ event.widget = DragSource.this;
+ event.time = OS.GetMessageTime();
+ event.dataType = transferData;
+ notifyListeners(DND.DragSetData,event);
+
+ if (!event.doit) return COM.E_FAIL;
+
+ lastData = event.data;
+ data = event.data;
+ } else {
+ if (lastData == null) {
+ return COM.E_FAIL;
+ }
+ data = lastData;
+ }
+
+ // get matching transfer agent to perform conversion
+ Transfer transfer = null;
+ for (Transfer transferAgent : transferAgents) {
+ if (transferAgent != null && transferAgent.isSupportedType(transferData)){
+ transfer = transferAgent;
+ break;
+ }
+ }
+
+ if (transfer == null) return COM.DV_E_FORMATETC;
+ transfer.javaToNative(data, transferData);
+ if (transferData.result != COM.S_OK) return transferData.result;
+ COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
+ return transferData.result;
+ }
+
+ private int SetData(long pFormatetc, long pmedium, int fRelease) {
+ if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
+ FORMATETC formatetc = new FORMATETC();
+ COM.MoveMemory(formatetc, pFormatetc, FORMATETC.sizeof);
+ if (formatetc.cfFormat == CFSTR_PERFORMEDDROPEFFECT && formatetc.tymed == COM.TYMED_HGLOBAL) {
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ COM.MoveMemory(stgmedium, pmedium,STGMEDIUM.sizeof);
+ //TODO - this should be GlobalLock()
+ long[] ptrEffect = new long[1];
+ OS.MoveMemory(ptrEffect, stgmedium.unionField, C.PTR_SIZEOF);
+ int[] effect = new int[1];
+ OS.MoveMemory(effect, ptrEffect[0], 4);
+ if (isActive()) {
+ dataEffect = osToOp(effect[0]);
+ }
+ }
+ if (fRelease == 1) {
+ COM.ReleaseStgMedium(pmedium);
+ }
+ return COM.S_OK;
+ }
+ }
+
+/**
+ * Creates a new
if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method should be called by
+ * device implementors to enforce the standard SWT invariants.
+ * DragSource
to handle dragging from the specified Control
.
+ * Creating an instance of a DragSource may cause system resources to be allocated depending on the platform.
+ * It is therefore mandatory that the DragSource instance be disposed when no longer required.
+ *
+ * @param control the Control
that the user clicks on to initiate the drag
+ * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
+ * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
+ *
+ * @exception SWTException
+ *
+ * @exception SWTError
+ *
+ *
+ * DragSourceListener
+ * interface.
+ *
+ *
+ *
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException dragStart
is called when the user has begun the actions required to drag the widget.
+ * This event gives the application the chance to decide if a drag should be started.
+ * dragSetData
is called when the data is required from the drag source.
+ * dragFinished
is called when the drop has successfully completed (mouse up
+ * over a valid target) or has been terminated (such as hitting the ESC key). Perform cleanup
+ * such as removing data from the source side on a successful move operation.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DragSourceListener
+ * @see #getDragListeners
+ * @see #removeDragListener
+ * @see DragSourceEvent
+ */
+public void addDragListener(DragSourceListener listener) {
+ if (listener == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
+ DNDListener typedListener = new DNDListener(listener);
+ typedListener.dndWidget = this;
+ addListener(DND.DragStart, typedListener);
+ addListener(DND.DragSetData, typedListener);
+ addListener(DND.DragEnd, typedListener);
+}
+
+private void createCOMInterfaces() {
+ releaseCOMInterfaces();
+ iDropSource = new COMIDropSource();
+ iDataObject = new COMIDataObject(transferAgents);
+}
+
+@Override
+protected void checkSubclass() {
+ String name = getClass().getName();
+ String validName = DragSource.class.getName();
+ if (!validName.equals(name)) {
+ DND.error(SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+
+private void releaseCOMInterfaces() {
+ if (iDropSource != null)
+ iDropSource.Release();
+ iDropSource = null;
+
+ if (iDataObject != null)
+ iDataObject.Release();
+ iDataObject = null;
+}
+
+private void drag(Event dragEvent) {
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.x = dragEvent.x;
+ event.y = dragEvent.y;
+ event.time = OS.GetMessageTime();
+ event.doit = true;
+ notifyListeners(DND.DragStart,event);
+ if (!event.doit || transferAgents == null || transferAgents.length == 0 ) return;
+
+ int[] pdwEffect = new int[1];
+ int operations = opToOs(getStyle());
+ Display display = control.getDisplay();
+ String key = "org.eclipse.swt.internal.win32.runMessagesInIdle"; //$NON-NLS-1$
+ Object oldValue = display.getData(key);
+ display.setData(key, Boolean.TRUE);
+ ImageList imagelist = null;
+ Image image = event.image;
+ hwndDrag = 0;
+ topControl = null;
+ if (image != null) {
+ imagelist = new ImageList(SWT.NONE);
+ imagelist.add(image);
+ topControl = control.getShell();
+ /*
+ * Bug in Windows. The image is inverted if the shell is RIGHT_TO_LEFT.
+ * The fix is to create a transparent window that covers the shell client
+ * area and use it during the drag to prevent the image from being inverted.
+ * On XP if the shell is RTL, the image is not displayed.
+ */
+ int offsetX = event.offsetX;
+ hwndDrag = topControl.handle;
+ if ((topControl.getStyle() & SWT.RIGHT_TO_LEFT) != 0) {
+ offsetX = image.getBoundsInPixels().width - offsetX;
+ RECT rect = new RECT ();
+ OS.GetClientRect (topControl.handle, rect);
+ hwndDrag = OS.CreateWindowEx (
+ OS.WS_EX_TRANSPARENT | OS.WS_EX_NOINHERITLAYOUT,
+ WindowClass,
+ null,
+ OS.WS_CHILD | OS.WS_CLIPSIBLINGS,
+ 0, 0,
+ rect.right - rect.left, rect.bottom - rect.top,
+ topControl.handle,
+ 0,
+ OS.GetModuleHandle (null),
+ null);
+ OS.ShowWindow (hwndDrag, OS.SW_SHOW);
+ }
+ OS.ImageList_BeginDrag(imagelist.getHandle(), 0, offsetX, event.offsetY);
+ /*
+ * Feature in Windows. When ImageList_DragEnter() is called,
+ * it takes a snapshot of the screen If a drag is started
+ * when another window is in front, then the snapshot will
+ * contain part of the other window, causing pixel corruption.
+ * The fix is to force all paints to be delivered before
+ * calling ImageList_DragEnter().
+ */
+ int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (topControl.handle, null, 0, flags);
+ POINT pt = new POINT ();
+ pt.x = DPIUtil.autoScaleUp(dragEvent.x);// To Pixels
+ pt.y = DPIUtil.autoScaleUp(dragEvent.y);// To Pixels
+ OS.MapWindowPoints (control.handle, 0, pt, 1);
+ RECT rect = new RECT ();
+ OS.GetWindowRect (hwndDrag, rect);
+ OS.ImageList_DragEnter(hwndDrag, pt.x - rect.left, pt.y - rect.top);
+ }
+ String externalLoopKey = "org.eclipse.swt.internal.win32.externalEventLoop";
+ int result = COM.DRAGDROP_S_CANCEL;
+ try {
+ createCOMInterfaces();
+ display.setData(externalLoopKey, Boolean.TRUE);
+ result = COM.DoDragDrop(iDataObject.getAddress(), iDropSource.getAddress(), operations, pdwEffect);
+ } finally {
+ display.setData(externalLoopKey, Boolean.FALSE);
+ // ensure that we don't leave transparent window around
+ if (hwndDrag != 0) {
+ OS.ImageList_DragLeave(hwndDrag);
+ OS.ImageList_EndDrag();
+ imagelist.dispose();
+ if (hwndDrag != topControl.handle) OS.DestroyWindow(hwndDrag);
+ hwndDrag = 0;
+ topControl = null;
+ }
+ display.setData(key, oldValue);
+ releaseCOMInterfaces();
+ }
+ int operation = osToOp(pdwEffect[0]);
+ if (dataEffect == DND.DROP_MOVE) {
+ operation = (operation == DND.DROP_NONE || operation == DND.DROP_COPY) ? DND.DROP_TARGET_MOVE : DND.DROP_MOVE;
+ } else {
+ if (dataEffect != DND.DROP_NONE) {
+ operation = dataEffect;
+ }
+ }
+
+ event = new DNDEvent();
+ event.widget = this;
+ event.time = OS.GetMessageTime();
+ event.doit = (result == COM.DRAGDROP_S_DROP);
+ event.detail = operation;
+ notifyListeners(DND.DragEnd,event);
+ dataEffect = DND.DROP_NONE;
+}
+/*
+ * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
+ * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc
+ * must be incremented before returning. Caller is responsible for releasing ppenumFormatetc.
+ */
+private static int EnumFormatEtc(Transfer[] transferAgents, int dwDirection, long ppenumFormatetc) {
+ // only allow getting of data - SetData is not currently supported
+ if (dwDirection == COM.DATADIR_SET) return COM.E_NOTIMPL;
+
+ // what types have been registered?
+ TransferData[] allowedDataTypes = new TransferData[0];
+ for (Transfer transferAgent : transferAgents) {
+ if (transferAgent != null) {
+ TransferData[] formats = transferAgent.getSupportedTypes();
+ TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length];
+ System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length);
+ System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length);
+ allowedDataTypes = newAllowedDataTypes;
+ }
+ }
+
+ OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC();
+ enumFORMATETC.AddRef();
+
+ FORMATETC[] formats = new FORMATETC[allowedDataTypes.length];
+ for (int i = 0; i < formats.length; i++){
+ formats[i] = allowedDataTypes[i].formatetc;
+ }
+ enumFORMATETC.setFormats(formats);
+
+ OS.MoveMemory(ppenumFormatetc, new long[] {enumFORMATETC.getAddress()}, C.PTR_SIZEOF);
+ return COM.S_OK;
+}
+/**
+ * Returns the Control which is registered for this DragSource. This is the control that the
+ * user clicks in to initiate dragging.
+ *
+ * @return the Control which is registered for this DragSource
+ */
+public Control getControl() {
+ return control;
+}
+
+/**
+ * Returns an array of listeners who will be notified when a drag and drop
+ * operation is in progress, by sending it one of the messages defined in
+ * the DragSourceListener
interface.
+ *
+ * @return the listeners who will be notified when a drag and drop
+ * operation is in progress
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DragSourceListener
+ * @see #addDragListener
+ * @see #removeDragListener
+ * @see DragSourceEvent
+ *
+ * @since 3.4
+ */
+public DragSourceListener[] getDragListeners() {
+ Listener[] listeners = getListeners(DND.DragStart);
+ int length = listeners.length;
+ DragSourceListener[] dragListeners = new DragSourceListener[length];
+ int count = 0;
+ for (int i = 0; i < length; i++) {
+ Listener listener = listeners[i];
+ if (listener instanceof DNDListener) {
+ dragListeners[count] = (DragSourceListener) ((DNDListener) listener).getEventListener();
+ count++;
+ }
+ }
+ if (count == length) return dragListeners;
+ DragSourceListener[] result = new DragSourceListener[count];
+ System.arraycopy(dragListeners, 0, result, 0, count);
+ return result;
+}
+
+/**
+ * Returns the drag effect that is registered for this DragSource. This drag
+ * effect will be used during a drag and drop operation.
+ *
+ * @return the drag effect that is registered for this DragSource
+ *
+ * @since 3.3
+ */
+public DragSourceEffect getDragSourceEffect() {
+ return dragEffect;
+}
+
+/**
+ * Returns the list of data types that can be transferred by this DragSource.
+ *
+ * @return the list of data types that can be transferred by this DragSource
+ */
+public Transfer[] getTransfer(){
+ return transferAgents;
+}
+
+private int GiveFeedback(int dwEffect) {
+ return COM.DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+private int QueryContinueDrag(int fEscapePressed, int grfKeyState) {
+ if (topControl != null && topControl.isDisposed()) return COM.DRAGDROP_S_CANCEL;
+ if (fEscapePressed != 0){
+ if (hwndDrag != 0) OS.ImageList_DragLeave(hwndDrag);
+ return COM.DRAGDROP_S_CANCEL;
+ }
+ /*
+ * Bug in Windows. On some machines that do not have XBUTTONs,
+ * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
+ * causing mouse capture to become stuck. The fix is to test
+ * for the extra buttons only when they exist.
+ */
+ int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
+// if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
+ if ((grfKeyState & mask) == 0) {
+ if (hwndDrag != 0) OS.ImageList_DragLeave(hwndDrag);
+ return COM.DRAGDROP_S_DROP;
+ }
+
+ if (hwndDrag != 0) {
+ POINT pt = new POINT ();
+ OS.GetCursorPos (pt);
+ RECT rect = new RECT ();
+ OS.GetWindowRect (hwndDrag, rect);
+ OS.ImageList_DragMove (pt.x - rect.left, pt.y - rect.top);
+ }
+ return COM.S_OK;
+}
+
+private void onDispose() {
+ if (control == null) return;
+ releaseCOMInterfaces();
+ if (controlListener != null){
+ control.removeListener(SWT.Dispose, controlListener);
+ control.removeListener(SWT.DragDetect, controlListener);
+ }
+ controlListener = null;
+ control.setData(DND.DRAG_SOURCE_KEY, null);
+ control = null;
+ transferAgents = null;
+}
+
+private int opToOs(int operation) {
+ int osOperation = 0;
+ if ((operation & DND.DROP_COPY) != 0){
+ osOperation |= COM.DROPEFFECT_COPY;
+ }
+ if ((operation & DND.DROP_LINK) != 0) {
+ osOperation |= COM.DROPEFFECT_LINK;
+ }
+ if ((operation & DND.DROP_MOVE) != 0) {
+ osOperation |= COM.DROPEFFECT_MOVE;
+ }
+ return osOperation;
+}
+
+private int osToOp(int osOperation){
+ int operation = 0;
+ if ((osOperation & COM.DROPEFFECT_COPY) != 0){
+ operation |= DND.DROP_COPY;
+ }
+ if ((osOperation & COM.DROPEFFECT_LINK) != 0) {
+ operation |= DND.DROP_LINK;
+ }
+ if ((osOperation & COM.DROPEFFECT_MOVE) != 0) {
+ operation |= DND.DROP_MOVE;
+ }
+ return operation;
+}
+
+private static int QueryGetData(Transfer[] transferAgents, long pFormatetc) {
+ if (transferAgents == null) return COM.E_FAIL;
+ TransferData transferData = new TransferData();
+ transferData.formatetc = new FORMATETC();
+ COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+ transferData.type = transferData.formatetc.cfFormat;
+
+ // is this type supported by the transfer agent?
+ for (Transfer transferAgent : transferAgents) {
+ if (transferAgent != null && transferAgent.isSupportedType(transferData))
+ return COM.S_OK;
+ }
+
+ return COM.DV_E_FORMATETC;
+}
+
+/* QueryInterface([in] riid, [out] ppvObject)
+ * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
+ * must be incremented before returning. Caller is responsible for releasing ppvObject.
+ */
+private static int QueryInterface(COMObject comObject, long riid, long ppvObject) {
+ if (riid == 0 || ppvObject == 0)
+ return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+
+ if (comObject != null && COM.IsEqualGUID(guid, COM.IIDIUnknown)
+ || (COM.IsEqualGUID(guid, COM.IIDIDropSource) && (comObject instanceof COMIDropSource))
+ || (COM.IsEqualGUID(guid, COM.IIDIDataObject) && (comObject instanceof COMIDataObject))) {
+ OS.MoveMemory(ppvObject, new long[] {comObject.getAddress()}, C.PTR_SIZEOF);
+ comObject.method1(null); // AddRef
+ return COM.S_OK;
+ }
+
+ OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a drag and drop operation is in progress.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DragSourceListener
+ * @see #addDragListener
+ * @see #getDragListeners
+ */
+public void removeDragListener(DragSourceListener listener) {
+ if (listener == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
+ removeListener(DND.DragStart, listener);
+ removeListener(DND.DragSetData, listener);
+ removeListener(DND.DragEnd, listener);
+}
+
+/**
+ * Specifies the drag effect for this DragSource. This drag effect will be
+ * used during a drag and drop operation.
+ *
+ * @param effect the drag effect that is registered for this DragSource
+ *
+ * @since 3.3
+ */
+public void setDragSourceEffect(DragSourceEffect effect) {
+ dragEffect = effect;
+}
+
+/**
+ * Specifies the list of data types that can be transferred by this DragSource.
+ * The application must be able to provide data to match each of these types when
+ * a successful drop has occurred.
+ *
+ * @param transferAgents a list of Transfer objects which define the types of data that can be
+ * dragged from this source
+ */
+public void setTransfer(Transfer... transferAgents){
+ this.transferAgents = transferAgents;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DragSourceAdapter.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DragSourceAdapter.java
new file mode 100644
index 000000000..c2680d19d
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DragSourceAdapter.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the DragSourceListener
interface.
+ *
+ * DragSourceEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.dragStart
permits the drag operation to start.
+ * For additional information see DragSourceListener.dragStart
.
+ *
+ * @param event the information associated with the drag start event
+ */
+@Override
+public void dragStart(DragSourceEvent event){}
+
+/**
+ * This implementation of dragFinished
does nothing.
+ * For additional information see DragSourceListener.dragFinished
.
+ *
+ * @param event the information associated with the drag finished event
+ */
+@Override
+public void dragFinished(DragSourceEvent event){}
+
+/**
+ * This implementation of dragSetData
does nothing.
+ * For additional information see DragSourceListener.dragSetData
.
+ *
+ * @param event the information associated with the drag set data event
+ */
+@Override
+public void dragSetData(DragSourceEvent event){}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DragSourceEffect.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DragSourceEffect.java
new file mode 100644
index 000000000..0f617eb01
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DragSourceEffect.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides default implementations to display a drag source
+ * effect during a drag and drop operation. The current implementation
+ * does not provide any visual feedback.
+ *
+ * DragSourceAdapter
so that it can provide custom visual
+ * feedback when a DragSourceEvent
occurs.
+ * DragSourceEffect
+ * class, override the DragSourceAdapter.dragStart
method and set
+ * the field DragSourceEvent.image
with their own image.
+ * The image should be disposed when DragSourceAdapter.dragFinished
is called.
+ * DragSourceEffect
to handle drag effect from the specified Control
.
+ *
+ * @param control the Control
that the user clicks on to initiate the drag
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+ public DragSourceEffect(Control control) {
+ if (control == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ this.control = control;
+ }
+
+ /**
+ * Returns the Control which is registered for this DragSourceEffect. This is the control that the
+ * user clicks in to initiate dragging.
+ *
+ * @return the Control which is registered for this DragSourceEffect
+ */
+ public Control getControl() {
+ return control;
+ }
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DragSourceEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DragSourceEvent.java
new file mode 100644
index 000000000..3b287c5b0
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DragSourceEvent.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * The DragSourceEvent contains the event information passed in the methods of the DragSourceListener.
+ *
+ * @see DragSourceListener
+ * @see Sample code and further information
+ */
+public class DragSourceEvent extends TypedEvent {
+ /**
+ * The operation that was performed.
+ * @see DND#DROP_NONE
+ * @see DND#DROP_MOVE
+ * @see DND#DROP_COPY
+ * @see DND#DROP_LINK
+ * @see DND#DROP_TARGET_MOVE
+ */
+ public int detail;
+
+ /**
+ * In dragStart, the doit field determines if the drag and drop operation
+ * should proceed; in dragFinished, the doit field indicates whether
+ * the operation was performed successfully.
+ * DragSourceListener
class provides event notification to the application for DragSource events.
+ *
+ * DropTarget
, the application which defines the DragSource
+ * must provide the dropped data by implementing dragSetData
. In the dragSetData, the application
+ * must support all the data types that were specified in the DragSource#setTransfer method.DragSource
is required to take the appropriate cleanup action. In the case of a successful
+ * move operation, the application must remove the data that was transferred.
+ *
+ *
+ * @param event the information associated with the drag start event
+ *
+ * @see DragSourceEvent
+ */
+public void dragStart(DragSourceEvent event);
+
+/**
+ * The data is required from the drag source.
+ *
+ *
+ *
+ *
+ * @param event the information associated with the drag set data event
+ *
+ * @see DragSourceEvent
+ */
+public void dragSetData(DragSourceEvent event);
+
+/**
+ * The drop has successfully completed(mouse up over a valid target) or has been terminated (such as hitting
+ * the ESC key). Perform cleanup such as removing data from the source side on a successful move operation.
+ *
+ *
+ *
+ *
+ * @param event the information associated with the drag finished event
+ *
+ * @see DragSourceEvent
+ */
+public void dragFinished(DragSourceEvent event);
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DropTarget.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DropTarget.java
new file mode 100644
index 000000000..844cc8443
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DropTarget.java
@@ -0,0 +1,807 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ *
+ * Class DropTarget
defines the target object for a drag and drop transfer.
+ *
+ * Control
over which the user must position the cursor
+ * in order to drop the data being transferred. It also specifies what data types can be dropped on
+ * this control and what operations can be performed. You may have several DropTragets in an
+ * application but there can only be a one to one mapping between a Control
and a DropTarget
.
+ * The DropTarget can receive data from within the same application or from other applications
+ * (such as text dragged from a text editor like Word).
+ *
+ *
+ * int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
+ * Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
+ * DropTarget target = new DropTarget(label, operations);
+ * target.setTransfer(types);
+ *
DropTargetListener
which uses the class
+ * DropTargetEvent
. The application can modify the type of drag being performed
+ * on this Control at any stage of the drag by modifying the event.detail
field or the
+ * event.currentDataType
field. When the data is dropped, it is the responsibility of
+ * the application to copy this data for its own purposes.
+ *
+ *
+ *
+ *
+ * target.addDropListener (new DropTargetListener() {
+ * public void dragEnter(DropTargetEvent event) {};
+ * public void dragOver(DropTargetEvent event) {};
+ * public void dragLeave(DropTargetEvent event) {};
+ * public void dragOperationChanged(DropTargetEvent event) {};
+ * public void dropAccept(DropTargetEvent event) {}
+ * public void drop(DropTargetEvent event) {
+ * // A drop has occurred, copy over the data
+ * if (event.data == null) { // no data to copy, indicate failure in event.detail
+ * event.detail = DND.DROP_NONE;
+ * return;
+ * }
+ * label.setText ((String) event.data); // data copied to label text
+ * }
+ * });
+ *
+ *
+ *
+ * @see Drag and Drop snippets
+ * @see SWT Example: DNDExample
+ * @see Sample code and further information
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class DropTarget extends Widget {
+
+ Control control;
+ Listener controlListener;
+ Transfer[] transferAgents = new Transfer[0];
+ DropTargetEffect dropEffect;
+
+ // Track application selections
+ TransferData selectedDataType;
+ int selectedOperation;
+
+ // workaround - There is no event for "operation changed" so track operation based on key state
+ int keyOperation = -1;
+
+ // workaround - The dataobject address is only passed as an argument in drag enter and drop.
+ // To allow applications to query the data values during the drag over operations,
+ // maintain a reference to it.
+ IDataObject iDataObject;
+
+ // interfaces
+ COMObject iDropTarget;
+ int refCount;
+
+ static final String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$
+
+/**
+ * Creates a new DropTarget
to allow data to be dropped on the specified
+ * Control
.
+ * Creating an instance of a DropTarget may cause system resources to be allocated
+ * depending on the platform. It is therefore mandatory that the DropTarget instance
+ * be disposed when no longer required.
+ *
+ * @param control the Control
over which the user positions the cursor to drop the data
+ * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
+ * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
+ *
+ * @exception SWTException
+ *
+ * @exception SWTError
+ *
+ *
+ * DropTargetListener
+ * interface.
+ *
+ *
+ *
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException dragEnter
is called when the cursor has entered the drop target boundaries
+ * dragLeave
is called when the cursor has left the drop target boundaries and just before
+ * the drop occurs or is cancelled.
+ * dragOperationChanged
is called when the operation being performed has changed
+ * (usually due to the user changing the selected modifier key(s) while dragging)
+ * dragOver
is called when the cursor is moving over the drop target
+ * dropAccept
is called just before the drop is performed. The drop target is given
+ * the chance to change the nature of the drop or veto the drop by setting the event.detail
field
+ * drop
is called when the data is being dropped
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DropTargetListener
+ * @see #getDropListeners
+ * @see #removeDropListener
+ * @see DropTargetEvent
+ */
+public void addDropListener(DropTargetListener listener) {
+ if (listener == null) DND.error (SWT.ERROR_NULL_ARGUMENT);
+ DNDListener typedListener = new DNDListener (listener);
+ typedListener.dndWidget = this;
+ addListener (DND.DragEnter, typedListener);
+ addListener (DND.DragLeave, typedListener);
+ addListener (DND.DragOver, typedListener);
+ addListener (DND.DragOperationChanged, typedListener);
+ addListener (DND.Drop, typedListener);
+ addListener (DND.DropAccept, typedListener);
+}
+
+int AddRef() {
+ refCount++;
+ return refCount;
+}
+
+@Override
+protected void checkSubclass () {
+ String name = getClass().getName ();
+ String validName = DropTarget.class.getName();
+ if (!validName.equals(name)) {
+ DND.error (SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+
+void createCOMInterfaces() {
+ // register each of the interfaces that this object implements
+ boolean is32 = C.PTR_SIZEOF == 4;
+ iDropTarget = new COMObject(new int[]{2, 0, 0, is32 ? 5 : 4, is32 ? 4 : 3, 0, is32 ? 5 : 4}){
+ @Override
+ public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ @Override
+ public long method3(long[] args) {
+ if (args.length == 5) {
+ return DragEnter(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
+ } else {
+ return DragEnter_64(args[0], (int)args[1], args[2], args[3]);
+ }
+ }
+ @Override
+ public long method4(long[] args) {
+ if (args.length == 4) {
+ return DragOver((int)args[0], (int)args[1], (int)args[2], args[3]);
+ } else {
+ return DragOver_64((int)args[0], args[1], args[2]);
+ }
+ }
+ @Override
+ public long method5(long[] args) {return DragLeave();}
+ @Override
+ public long method6(long[] args) {
+ if (args.length == 5) {
+ return Drop(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
+ } else {
+ return Drop_64(args[0], (int)args[1], args[2], args[3]);
+ }
+ }
+ };
+}
+
+void disposeCOMInterfaces() {
+ if (iDropTarget != null)
+ iDropTarget.dispose();
+ iDropTarget = null;
+}
+
+int DragEnter_64(long pDataObject, int grfKeyState, long pt, long pdwEffect) {
+ POINT point = new POINT();
+ OS.MoveMemory(point, new long[]{pt}, 8);
+ return DragEnter(pDataObject, grfKeyState, point.x, point.y, pdwEffect);
+}
+
+int DragEnter(long pDataObject, int grfKeyState, int pt_x, int pt_y, long pdwEffect) {
+ pt_x = DPIUtil.autoScaleDown(pt_x);// To Points
+ pt_y = DPIUtil.autoScaleDown(pt_y);// To Points
+ selectedDataType = null;
+ selectedOperation = DND.DROP_NONE;
+ if (iDataObject != null) iDataObject.Release();
+ iDataObject = null;
+
+ DNDEvent event = new DNDEvent();
+ if (!setEventData(event, pDataObject, grfKeyState, pt_x, pt_y, pdwEffect)) {
+ OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+ return COM.S_FALSE;
+ }
+
+ // Remember the iDataObject because it is not passed into the DragOver callback
+ iDataObject = new IDataObject(pDataObject);
+ iDataObject.AddRef();
+
+ int allowedOperations = event.operations;
+ TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+ System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+ notifyListeners(DND.DragEnter, event);
+ refresh();
+ if (event.detail == DND.DROP_DEFAULT) {
+ event.detail = (allowedOperations & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+ }
+
+ selectedDataType = null;
+ for (int i = 0; i < allowedDataTypes.length; i++) {
+ if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
+ selectedDataType = allowedDataTypes[i];
+ break;
+ }
+ }
+
+ selectedOperation = DND.DROP_NONE;
+ if (selectedDataType != null && ((allowedOperations & event.detail) != 0)) {
+ selectedOperation = event.detail;
+ }
+
+ OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
+ return COM.S_OK;
+}
+
+int DragLeave() {
+ keyOperation = -1;
+
+ if (iDataObject == null) return COM.S_FALSE;
+
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.time = OS.GetMessageTime();
+ event.detail = DND.DROP_NONE;
+ notifyListeners(DND.DragLeave, event);
+ refresh();
+
+ iDataObject.Release();
+ iDataObject = null;
+ return COM.S_OK;
+}
+
+int DragOver_64(int grfKeyState, long pt, long pdwEffect) {
+ POINT point = new POINT();
+ OS.MoveMemory(point, new long[]{pt}, 8);
+ return DragOver(grfKeyState, point.x, point.y, pdwEffect);
+}
+
+int DragOver(int grfKeyState, int pt_x, int pt_y, long pdwEffect) {
+ pt_x = DPIUtil.autoScaleDown(pt_x);// To Points
+ pt_y = DPIUtil.autoScaleDown(pt_y);// To Points
+ if (iDataObject == null) return COM.S_FALSE;
+ int oldKeyOperation = keyOperation;
+
+ DNDEvent event = new DNDEvent();
+ if (!setEventData(event, iDataObject.getAddress(), grfKeyState, pt_x, pt_y, pdwEffect)) {
+ keyOperation = -1;
+ OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+ return COM.S_FALSE;
+ }
+
+ int allowedOperations = event.operations;
+ TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+ System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+
+ if (keyOperation == oldKeyOperation) {
+ event.type = DND.DragOver;
+ event.dataType = selectedDataType;
+ event.detail = selectedOperation;
+ } else {
+ event.type = DND.DragOperationChanged;
+ event.dataType = selectedDataType;
+ }
+ notifyListeners(event.type, event);
+ refresh();
+ if (event.detail == DND.DROP_DEFAULT) {
+ event.detail = (allowedOperations & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+ }
+
+ selectedDataType = null;
+ for (int i = 0; i < allowedDataTypes.length; i++) {
+ if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
+ selectedDataType = allowedDataTypes[i];
+ break;
+ }
+ }
+
+ selectedOperation = DND.DROP_NONE;
+ if (selectedDataType != null && ((allowedOperations & event.detail) == event.detail)) {
+ selectedOperation = event.detail;
+ }
+
+ OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
+ return COM.S_OK;
+}
+
+int Drop_64(long pDataObject, int grfKeyState, long pt, long pdwEffect) {
+ POINT point = new POINT();
+ OS.MoveMemory(point, new long[]{pt}, 8);
+ return Drop(pDataObject, grfKeyState, point.x, point.y, pdwEffect);
+}
+
+int Drop(long pDataObject, int grfKeyState, int pt_x, int pt_y, long pdwEffect) {
+ try {
+ pt_x = DPIUtil.autoScaleDown(pt_x);// To Points
+ pt_y = DPIUtil.autoScaleDown(pt_y);// To Points
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.time = OS.GetMessageTime();
+ if (dropEffect != null) {
+ event.item = dropEffect.getItem(pt_x, pt_y);
+ }
+ event.detail = DND.DROP_NONE;
+ notifyListeners(DND.DragLeave, event);
+ refresh();
+
+ event = new DNDEvent();
+ if (!setEventData(event, pDataObject, grfKeyState, pt_x, pt_y, pdwEffect)) {
+ keyOperation = -1;
+ OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+ return COM.S_FALSE;
+ }
+ keyOperation = -1;
+ int allowedOperations = event.operations;
+ TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+ System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+ event.dataType = selectedDataType;
+ event.detail = selectedOperation;
+ notifyListeners(DND.DropAccept,event);
+ refresh();
+
+ selectedDataType = null;
+ for (int i = 0; i < allowedDataTypes.length; i++) {
+ if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
+ selectedDataType = allowedDataTypes[i];
+ break;
+ }
+ }
+ selectedOperation = DND.DROP_NONE;
+ if (selectedDataType != null && (allowedOperations & event.detail) == event.detail) {
+ selectedOperation = event.detail;
+ }
+
+ if (selectedOperation == DND.DROP_NONE){
+ OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+ return COM.S_OK;
+ }
+
+ // Get Data in a Java format
+ Object object = null;
+ for (int i = 0; i < transferAgents.length; i++){
+ Transfer transfer = transferAgents[i];
+ if (transfer != null && transfer.isSupportedType(selectedDataType)){
+ object = transfer.nativeToJava(selectedDataType);
+ break;
+ }
+ }
+ if (object == null){
+ selectedOperation = DND.DROP_NONE;
+ }
+
+ event.detail = selectedOperation;
+ event.dataType = selectedDataType;
+ event.data = object;
+ OS.ImageList_DragShowNolock(false);
+ try {
+ notifyListeners(DND.Drop,event);
+ } finally {
+ OS.ImageList_DragShowNolock(true);
+ }
+ refresh();
+ selectedOperation = DND.DROP_NONE;
+ if ((allowedOperations & event.detail) == event.detail) {
+ selectedOperation = event.detail;
+ }
+ //notify source of action taken
+ OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
+ return COM.S_OK;
+ } finally {
+ if (iDataObject != null) {
+ iDataObject.Release();
+ iDataObject = null;
+ }
+ }
+}
+
+/**
+ * Returns the Control which is registered for this DropTarget. This is the control over which the
+ * user positions the cursor to drop the data.
+ *
+ * @return the Control which is registered for this DropTarget
+ */
+public Control getControl () {
+ return control;
+}
+
+/**
+ * Returns an array of listeners who will be notified when a drag and drop
+ * operation is in progress, by sending it one of the messages defined in
+ * the DropTargetListener
interface.
+ *
+ * @return the listeners who will be notified when a drag and drop
+ * operation is in progress
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DropTargetListener
+ * @see #addDropListener
+ * @see #removeDropListener
+ * @see DropTargetEvent
+ *
+ * @since 3.4
+ */
+public DropTargetListener[] getDropListeners() {
+ Listener[] listeners = getListeners(DND.DragEnter);
+ int length = listeners.length;
+ DropTargetListener[] dropListeners = new DropTargetListener[length];
+ int count = 0;
+ for (int i = 0; i < length; i++) {
+ Listener listener = listeners[i];
+ if (listener instanceof DNDListener) {
+ dropListeners[count] = (DropTargetListener) ((DNDListener) listener).getEventListener();
+ count++;
+ }
+ }
+ if (count == length) return dropListeners;
+ DropTargetListener[] result = new DropTargetListener[count];
+ System.arraycopy(dropListeners, 0, result, 0, count);
+ return result;
+}
+
+/**
+ * Returns the drop effect for this DropTarget. This drop effect will be
+ * used during a drag and drop to display the drag under effect on the
+ * target widget.
+ *
+ * @return the drop effect that is registered for this DropTarget
+ *
+ * @since 3.3
+ */
+public DropTargetEffect getDropTargetEffect() {
+ return dropEffect;
+}
+
+int getOperationFromKeyState(int grfKeyState) {
+ boolean ctrl = (grfKeyState & OS.MK_CONTROL) != 0;
+ boolean shift = (grfKeyState & OS.MK_SHIFT) != 0;
+ boolean alt = (grfKeyState & OS.MK_ALT) != 0;
+ if (alt) {
+ if (ctrl || shift) return DND.DROP_DEFAULT;
+ return DND.DROP_LINK;
+ }
+ if (ctrl && shift) return DND.DROP_LINK;
+ if (ctrl)return DND.DROP_COPY;
+ if (shift)return DND.DROP_MOVE;
+ return DND.DROP_DEFAULT;
+}
+
+/**
+ * Returns a list of the data types that can be transferred to this DropTarget.
+ *
+ * @return a list of the data types that can be transferred to this DropTarget
+ */
+public Transfer[] getTransfer() {
+ return transferAgents;
+}
+
+void onDispose () {
+ if (control == null) return;
+
+ COM.RevokeDragDrop(control.handle);
+
+ if (controlListener != null)
+ control.removeListener(SWT.Dispose, controlListener);
+ controlListener = null;
+ control.setData(DND.DROP_TARGET_KEY, null);
+ transferAgents = null;
+ control = null;
+
+ COM.CoLockObjectExternal(iDropTarget.getAddress(), false, true);
+
+ this.Release();
+ if (iDataObject != null) {
+ iDataObject.Release();
+ }
+ iDataObject = null;
+
+ if (COM.FreeUnusedLibraries) {
+ COM.CoFreeUnusedLibraries();
+ }
+}
+
+int opToOs(int operation) {
+ int osOperation = 0;
+ if ((operation & DND.DROP_COPY) != 0){
+ osOperation |= COM.DROPEFFECT_COPY;
+ }
+ if ((operation & DND.DROP_LINK) != 0) {
+ osOperation |= COM.DROPEFFECT_LINK;
+ }
+ if ((operation & DND.DROP_MOVE) != 0) {
+ osOperation |= COM.DROPEFFECT_MOVE;
+ }
+ return osOperation;
+}
+
+int osToOp(int osOperation){
+ int operation = 0;
+ if ((osOperation & COM.DROPEFFECT_COPY) != 0){
+ operation |= DND.DROP_COPY;
+ }
+ if ((osOperation & COM.DROPEFFECT_LINK) != 0) {
+ operation |= DND.DROP_LINK;
+ }
+ if ((osOperation & COM.DROPEFFECT_MOVE) != 0) {
+ operation |= DND.DROP_MOVE;
+ }
+ return operation;
+}
+
+/* QueryInterface([in] iid, [out] ppvObject)
+ * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
+ * must be incremented before returning. Caller is responsible for releasing ppvObject.
+ */
+int QueryInterface(long riid, long ppvObject) {
+
+ if (riid == 0 || ppvObject == 0)
+ return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+ if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDropTarget)) {
+ OS.MoveMemory(ppvObject, new long[] {iDropTarget.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+
+ OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+
+int Release() {
+ refCount--;
+
+ if (refCount == 0) {
+ disposeCOMInterfaces();
+ if (COM.FreeUnusedLibraries) {
+ COM.CoFreeUnusedLibraries();
+ }
+ }
+
+ return refCount;
+}
+
+void refresh() {
+ if (control == null || control.isDisposed()) return;
+ long handle = control.handle;
+ RECT lpRect = new RECT();
+ if (OS.GetUpdateRect(handle, lpRect, false)) {
+ OS.ImageList_DragShowNolock(false);
+ OS.RedrawWindow(handle, lpRect, 0, OS.RDW_UPDATENOW | OS.RDW_INVALIDATE);
+ OS.ImageList_DragShowNolock(true);
+ }
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a drag and drop operation is in progress.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DropTargetListener
+ * @see #addDropListener
+ * @see #getDropListeners
+ */
+public void removeDropListener(DropTargetListener listener) {
+ if (listener == null) DND.error (SWT.ERROR_NULL_ARGUMENT);
+ removeListener (DND.DragEnter, listener);
+ removeListener (DND.DragLeave, listener);
+ removeListener (DND.DragOver, listener);
+ removeListener (DND.DragOperationChanged, listener);
+ removeListener (DND.Drop, listener);
+ removeListener (DND.DropAccept, listener);
+}
+
+/**
+ * Specifies the drop effect for this DropTarget. This drop effect will be
+ * used during a drag and drop to display the drag under effect on the
+ * target widget.
+ *
+ * @param effect the drop effect that is registered for this DropTarget
+ *
+ * @since 3.3
+ */
+public void setDropTargetEffect(DropTargetEffect effect) {
+ dropEffect = effect;
+}
+
+boolean setEventData(DNDEvent event, long pDataObject, int grfKeyState, int pt_x, int pt_y, long pdwEffect) {
+ if (pDataObject == 0 || pdwEffect == 0) return false;
+
+ // get allowed operations
+ int style = getStyle();
+ int[] operations = new int[1];
+ OS.MoveMemory(operations, pdwEffect, 4);
+ operations[0] = osToOp(operations[0]) & style;
+ if (operations[0] == DND.DROP_NONE) return false;
+
+ // get current operation
+ int operation = getOperationFromKeyState(grfKeyState);
+ keyOperation = operation;
+ if (operation == DND.DROP_DEFAULT) {
+ if ((style & DND.DROP_DEFAULT) == 0) {
+ operation = (operations[0] & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+ }
+ } else {
+ if ((operation & operations[0]) == 0) operation = DND.DROP_NONE;
+ }
+
+ // Get allowed transfer types
+ TransferData[] dataTypes = new TransferData[0];
+ IDataObject dataObject = new IDataObject(pDataObject);
+ dataObject.AddRef();
+ try {
+ long[] address = new long[1];
+ if (dataObject.EnumFormatEtc(COM.DATADIR_GET, address) != COM.S_OK) {
+ return false;
+ }
+ IEnumFORMATETC enumFormatetc = new IEnumFORMATETC(address[0]);
+ try {
+ // Loop over enumerator and save any types that match what we are looking for
+ long rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof);
+ try {
+ int[] pceltFetched = new int[1];
+ enumFormatetc.Reset();
+ while (enumFormatetc.Next(1, rgelt, pceltFetched) == COM.S_OK && pceltFetched[0] == 1) {
+ TransferData transferData = new TransferData();
+ transferData.formatetc = new FORMATETC();
+ COM.MoveMemory(transferData.formatetc, rgelt, FORMATETC.sizeof);
+ transferData.type = transferData.formatetc.cfFormat;
+ transferData.pIDataObject = pDataObject;
+ for (int i = 0; i < transferAgents.length; i++){
+ Transfer transfer = transferAgents[i];
+ if (transfer != null && transfer.isSupportedType(transferData)){
+ TransferData[] newDataTypes = new TransferData[dataTypes.length + 1];
+ System.arraycopy(dataTypes, 0, newDataTypes, 0, dataTypes.length);
+ newDataTypes[dataTypes.length] = transferData;
+ dataTypes = newDataTypes;
+ break;
+ }
+ }
+ }
+ } finally {
+ OS.GlobalFree(rgelt);
+ }
+ } finally {
+ enumFormatetc.Release();
+ }
+ } finally {
+ dataObject.Release();
+ }
+ if (dataTypes.length == 0) return false;
+
+ event.widget = this;
+ event.x = pt_x;
+ event.y = pt_y;
+ event.time = OS.GetMessageTime();
+ event.feedback = DND.FEEDBACK_SELECT;
+ event.dataTypes = dataTypes;
+ event.dataType = dataTypes[0];
+ if (dropEffect != null) {
+ event.item = dropEffect.getItem(pt_x, pt_y);
+ }
+ event.operations = operations[0];
+ event.detail = operation;
+ return true;
+}
+
+/**
+ * Specifies the data types that can be transferred to this DropTarget. If data is
+ * being dragged that does not match one of these types, the drop target will be notified of
+ * the drag and drop operation but the currentDataType will be null and the operation
+ * will be DND.NONE.
+ *
+ * @param transferAgents a list of Transfer objects which define the types of data that can be
+ * dropped on this target
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public void setTransfer(Transfer... transferAgents){
+ if (transferAgents == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
+ this.transferAgents = transferAgents;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DropTargetAdapter.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DropTargetAdapter.java
new file mode 100644
index 000000000..c3e958587
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DropTargetAdapter.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the DropTargetListener
interface.
+ * DropTargetEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * dragEnter
permits the default
+ * operation defined in event.detail
to be performed on the current data type
+ * defined in event.currentDataType
.
+ * For additional information see DropTargetListener.dragEnter
.
+ *
+ * @param event the information associated with the drag enter event
+ */
+@Override
+public void dragEnter(DropTargetEvent event){}
+
+/**
+ * This implementation of dragLeave
does nothing.
+ * For additional information see DropTargetListener.dragOperationChanged
.
+ *
+ * @param event the information associated with the drag leave event
+ */
+@Override
+public void dragLeave(DropTargetEvent event){}
+
+/**
+ * This implementation of dragOperationChanged
permits the default
+ * operation defined in event.detail
to be performed on the current data type
+ * defined in event.currentDataType
.
+ * For additional information see DropTargetListener.dragOperationChanged
.
+ *
+ * @param event the information associated with the drag operation changed event
+ */
+@Override
+public void dragOperationChanged(DropTargetEvent event){}
+
+/**
+ * This implementation of dragOver
permits the default
+ * operation defined in event.detail
to be performed on the current data type
+ * defined in event.currentDataType
.
+ * For additional information see DropTargetListener.dragOver
.
+ *
+ * @param event the information associated with the drag over event
+ */
+@Override
+public void dragOver(DropTargetEvent event){}
+
+/**
+ * This implementation of drop
does nothing.
+ * For additional information see DropTargetListener.drop
.
+ *
+ * @param event the information associated with the drop event
+ */
+@Override
+public void drop(DropTargetEvent event){}
+
+/**
+ * This implementation of dropAccept
permits the default
+ * operation defined in event.detail
to be performed on the current data type
+ * defined in event.currentDataType
.
+ * For additional information see DropTargetListener.dropAccept
.
+ *
+ * @param event the information associated with the drop accept event
+ */
+@Override
+public void dropAccept(DropTargetEvent event){}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DropTargetEffect.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DropTargetEffect.java
new file mode 100644
index 000000000..ab9f3b3ff
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/DropTargetEffect.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+
+/**
+ * This class provides a default drag under effect during a drag and drop.
+ * The current implementation does not provide any visual feedback.
+ *
+ * DropTargetAdapter
so that it can provide custom visual
+ * feedback when a DropTargetEvent
occurs.
+ * DropTargetEffect
and override any applicable methods
+ * in DropTargetAdapter
to display their own drag under effect.DND
which is applicable to instances of this class,
+ * or it must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those DND
effect constants.
+ *
+ *
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ * @see Sample code and further information
+ *
+ * @since 3.3
+ */
+public class DropTargetEffect extends DropTargetAdapter {
+ Control control;
+
+ /**
+ * Creates a new DropTargetEffect
to handle the drag under effect on the specified
+ * Control
.
+ *
+ * @param control the Control
over which the user positions the cursor to drop the data
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+ public DropTargetEffect(Control control) {
+ if (control == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ this.control = control;
+ }
+
+ /**
+ * Returns the Control which is registered for this DropTargetEffect. This is the control over which the
+ * user positions the cursor to drop the data.
+ *
+ * @return the Control which is registered for this DropTargetEffect
+ */
+ public Control getControl() {
+ return control;
+ }
+
+ /**
+ * Returns the item at the given x-y coordinate in the receiver
+ * or null if no such item exists. The x-y coordinate is in the
+ * display relative coordinates.
+ *
+ * @param x the x coordinate used to locate the item
+ * @param y the y coordinate used to locate the item
+ * @return the item at the given x-y coordinate, or null if the coordinate is not in a selectable item
+ */
+ public Widget getItem(int x, int y) {
+ if (control instanceof Table) {
+ return getItem((Table) control, x, y);
+ }
+ if (control instanceof Tree) {
+ return getItem((Tree) control, x, y);
+ }
+ return null;
+ }
+
+ Widget getItem(Table table, int x, int y) {
+ Point coordinates = new Point(x, y);
+ coordinates = table.toControl(coordinates);
+ TableItem item = table.getItem(coordinates);
+ if (item != null) return item;
+ Rectangle area = table.getClientArea();
+ int tableBottom = area.y + area.height;
+ int itemCount = table.getItemCount();
+ for (int i=table.getTopIndex(); iDisplay
+ */
+ public int x;
+
+ /**
+ * The y-cordinate of the cursor relative to the Display
+ */
+ public int y;
+
+ /**
+ * The operation being performed.
+ * @see DND#DROP_NONE
+ * @see DND#DROP_MOVE
+ * @see DND#DROP_COPY
+ * @see DND#DROP_LINK
+ * @see DND#DROP_DEFAULT
+ */
+ public int detail;
+
+ /**
+ * A bitwise OR'ing of the operations that the DragSource can support
+ * (e.g. DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK).
+ * The detail value must be a member of this list or DND.DROP_NONE.
+ * @see DND#DROP_NONE
+ * @see DND#DROP_MOVE
+ * @see DND#DROP_COPY
+ * @see DND#DROP_LINK
+ * @see DND#DROP_DEFAULT
+ */
+ public int operations;
+
+ /**
+ * A bitwise OR'ing of the drag under effect feedback to be displayed to the user
+ * (e.g. DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL | DND.FEEDBACK_EXPAND).
+ * DropTargetListener
class provides event notification to the application
+ * for DropTarget events.
+ *
+ *
+ *
+ *
+ * operations
value is determined by the modifier keys pressed by the user.
+ * If no keys are pressed the event.detail
field is set to DND.DROP_DEFAULT.
+ * If the application does not set the event.detail
to something other
+ * than DND.DROP_DEFAULT
the operation will be set to the platform defined standard
+ * default.currentDataType
is determined by the first transfer agent specified in
+ * setTransfer() that matches a data type provided by the drag source.detail
field but the choice must be one of the values in the operations
+ * field or DND.DROP_NONE.currentDataTypes
field but the value must be one of the values
+ * in the dataTypes
list.
+ *
+ *
+ * @param event the information associated with the drag leave event
+ *
+ * @see DropTargetEvent
+ */
+public void dragLeave(DropTargetEvent event);
+
+/**
+ * The operation being performed has changed (usually due to the user changing the selected modifier key(s)
+ * while dragging).
+ *
+ *
+ *
+ *
+ * operations
value is determined by the modifier keys pressed by the user.
+ * If no keys are pressed the event.detail
field is set to DND.DROP_DEFAULT.
+ * If the application does not set the event.detail
to something other than
+ * DND.DROP_DEFAULT
the operation will be set to the platform defined standard default.currentDataType
value is determined by the value assigned to
+ * currentDataType
in previous dragEnter and dragOver calls.detail
field but the choice must be one of the values in the operations
+ * field.currentDataTypes
field but the value must be one of the values in the
+ * dataTypes
list.
+ *
+ *
+ * operations
value is determined by the value assigned to
+ * currentDataType
in previous dragEnter and dragOver calls.currentDataType
value is determined by the value assigned to
+ * currentDataType
in previous dragEnter and dragOver calls.detail
field but the choice must be one of the values in the operations
+ * field.currentDataTypes
field but the value must be one of the values in the
+ * dataTypes
list.data
field is null. On some platforms, it is possible
+ * to obtain the data being transferred before the transfer occurs but in most platforms this is
+ * not possible. On those platforms where the data is available, the application can access the
+ * data as follows:
+ *
+ * @param event the information associated with the drag over event
+ *
+ * @see DropTargetEvent
+ */
+public void dragOver(DropTargetEvent event);
+
+/**
+ * The data is being dropped. The data field contains java format of the data being dropped.
+ * To determine the type of the data object, refer to the documentation for the Transfer subclass
+ * specified in event.currentDataType.
+ *
+ *
+ * public void dragOver(DropTargetEvent event) {
+ * TextTransfer textTransfer = TextTransfer.getInstance();
+ * String data = (String)textTransfer.nativeToJava(event.currentDataType);
+ * if (data != null) {
+ * System.out.println("Data to be dropped is (Text)"+data);
+ * }
+ * };
+ *
+ *
+ *
+ *
+ *
+ *
+ * event.detail
field to
+ * DND.DROP_NONE
.detail
field but the choice must be one of the values in the
+ * operations
field.currentDataTypes
field but the value must be one of the values in the
+ * dataTypes
list.FileTransfer
provides a platform specific mechanism
+ * for converting a list of files represented as a java String[]
to a
+ * platform specific representation of the data and vice versa.
+ * Each String
in the array contains the absolute path for a single
+ * file or directory.
+ *
+ * String[]
containing a list of files is shown
+ * below:
+ *
+ * @see Transfer
+ */
+public class FileTransfer extends ByteArrayTransfer {
+
+ private static FileTransfer _instance = new FileTransfer();
+ private static final String CF_HDROP = "CF_HDROP"; //$NON-NLS-1$
+ private static final int CF_HDROPID = COM.CF_HDROP;
+ private static final String CFSTR_SHELLIDLIST = "Shell IDList Array"; //$NON-NLS-1$
+ private static final int CFSTR_SHELLIDLISTID = registerType(CFSTR_SHELLIDLIST);
+
+private FileTransfer() {}
+
+/**
+ * Returns the singleton instance of the FileTransfer class.
+ *
+ * @return the singleton instance of the FileTransfer class
+ */
+public static FileTransfer getInstance () {
+ return _instance;
+}
+
+/**
+ * This implementation of
+ * File file1 = new File("C:\\temp\\file1");
+ * File file2 = new File("C:\\temp\\file2");
+ * String[] fileData = new String[2];
+ * fileData[0] = file1.getAbsolutePath();
+ * fileData[1] = file2.getAbsolutePath();
+ *
javaToNative
converts a list of file names
+ * represented by a java String[]
to a platform specific representation.
+ * Each String
in the array contains the absolute path for a single
+ * file or directory.
+ *
+ * @param object a java String[]
containing the file names to be converted
+ * @param transferData an empty TransferData
object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+@Override
+public void javaToNative(Object object, TransferData transferData) {
+ if (!checkFile(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ String[] fileNames = (String[]) object;
+ long newPtr = 0;
+ if (transferData.type == CF_HDROPID) {
+ StringBuilder allFiles = new StringBuilder();
+ for (int i = 0; i < fileNames.length; i++) {
+ allFiles.append(fileNames[i]);
+ allFiles.append('\0'); // each name is null terminated
+ }
+ allFiles.append('\0'); // there is an extra null terminator at the very end
+ char [] buffer = new char [allFiles.length()];
+ allFiles.getChars(0, allFiles.length(), buffer, 0);
+ DROPFILES dropfiles = new DROPFILES();
+ dropfiles.pFiles = DROPFILES.sizeof;
+ dropfiles.pt_x = dropfiles.pt_y = 0;
+ dropfiles.fNC = 0;
+ dropfiles.fWide = 1;
+ // Allocate the memory because the caller (DropTarget) has not handed it in
+ // The caller of this method must release the data when it is done with it.
+ int byteCount = buffer.length * TCHAR.sizeof;
+ newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, DROPFILES.sizeof + byteCount);
+ if (newPtr != 0) {
+ OS.MoveMemory(newPtr, dropfiles, DROPFILES.sizeof);
+ OS.MoveMemory(newPtr + DROPFILES.sizeof, buffer, byteCount);
+ }
+ } else if (transferData.type == CFSTR_SHELLIDLISTID) {
+ newPtr = generateCidaFromFilepaths(fileNames);
+ }
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = newPtr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = newPtr != 0 ? COM.S_OK : COM.E_FAIL;
+}
+
+/**
+ * This implementation of nativeToJava
converts a platform specific
+ * representation of a list of file names to a java String[]
.
+ * Each String in the array contains the absolute path for a single file or directory.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java String[]
containing a list of file names if the conversion
+ * was successful; otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+@Override
+public Object nativeToJava(TransferData transferData) {
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+
+ // get file names from IDataObject
+ IDataObject dataObject = new IDataObject(transferData.pIDataObject);
+ dataObject.AddRef();
+ FORMATETC formatetc = new FORMATETC();
+ formatetc.cfFormat = COM.CF_HDROP;
+ formatetc.ptd = 0;
+ formatetc.dwAspect = COM.DVASPECT_CONTENT;
+ formatetc.lindex = -1;
+ formatetc.tymed = COM.TYMED_HGLOBAL;
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(dataObject, formatetc, stgmedium);
+ dataObject.Release();
+ if (transferData.result != COM.S_OK) return null;
+ // How many files are there?
+ int count = OS.DragQueryFile(stgmedium.unionField, 0xFFFFFFFF, null, 0);
+ String[] fileNames = new String[count];
+ for (int i = 0; i < count; i++) {
+ // How long is the name ?
+ int size = OS.DragQueryFile(stgmedium.unionField, i, null, 0);
+ char [] lpszFile = new char [size + 1];
+ // Get file name and append it to string
+ OS.DragQueryFile(stgmedium.unionField, i, lpszFile, size + 1);
+ fileNames[i] = new String(lpszFile, 0, size);
+ }
+ OS.DragFinish(stgmedium.unionField); // frees data associated with HDROP data
+ return fileNames;
+}
+
+/**
+ * Generate {@link CIDA} structure and trailing data to transfer filenames
+ * as {@link #CFSTR_SHELLIDLIST}.
+ * 0
on failure
+ */
+private long generateCidaFromFilepaths(String[] fileNames) {
+ final int n = fileNames.length;
+ long [] pidls = new long [n];
+ try {
+ CIDA cida = new CIDA();
+ cida.cidl = n;
+ int cidaSize = CIDA.sizeof + 4 * n;
+ cida.aoffset = cidaSize; // offsets are from cida begin so the first is equal to cida size
+
+ int[] pidlOffsets = new int[n];
+ int[] pidlSizes = new int[n];
+ int pidlSizeSum = 2; // initialize with 2 for the empty (but double null terminated) parent pidl
+ for (int i = 0; i < n; i++) {
+ TCHAR szfileName = new TCHAR(0, fileNames[i], true);
+ long [] ppv = new long [1];
+ int hr = COM.PathToPIDL(szfileName.chars, ppv);
+ if (hr != OS.S_OK) {
+ return 0;
+ }
+ pidls[i] = ppv[0];
+ pidlSizes[i] = OS.ILGetSize(pidls[i]);
+ pidlSizeSum += pidlSizes[i];
+
+ if (i == 0) {
+ pidlOffsets[0] = cidaSize + 2;
+ }
+ else {
+ pidlOffsets[i] = pidlOffsets[i - 1] + pidlSizes[i - 1];
+ }
+ }
+
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, cidaSize + pidlSizeSum);
+ if (newPtr != 0) {
+ OS.MoveMemory(newPtr, cida, CIDA.sizeof);
+ OS.MoveMemory(newPtr + CIDA.sizeof, pidlOffsets, 4 * cida.cidl);
+ for (int i = 0; i < n; i++) {
+ OS.MoveMemory(newPtr + pidlOffsets[i], pidls[i], pidlSizes[i]);
+ }
+ }
+ return newPtr;
+ } finally {
+ for (int i = 0; i < n; i++) {
+ if (pidls[i] != 0) {
+ OS.CoTaskMemFree(pidls[i]);
+ }
+ }
+ }
+}
+
+@Override
+public boolean isSupportedType(TransferData transferData) {
+ // filter Shell ID List Array transfer only for dropping
+ if (transferData != null && transferData.pIDataObject != 0 && transferData.type == CFSTR_SHELLIDLISTID) {
+ return false;
+ }
+ return super.isSupportedType(transferData);
+}
+
+@Override
+protected int[] getTypeIds(){
+ // Note: FileTransfer adds Shell ID List as transfer type but later
+ // limit this type for dragging only.
+ return new int[] {CF_HDROPID, CFSTR_SHELLIDLISTID};
+}
+
+@Override
+protected String[] getTypeNames(){
+ return new String[] {CF_HDROP, CFSTR_SHELLIDLIST};
+}
+boolean checkFile(Object object) {
+ if (object == null || !(object instanceof String[]) || ((String[])object).length == 0) return false;
+ String[] strings = (String[])object;
+ for (int i = 0; i < strings.length; i++) {
+ if (strings[i] == null || strings[i].length() == 0) return false;
+ }
+ return true;
+}
+
+@Override
+protected boolean validate(Object object) {
+ return checkFile(object);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/HTMLTransfer.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/HTMLTransfer.java
new file mode 100644
index 000000000..1be51dba9
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/HTMLTransfer.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * The class HTMLTransfer
provides a platform specific mechanism
+ * for converting text in HTML format represented as a java String
+ * to a platform specific representation of the data and vice versa.
+ *
+ * String
containing HTML text is shown
+ * below:
+ *
+ * @see Transfer
+ */
+public class HTMLTransfer extends ByteArrayTransfer {
+
+ static HTMLTransfer _instance = new HTMLTransfer();
+ static final String HTML_FORMAT = "HTML Format"; //$NON-NLS-1$
+ static final int HTML_FORMATID = registerType(HTML_FORMAT);
+ static final String NUMBER = "00000000"; //$NON-NLS-1$
+ static final String HEADER = "Version:0.9\r\nStartHTML:"+NUMBER+"\r\nEndHTML:"+NUMBER+"\r\nStartFragment:"+NUMBER+"\r\nEndFragment:"+NUMBER+"\r\n";
+ static final String PREFIX = ""; //$NON-NLS-1$
+ static final String SUFFIX = ""; //$NON-NLS-1$
+ static final String StartFragment = "StartFragment:"; //$NON-NLS-1$
+ static final String EndFragment = "EndFragment:"; //$NON-NLS-1$
+
+private HTMLTransfer() {}
+
+/**
+ * Returns the singleton instance of the HTMLTransfer class.
+ *
+ * @return the singleton instance of the HTMLTransfer class
+ */
+public static HTMLTransfer getInstance () {
+ return _instance;
+}
+
+/**
+ * This implementation of
+ * String htmlData = "<p>This is a paragraph of text.</p>";
+ *
javaToNative
converts HTML-formatted text
+ * represented by a java String
to a platform specific representation.
+ *
+ * @param object a java String
containing HTML text
+ * @param transferData an empty TransferData
object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+@Override
+public void javaToNative (Object object, TransferData transferData){
+ if (!checkHTML(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ String string = (String)object;
+ int count = string.length();
+ char[] chars = new char[count + 1];
+ string.getChars(0, count, chars, 0);
+ /* NOTE: CF_HTML uses UTF-8 encoding. */
+ int cchMultiByte = OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, -1, null, 0, null, null);
+ if (cchMultiByte == 0) {
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.DV_E_STGMEDIUM;
+ return;
+ }
+ int startHTML = HEADER.length();
+ int startFragment = startHTML + PREFIX.length();
+ int endFragment = startFragment + cchMultiByte - 1;
+ int endHTML = endFragment + SUFFIX.length();
+
+ StringBuilder buffer = new StringBuilder(HEADER);
+ int maxLength = NUMBER.length();
+ //startHTML
+ int start = buffer.toString().indexOf(NUMBER);
+ String temp = Integer.toString(startHTML);
+ buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+ //endHTML
+ start = buffer.toString().indexOf(NUMBER, start);
+ temp = Integer.toString(endHTML);
+ buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+ //startFragment
+ start = buffer.toString().indexOf(NUMBER, start);
+ temp = Integer.toString(startFragment);
+ buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+ //endFragment
+ start = buffer.toString().indexOf(NUMBER, start);
+ temp = Integer.toString(endFragment);
+ buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+
+ buffer.append(PREFIX);
+ buffer.append(string);
+ buffer.append(SUFFIX);
+
+ count = buffer.length();
+ chars = new char[count + 1];
+ buffer.getChars(0, count, chars, 0);
+ cchMultiByte = OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, -1, null, 0, null, null);
+ long lpMultiByteStr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, cchMultiByte);
+ OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = lpMultiByteStr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ return;
+}
+
+/**
+ * This implementation of nativeToJava
converts a platform specific
+ * representation of HTML text to a java String
.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java String
containing HTML text if the conversion was successful;
+ * otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+@Override
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ FORMATETC formatetc = transferData.formatetc;
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ long hMem = stgmedium.unionField;
+
+ try {
+ long lpMultiByteStr = OS.GlobalLock(hMem);
+ if (lpMultiByteStr == 0) return null;
+ try {
+ /* NOTE: CF_HTML uses UTF-8 encoding.
+ * The MSDN documentation for MultiByteToWideChar states that dwFlags must be set to 0 for UTF-8.
+ * Otherwise, the function fails with ERROR_INVALID_FLAGS. */
+ int cchWideChar = OS.MultiByteToWideChar (OS.CP_UTF8, 0, lpMultiByteStr, -1, null, 0);
+ if (cchWideChar == 0) return null;
+ char[] lpWideCharStr = new char [cchWideChar - 1];
+ OS.MultiByteToWideChar (OS.CP_UTF8, 0, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+ String string = new String(lpWideCharStr);
+ int fragmentStart = 0, fragmentEnd = 0;
+ int start = string.indexOf(StartFragment) + StartFragment.length();
+ int end = start + 1;
+ while (end < string.length()) {
+ String s = string.substring(start, end);
+ try {
+ fragmentStart = Integer.parseInt(s);
+ end++;
+ } catch (NumberFormatException e) {
+ break;
+ }
+ }
+ start = string.indexOf(EndFragment) + EndFragment.length();
+ end = start + 1;
+ while (end < string.length()) {
+ String s = string.substring(start, end);
+ try {
+ fragmentEnd = Integer.parseInt(s);
+ end++;
+ } catch (NumberFormatException e) {
+ break;
+ }
+ }
+ if (fragmentEnd <= fragmentStart || fragmentEnd > C.strlen(lpMultiByteStr)) return null;
+ cchWideChar = OS.MultiByteToWideChar (OS.CP_UTF8, 0, lpMultiByteStr+fragmentStart, fragmentEnd - fragmentStart, lpWideCharStr, lpWideCharStr.length);
+ if (cchWideChar == 0) return null;
+ String s = new String(lpWideCharStr, 0, cchWideChar);
+ /*
+ * Firefox includes in the fragment, so remove it.
+ */
+ String foxStart = "\r\n"; //$NON-NLS-1$
+ int prefix = s.indexOf(foxStart);
+ if (prefix != -1) {
+ prefix += foxStart.length();
+ s = s.substring(prefix);
+ }
+ return s;
+ } finally {
+ OS.GlobalUnlock(hMem);
+ }
+ } finally {
+ OS.GlobalFree(hMem);
+ }
+}
+@Override
+protected int[] getTypeIds(){
+ return new int[] {HTML_FORMATID};
+}
+@Override
+protected String[] getTypeNames(){
+ return new String[] {HTML_FORMAT};
+}
+boolean checkHTML(Object object) {
+ return (object != null && object instanceof String && ((String)object).length() > 0);
+}
+@Override
+protected boolean validate(Object object) {
+ return checkHTML(object);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/ImageTransfer.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/ImageTransfer.java
new file mode 100644
index 000000000..0c678f16c
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/ImageTransfer.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * The class ImageTransfer
provides a platform specific mechanism
+ * for converting an Image represented as a java ImageData
to a
+ * platform specific representation of the data and vice versa.
+ *
+ * ImageData
is shown below:
+ *
+ * @see Transfer
+ *
+ * @since 3.4
+ */
+public class ImageTransfer extends ByteArrayTransfer {
+
+ private static ImageTransfer _instance = new ImageTransfer();
+ private static final String CF_DIB = "CF_DIB"; //$NON-NLS-1$
+ private static final int CF_DIBID = COM.CF_DIB;
+
+private ImageTransfer() {}
+
+/**
+ * Returns the singleton instance of the ImageTransfer class.
+ *
+ * @return the singleton instance of the ImageTransfer class
+ */
+public static ImageTransfer getInstance () {
+ return _instance;
+}
+
+/**
+ * This implementation of
+ * Image image = new Image(display, "C:\\temp\\img1.gif");
+ * ImageData imgData = image.getImageData();
+ *
javaToNative
converts an ImageData object represented
+ * by java ImageData
to a platform specific representation.
+ *
+ * @param object a java ImageData
containing the ImageData to be converted
+ * @param transferData an empty TransferData
object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+@Override
+public void javaToNative(Object object, TransferData transferData) {
+ if (!checkImage(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ ImageData imgData = (ImageData)object;
+ if (imgData == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+
+ int imageSize = imgData.data.length;
+ int imageHeight = imgData.height;
+ int bytesPerLine = imgData.bytesPerLine;
+
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biSizeImage = imageSize;
+ bmiHeader.biWidth = imgData.width;
+ bmiHeader.biHeight = imageHeight;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = (short)imgData.depth;
+ bmiHeader.biCompression = OS.DIB_RGB_COLORS;
+
+ int colorSize = 0;
+ if (bmiHeader.biBitCount <= 8) {
+ colorSize += (1 << bmiHeader.biBitCount) * 4;
+ }
+ byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + colorSize];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+
+ RGB[] rgbs = imgData.palette.getRGBs();
+ if (rgbs != null && colorSize > 0) {
+ int offset = BITMAPINFOHEADER.sizeof;
+ for (int j = 0; j < rgbs.length; j++) {
+ bmi[offset] = (byte)rgbs[j].blue;
+ bmi[offset + 1] = (byte)rgbs[j].green;
+ bmi[offset + 2] = (byte)rgbs[j].red;
+ bmi[offset + 3] = 0;
+ offset += 4;
+ }
+ }
+ long newPtr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, BITMAPINFOHEADER.sizeof + colorSize + imageSize);
+ OS.MoveMemory(newPtr, bmi, bmi.length);
+ long pBitDest = newPtr + BITMAPINFOHEADER.sizeof + colorSize;
+
+ if (imageHeight <= 0) {
+ OS.MoveMemory(pBitDest, imgData.data, imageSize);
+ } else {
+ int offset = 0;
+ pBitDest += bytesPerLine * (imageHeight - 1);
+ byte[] scanline = new byte[bytesPerLine];
+ for (int i = 0; i < imageHeight; i++) {
+ System.arraycopy(imgData.data, offset, scanline, 0, bytesPerLine);
+ OS.MoveMemory(pBitDest, scanline, bytesPerLine);
+ offset += bytesPerLine;
+ pBitDest -= bytesPerLine;
+ }
+ }
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = newPtr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+}
+
+
+/**
+ * This implementation of nativeToJava
converts a platform specific
+ * representation of an image to java ImageData
.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java ImageData
of the image if the conversion was successful;
+ * otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+@Override
+public Object nativeToJava(TransferData transferData) {
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+ IDataObject dataObject = new IDataObject(transferData.pIDataObject);
+ dataObject.AddRef();
+ FORMATETC formatetc = new FORMATETC();
+ formatetc.cfFormat = COM.CF_DIB;
+ formatetc.ptd = 0;
+ formatetc.dwAspect = COM.DVASPECT_CONTENT;
+ formatetc.lindex = -1;
+ formatetc.tymed = COM.TYMED_HGLOBAL;
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(dataObject, formatetc, stgmedium);
+
+ if (transferData.result != COM.S_OK) return null;
+ long hMem = stgmedium.unionField;
+ dataObject.Release();
+ try {
+ long ptr = OS.GlobalLock(hMem);
+ if (ptr == 0) return null;
+ try {
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ OS.MoveMemory(bmiHeader, ptr, BITMAPINFOHEADER.sizeof);
+ long[] pBits = new long[1];
+ long memDib = OS.CreateDIBSection(0, ptr, OS.DIB_RGB_COLORS, pBits, 0, 0);
+ if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ long bits = ptr + bmiHeader.biSize;
+ if (bmiHeader.biBitCount <= 8) {
+ bits += (bmiHeader.biClrUsed == 0 ? (1 << bmiHeader.biBitCount) : bmiHeader.biClrUsed) * 4;
+ } else if (bmiHeader.biCompression == OS.BI_BITFIELDS) {
+ bits += 12;
+ }
+ if (bmiHeader.biHeight < 0) {
+ OS.MoveMemory(pBits[0], bits, bmiHeader.biSizeImage);
+ } else {
+ DIBSECTION dib = new DIBSECTION();
+ OS.GetObject(memDib, DIBSECTION.sizeof, dib);
+ int biHeight = dib.biHeight;
+ int scanline = dib.biSizeImage / biHeight;
+ long pDestBits = pBits[0];
+ long pSourceBits = bits + scanline * (biHeight - 1);
+ for (int i = 0; i < biHeight; i++) {
+ OS.MoveMemory(pDestBits, pSourceBits, scanline);
+ pDestBits += scanline;
+ pSourceBits -= scanline;
+ }
+ }
+ Image image = Image.win32_new(null, SWT.BITMAP, memDib);
+ ImageData data = image.getImageData (DPIUtil.getDeviceZoom ());
+ OS.DeleteObject(memDib);
+ image.dispose();
+ return data;
+ } finally {
+ OS.GlobalUnlock(hMem);
+ }
+ } finally {
+ OS.GlobalFree(hMem);
+ }
+}
+
+@Override
+protected int[] getTypeIds(){
+ return new int[] {CF_DIBID};
+}
+
+@Override
+protected String[] getTypeNames(){
+ return new String[] {CF_DIB};
+}
+boolean checkImage(Object object) {
+ if (object == null || !(object instanceof ImageData)) return false;
+ return true;
+}
+
+@Override
+protected boolean validate(Object object) {
+ return checkImage(object);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/OleEnumFORMATETC.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/OleEnumFORMATETC.java
new file mode 100644
index 000000000..cb7278f95
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/OleEnumFORMATETC.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+final class OleEnumFORMATETC {
+
+ private COMObject iEnumFORMATETC;
+
+ private int refCount;
+ private int index;
+
+ private FORMATETC[] formats;
+
+OleEnumFORMATETC() {
+
+ createCOMInterfaces();
+
+}
+int AddRef() {
+ refCount++;
+ return refCount;
+}
+private void createCOMInterfaces() {
+ iEnumFORMATETC = new COMObject(new int[] {2, 0, 0, 3, 1, 0, 1}){
+ @Override
+ public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ @Override
+ public long method3(long[] args) {return Next((int)args[0], args[1], args[2]);}
+ @Override
+ public long method4(long[] args) {return Skip((int)args[0]);}
+ @Override
+ public long method5(long[] args) {return Reset();}
+ // method6 Clone - not implemented
+ };
+}
+private void disposeCOMInterfaces() {
+ if (iEnumFORMATETC != null)
+ iEnumFORMATETC.dispose();
+ iEnumFORMATETC = null;
+}
+long getAddress() {
+ return iEnumFORMATETC.getAddress();
+}
+private FORMATETC[] getNextItems(int numItems){
+
+ if (formats == null || numItems < 1) return null;
+
+ int endIndex = index + numItems - 1;
+ if (endIndex > (formats.length - 1)) endIndex = formats.length - 1;
+ if (index > endIndex) return null;
+
+ FORMATETC[] items = new FORMATETC[endIndex - index + 1];
+ for (int i = 0; i < items.length; i++){
+ items[i] = formats[index];
+ index++;
+ }
+
+ return items;
+}
+private int Next(int celt, long rgelt, long pceltFetched) {
+ /* Retrieves the next celt items in the enumeration sequence.
+ If there are fewer than the requested number of elements left in the sequence,
+ it retrieves the remaining elements.
+ The number of elements actually retrieved is returned through pceltFetched
+ (unless the caller passed in NULL for that parameter).
+ */
+
+ if (rgelt == 0) return COM.E_INVALIDARG;
+ if (pceltFetched == 0 && celt != 1) return COM.E_INVALIDARG;
+
+ FORMATETC[] nextItems = getNextItems(celt);
+ if (nextItems != null) {
+ for (int i = 0; i < nextItems.length; i++) {
+ COM.MoveMemory(rgelt + i*FORMATETC.sizeof, nextItems[i], FORMATETC.sizeof);
+ }
+
+ if (pceltFetched != 0)
+ OS.MoveMemory(pceltFetched, new int[] {nextItems.length}, 4);
+
+ if (nextItems.length == celt) return COM.S_OK;
+
+ } else {
+ if (pceltFetched != 0)
+ OS.MoveMemory(pceltFetched, new int[] {0}, 4);
+ COM.MoveMemory(rgelt, new FORMATETC(), FORMATETC.sizeof);
+
+ }
+ return COM.S_FALSE;
+}
+private int QueryInterface(long riid, long ppvObject) {
+
+ if (riid == 0 || ppvObject == 0) return COM.E_NOINTERFACE;
+
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+
+ if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIEnumFORMATETC)) {
+ OS.MoveMemory(ppvObject, new long[] {iEnumFORMATETC.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+int Release() {
+ refCount--;
+
+ if (refCount == 0) {
+ disposeCOMInterfaces();
+ if (COM.FreeUnusedLibraries) {
+ COM.CoFreeUnusedLibraries();
+ }
+ }
+
+ return refCount;
+}
+private int Reset() {
+ //Resets the enumeration sequence to the beginning.
+ index = 0;
+ return COM.S_OK;
+}
+void setFormats(FORMATETC[] newFormats) {
+ formats = newFormats;
+ index = 0;
+}
+private int Skip(int celt) {
+ //Skips over the next specified number of elements in the enumeration sequence.
+ if (celt < 1 ) return COM.E_INVALIDARG;
+
+ index += celt;
+ if (index > (formats.length - 1)){
+ index = formats.length - 1;
+ return COM.S_FALSE;
+ }
+ return COM.S_OK;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/RTFTransfer.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/RTFTransfer.java
new file mode 100644
index 000000000..ab1fbb1f8
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/RTFTransfer.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * The class RTFTransfer
provides a platform specific mechanism
+ * for converting text in RTF format represented as a java String
+ * to a platform specific representation of the data and vice versa.
+ *
+ * String
containing RTF text is shown
+ * below:
+ *
+ * @see Transfer
+ */
+public class RTFTransfer extends ByteArrayTransfer {
+
+ private static RTFTransfer _instance = new RTFTransfer();
+ private static final String CF_RTF = "Rich Text Format"; //$NON-NLS-1$
+ private static final int CF_RTFID = registerType(CF_RTF);
+
+private RTFTransfer() {}
+
+/**
+ * Returns the singleton instance of the RTFTransfer class.
+ *
+ * @return the singleton instance of the RTFTransfer class
+ */
+public static RTFTransfer getInstance () {
+ return _instance;
+}
+
+/**
+ * This implementation of
+ * String rtfData = "{\\rtf1{\\colortbl;\\red255\\green0\\blue0;}\\uc1\\b\\i Hello World}";
+ *
javaToNative
converts RTF-formatted text
+ * represented by a java String
to a platform specific representation.
+ *
+ * @param object a java String
containing RTF text
+ * @param transferData an empty TransferData
object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+@Override
+public void javaToNative (Object object, TransferData transferData){
+ if (!checkRTF(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ // CF_RTF is stored as a null terminated byte array
+ String string = (String)object;
+ int count = string.length();
+ char[] chars = new char[count + 1];
+ string.getChars(0, count, chars, 0);
+ int codePage = OS.GetACP();
+ int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+ if (cchMultiByte == 0) {
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.DV_E_STGMEDIUM;
+ return;
+ }
+ long lpMultiByteStr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, cchMultiByte);
+ OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = lpMultiByteStr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ return;
+}
+
+/**
+ * This implementation of nativeToJava
converts a platform specific
+ * representation of RTF text to a java String
.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java String
containing RTF text if the conversion was successful;
+ * otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+@Override
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ FORMATETC formatetc = transferData.formatetc;
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ long hMem = stgmedium.unionField;
+ try {
+ long lpMultiByteStr = OS.GlobalLock(hMem);
+ if (lpMultiByteStr == 0) return null;
+ try {
+ int codePage = OS.GetACP();
+ int cchWideChar = OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, null, 0);
+ if (cchWideChar == 0) return null;
+ char[] lpWideCharStr = new char [cchWideChar - 1];
+ OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+ return new String(lpWideCharStr);
+ } finally {
+ OS.GlobalUnlock(hMem);
+ }
+ } finally {
+ OS.GlobalFree(hMem);
+ }
+}
+
+@Override
+protected int[] getTypeIds(){
+ return new int[] {CF_RTFID};
+}
+
+@Override
+protected String[] getTypeNames(){
+ return new String[] {CF_RTF};
+}
+
+boolean checkRTF(Object object) {
+ return (object != null && object instanceof String && ((String)object).length() > 0);
+}
+
+@Override
+protected boolean validate(Object object) {
+ return checkRTF(object);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TableDragSourceEffect.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TableDragSourceEffect.java
new file mode 100644
index 000000000..8eac76a34
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TableDragSourceEffect.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.DPIUtil.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides default implementations to display a source image
+ * when a drag is initiated from a Table
.
+ *
+ * Table
can
+ * extend the TableDragSourceEffect
class, override the
+ * TableDragSourceEffect.dragStart
method and set the field
+ * DragSourceEvent.image
with their own image.super
method to get the default drag source effect implementation.
+ *
+ * @see DragSourceEffect
+ * @see DragSourceEvent
+ * @see Sample code and further information
+ *
+ * @since 3.3
+ */
+public class TableDragSourceEffect extends DragSourceEffect {
+ Image dragSourceImage = null;
+
+ /**
+ * Creates a new TableDragSourceEffect
to handle drag effect
+ * from the specified Table
.
+ *
+ * @param table the Table
that the user clicks on to initiate the drag
+ */
+ public TableDragSourceEffect(Table table) {
+ super(table);
+ }
+
+ /**
+ * This implementation of dragFinished
disposes the image
+ * that was created in TableDragSourceEffect.dragStart
.
+ *
+ * Subclasses that override this method should call super.dragFinished(event)
+ * to dispose the image in the default implementation.
+ *
+ * @param event the information associated with the drag finished event
+ */
+ @Override
+ public void dragFinished(DragSourceEvent event) {
+ if (dragSourceImage != null) dragSourceImage.dispose();
+ dragSourceImage = null;
+ }
+
+ /**
+ * This implementation of dragStart
will create a default
+ * image that will be used during the drag. The image should be disposed
+ * when the drag is completed in the TableDragSourceEffect.dragFinished
+ * method.
+ *
+ * Subclasses that override this method should call super.dragStart(event)
+ * to use the image from the default implementation.
+ *
+ * @param event the information associated with the drag start event
+ */
+ @Override
+ public void dragStart(DragSourceEvent event) {
+ event.image = getDragSourceImage(event);
+ }
+
+ Image getDragSourceImage(DragSourceEvent event) {
+ if (dragSourceImage != null) dragSourceImage.dispose();
+ dragSourceImage = null;
+ SHDRAGIMAGE shdi = new SHDRAGIMAGE();
+ int DI_GETDRAGIMAGE = OS.RegisterWindowMessage (new TCHAR (0, "ShellGetDragImage", true)); //$NON-NLS-1$
+ if (OS.SendMessage (control.handle, DI_GETDRAGIMAGE, 0, shdi) != 0) {
+ if ((control.getStyle() & SWT.MIRRORED) != 0) {
+ event.offsetX = shdi.sizeDragImage.cx - shdi.ptOffset.x;
+ } else {
+ event.offsetX = shdi.ptOffset.x;
+ }
+ event.offsetY = shdi.ptOffset.y;
+ long hImage = shdi.hbmpDragImage;
+ if (hImage != 0) {
+ BITMAP bm = new BITMAP ();
+ OS.GetObject (hImage, BITMAP.sizeof, bm);
+ int srcWidth = bm.bmWidth;
+ int srcHeight = bm.bmHeight;
+
+ /* Create resources */
+ long hdc = OS.GetDC (0);
+ long srcHdc = OS.CreateCompatibleDC (hdc);
+ long oldSrcBitmap = OS.SelectObject (srcHdc, hImage);
+ long memHdc = OS.CreateCompatibleDC (hdc);
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = srcWidth;
+ bmiHeader.biHeight = -srcHeight;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = 32;
+ bmiHeader.biCompression = OS.BI_RGB;
+ byte [] bmi = new byte[BITMAPINFOHEADER.sizeof];
+ OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ long [] pBits = new long [1];
+ long memDib = OS.CreateDIBSection (0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
+ if (memDib == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+ long oldMemBitmap = OS.SelectObject (memHdc, memDib);
+
+ BITMAP dibBM = new BITMAP ();
+ OS.GetObject (memDib, BITMAP.sizeof, dibBM);
+ int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
+
+ /* Get the foreground pixels */
+ OS.BitBlt (memHdc, 0, 0, srcWidth, srcHeight, srcHdc, 0, 0, OS.SRCCOPY);
+ byte[] srcData = new byte [sizeInBytes];
+ OS.MoveMemory (srcData, dibBM.bmBits, sizeInBytes);
+
+ PaletteData palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ ImageData data = new ImageData(srcWidth, srcHeight, bm.bmBitsPixel, palette, bm.bmWidthBytes, srcData);
+ if (shdi.crColorKey == -1) {
+ byte[] alphaData = new byte[srcWidth * srcHeight];
+ int spinc = dibBM.bmWidthBytes - srcWidth * 4;
+ int ap = 0, sp = 3;
+ for (int y = 0; y < srcHeight; ++y) {
+ for (int x = 0; x < srcWidth; ++x) {
+ alphaData [ap++] = srcData [sp];
+ sp += 4;
+ }
+ sp += spinc;
+ }
+ data.alphaData = alphaData;
+ } else {
+ data.transparentPixel = shdi.crColorKey << 8;
+ }
+ Display display = control.getDisplay();
+ dragSourceImage = new Image(display, new AutoScaleImageDataProvider(display, data, DPIUtil.getDeviceZoom()));
+ OS.SelectObject (memHdc, oldMemBitmap);
+ OS.DeleteDC (memHdc);
+ OS.DeleteObject (memDib);
+ OS.SelectObject (srcHdc, oldSrcBitmap);
+ OS.DeleteDC (srcHdc);
+ OS.ReleaseDC (0, hdc);
+ OS.DeleteObject (hImage);
+ return dragSourceImage;
+ }
+ }
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TableDropTargetEffect.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TableDropTargetEffect.java
new file mode 100644
index 000000000..42cb9d6b8
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TableDropTargetEffect.java
@@ -0,0 +1,235 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides a default drag under effect (eg. select, insert and scroll)
+ * when a drag occurs over a Table
.
+ *
+ * Table
+ * can extend the TableDropTargetEffect
and override any applicable methods
+ * in TableDropTargetEffect
to display their own drag under effect.super
method to get the default drag under effect implementation.
+ *
+ * DND
which is applicable to instances of this class,
+ * or it must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those DND
effect constants.
+ *
+ *
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ * @see Sample code and further information
+ *
+ * @since 3.3
+ */
+public class TableDropTargetEffect extends DropTargetEffect {
+ static final int SCROLL_HYSTERESIS = 200; // milli seconds
+
+ int scrollIndex = -1;
+ long scrollBeginTime;
+ TableItem dropHighlight;
+ int iItemInsert = -1;
+
+ /**
+ * Creates a new TableDropTargetEffect
to handle the drag under effect on the specified
+ * Table
.
+ *
+ * @param table the Table
over which the user positions the cursor to drop the data
+ */
+ public TableDropTargetEffect(Table table) {
+ super(table);
+ }
+
+ int checkEffect(int effect) {
+ // Some effects are mutually exclusive. Make sure that only one of the mutually exclusive effects has been specified.
+ if ((effect & DND.FEEDBACK_SELECT) != 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE;
+ if ((effect & DND.FEEDBACK_INSERT_BEFORE) != 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER;
+ return effect;
+ }
+
+ /**
+ * This implementation of dragEnter
provides a default drag under effect
+ * for the feedback specified in event.feedback
.
+ *
+ * For additional information see DropTargetAdapter.dragEnter
.
+ *
+ * Subclasses that override this method should call super.dragEnter(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag enter event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ @Override
+ public void dragEnter(DropTargetEvent event) {
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ dropHighlight = null;
+ iItemInsert = -1;
+ }
+
+ /**
+ * This implementation of dragLeave
provides a default drag under effect
+ * for the feedback specified in event.feedback
.
+ *
+ * For additional information see DropTargetAdapter.dragLeave
.
+ *
+ * Subclasses that override this method should call super.dragLeave(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag leave event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ @Override
+ public void dragLeave(DropTargetEvent event) {
+ Table table = (Table) control;
+ long handle = table.handle;
+ if (dropHighlight != null) {
+ LVITEM lvItem = new LVITEM ();
+ lvItem.stateMask = OS.LVIS_DROPHILITED;
+ OS.SendMessage(handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+ dropHighlight = null;
+ }
+ if (iItemInsert != -1) {
+ LVINSERTMARK plvim = new LVINSERTMARK ();
+ plvim.cbSize = LVINSERTMARK.sizeof;
+ plvim.iItem = -1;
+ OS.SendMessage(handle, OS.LVM_SETINSERTMARK, 0, plvim);
+ iItemInsert = -1;
+ }
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+
+ /**
+ * This implementation of dragOver
provides a default drag under effect
+ * for the feedback specified in event.feedback
. The class description
+ * lists the FEEDBACK constants that are applicable to the class.
+ *
+ * For additional information see DropTargetAdapter.dragOver
.
+ *
+ * Subclasses that override this method should call super.dragOver(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag over event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ * @see DND#FEEDBACK_SELECT
+ * @see DND#FEEDBACK_SCROLL
+ */
+ @Override
+ public void dragOver(DropTargetEvent event) {
+ Table table = (Table) getControl();
+ int effect = checkEffect(event.feedback);
+ long handle = table.handle;
+ Point coordinates = new Point(event.x, event.y);
+ coordinates = DPIUtil.autoScaleUp(table.toControl(coordinates)); // To Pixels
+ LVHITTESTINFO pinfo = new LVHITTESTINFO();
+ pinfo.x = coordinates.x;
+ pinfo.y = coordinates.y;
+ OS.SendMessage(handle, OS.LVM_HITTEST, 0, pinfo);
+ if ((effect & DND.FEEDBACK_SCROLL) == 0) {
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ } else {
+ if (pinfo.iItem != -1 && scrollIndex == pinfo.iItem && scrollBeginTime != 0) {
+ if (System.currentTimeMillis() >= scrollBeginTime) {
+ int top = Math.max (0, (int)OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0));
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ int index = (scrollIndex - 1 < top) ? Math.max(0, scrollIndex - 1) : Math.min(count - 1, scrollIndex + 1);
+ boolean scroll = true;
+ if (pinfo.iItem == top) {
+ scroll = pinfo.iItem != index;
+ } else {
+ RECT itemRect = new RECT ();
+ itemRect.left = OS.LVIR_BOUNDS;
+ if (OS.SendMessage (handle, OS.LVM_GETITEMRECT, pinfo.iItem, itemRect) != 0) {
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ POINT pt = new POINT ();
+ pt.x = itemRect.left;
+ pt.y = itemRect.top;
+ if (OS.PtInRect (rect, pt)) {
+ pt.y = itemRect.bottom;
+ if (OS.PtInRect (rect, pt)) scroll = false;
+ }
+ }
+ }
+ if (scroll) {
+ OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 0);
+ table.redraw();
+ }
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+ } else {
+ scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+ scrollIndex = pinfo.iItem;
+ }
+ }
+
+ if (pinfo.iItem != -1 && (effect & DND.FEEDBACK_SELECT) != 0) {
+ TableItem item = table.getItem(pinfo.iItem);
+ if (dropHighlight != item) {
+ LVITEM lvItem = new LVITEM();
+ lvItem.stateMask = OS.LVIS_DROPHILITED;
+ OS.SendMessage(handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+ lvItem.state = OS.LVIS_DROPHILITED;
+ OS.SendMessage(handle, OS.LVM_SETITEMSTATE, pinfo.iItem, lvItem);
+ dropHighlight = item;
+ }
+ } else {
+ if (dropHighlight != null) {
+ LVITEM lvItem = new LVITEM ();
+ lvItem.stateMask = OS.LVIS_DROPHILITED;
+ OS.SendMessage(handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+ dropHighlight = null;
+ }
+ }
+ if (pinfo.iItem != -1 && (effect & (DND.FEEDBACK_INSERT_BEFORE | DND.FEEDBACK_INSERT_AFTER)) != 0) {
+ LVINSERTMARK plvim = new LVINSERTMARK ();
+ plvim.cbSize = LVINSERTMARK.sizeof;
+ plvim.dwFlags = (effect & DND.FEEDBACK_INSERT_AFTER) != 0 ? OS.LVIM_AFTER : 0;
+ plvim.iItem = pinfo.iItem;
+ if (OS.SendMessage(handle, OS.LVM_SETINSERTMARK, 0, plvim) != 0) {
+ iItemInsert = pinfo.iItem;
+ }
+ } else {
+ if (iItemInsert != -1) {
+ LVINSERTMARK plvim = new LVINSERTMARK ();
+ plvim.cbSize = LVINSERTMARK.sizeof;
+ plvim.iItem = -1;
+ OS.SendMessage(handle, OS.LVM_SETINSERTMARK, 0, plvim);
+ iItemInsert = -1;
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TextTransfer.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TextTransfer.java
new file mode 100644
index 000000000..c9c233ece
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TextTransfer.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * The class TextTransfer
provides a platform specific mechanism
+ * for converting plain text represented as a java String
+ * to a platform specific representation of the data and vice versa.
+ *
+ * String
containing plain text is shown
+ * below:
+ *
+ *
+ * String textData = "Hello World";
+ *
TextTransfer
does not change the content of the text
+ * data. For a better integration with the platform, the application should convert
+ * the line delimiters used in the text data to the standard line delimiter used by the
+ * platform.
+ * javaToNative
converts plain text
+ * represented by a java String
to a platform specific representation.
+ *
+ * @param object a java String
containing text
+ * @param transferData an empty TransferData
object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+@Override
+public void javaToNative (Object object, TransferData transferData){
+ if (!checkText(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ transferData.result = COM.E_FAIL;
+ String string = (String)object;
+ switch (transferData.type) {
+ case COM.CF_UNICODETEXT: {
+ int charCount = string.length ();
+ char[] chars = new char[charCount+1];
+ string.getChars (0, charCount, chars, 0);
+ int byteCount = chars.length * 2;
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, byteCount);
+ OS.MoveMemory(newPtr, chars, byteCount);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = newPtr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ break;
+ }
+ case COM.CF_TEXT: {
+ int count = string.length();
+ char[] chars = new char[count + 1];
+ string.getChars(0, count, chars, 0);
+ int codePage = OS.GetACP();
+ int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+ if (cchMultiByte == 0) {
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.DV_E_STGMEDIUM;
+ return;
+ }
+ long lpMultiByteStr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, cchMultiByte);
+ OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = lpMultiByteStr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ break;
+ }
+ }
+ return;
+}
+
+/**
+ * This implementation of nativeToJava
converts a platform specific
+ * representation of plain text to a java String
.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java String
containing text if the conversion was successful; otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+@Override
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ FORMATETC formatetc = transferData.formatetc;
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ long hMem = stgmedium.unionField;
+ try {
+ switch (transferData.type) {
+ case CF_UNICODETEXTID: {
+ /* Ensure byteCount is a multiple of 2 bytes */
+ int size = OS.GlobalSize(hMem) / 2 * 2;
+ if (size == 0) return null;
+ char[] chars = new char[size/2];
+ long ptr = OS.GlobalLock(hMem);
+ if (ptr == 0) return null;
+ try {
+ OS.MoveMemory(chars, ptr, size);
+ int length = chars.length;
+ for (int i=0; iTransfer
provides a mechanism for converting between a java
+ * representation of data and a platform specific representation of data and
+ * vice versa. It is used in data transfer operations such as drag and drop and
+ * clipboard copy/paste.
+ *
+ * TransferData
objects are filled
+ * in.TransferData
data type can be converted
+ * using this transfer agent, or false otherwise (including if transferData is
+ * null
).
+ *
+ * @param transferData a platform specific description of a data type; only the data
+ * type fields of the TransferData
object need to be filled in
+ *
+ * @return true if the transferData data type can be converted using this transfer
+ * agent
+ */
+abstract public boolean isSupportedType(TransferData transferData);
+
+/**
+ * Returns the platform specific ids of the data types that can be converted using
+ * this transfer agent.
+ *
+ * @return the platform specific ids of the data types that can be converted using
+ * this transfer agent
+ */
+abstract protected int[] getTypeIds();
+
+/**
+ * Returns the platform specific names of the data types that can be converted
+ * using this transfer agent.
+ *
+ * @return the platform specific names of the data types that can be converted
+ * using this transfer agent.
+ */
+abstract protected String[] getTypeNames();
+
+/**
+ * Converts a java representation of data to a platform specific representation of
+ * the data.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * @param object a java representation of the data to be converted; the type of
+ * Object that is passed in is dependent on the Transfer
subclass.
+ *
+ * @param transferData an empty TransferData object; this object will be
+ * filled in on return with the platform specific representation of the data
+ *
+ * @exception org.eclipse.swt.SWTException
+ *
+ */
+abstract protected void javaToNative (Object object, TransferData transferData);
+
+/**
+ * Converts a platform specific representation of data to a java representation.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * converted
+ *
+ * @return a java representation of the converted data if the conversion was
+ * successful; otherwise null. If transferData is null
null
then
+ * null
is returned. The type of Object that is returned is
+ * dependent on the Transfer
subclass.
+ */
+abstract protected Object nativeToJava(TransferData transferData);
+
+/**
+ * Registers a name for a data type and returns the associated unique identifier.
+ *
+ * TransferData
class is a platform specific data structure for
+ * describing the type and the contents of data being converted by a transfer agent.
+ *
+ * Tree
.
+ *
+ * Tree
can
+ * extend TreeDragSourceEffect
class and override the TreeDragSourceEffect.dragStart
+ * method and set the field DragSourceEvent.image
with their own image.super
method to get the default drag under effect implementation.
+ *
+ * @see DragSourceEffect
+ * @see DragSourceEvent
+ * @see Sample code and further information
+ *
+ * @since 3.3
+ */
+public class TreeDragSourceEffect extends DragSourceEffect {
+ Image dragSourceImage = null;
+
+ /**
+ * Creates a new TreeDragSourceEffect
to handle drag effect
+ * from the specified Tree
.
+ *
+ * @param tree the Tree
that the user clicks on to initiate the drag
+ */
+ public TreeDragSourceEffect(Tree tree) {
+ super(tree);
+ }
+
+ /**
+ * This implementation of dragFinished
disposes the image
+ * that was created in TreeDragSourceEffect.dragStart
.
+ *
+ * Subclasses that override this method should call super.dragFinished(event)
+ * to dispose the image in the default implementation.
+ *
+ * @param event the information associated with the drag finished event
+ */
+ @Override
+ public void dragFinished(DragSourceEvent event) {
+ if (dragSourceImage != null) dragSourceImage.dispose();
+ dragSourceImage = null;
+ }
+
+ /**
+ * This implementation of dragStart
will create a default
+ * image that will be used during the drag. The image should be disposed
+ * when the drag is completed in the TreeDragSourceEffect.dragFinished
+ * method.
+ *
+ * Subclasses that override this method should call super.dragStart(event)
+ * to use the image from the default implementation.
+ *
+ * @param event the information associated with the drag start event
+ */
+ @Override
+ public void dragStart(DragSourceEvent event) {
+ event.image = getDragSourceImage(event);
+ }
+
+ Image getDragSourceImage(DragSourceEvent event) {
+ if (dragSourceImage != null) dragSourceImage.dispose();
+ dragSourceImage = null;
+ SHDRAGIMAGE shdi = new SHDRAGIMAGE();
+ int DI_GETDRAGIMAGE = OS.RegisterWindowMessage (new TCHAR (0, "ShellGetDragImage", true)); //$NON-NLS-1$
+ if (OS.SendMessage (control.handle, DI_GETDRAGIMAGE, 0, shdi) != 0) {
+ if ((control.getStyle() & SWT.MIRRORED) != 0) {
+ event.offsetX = shdi.sizeDragImage.cx - shdi.ptOffset.x;
+ } else {
+ event.offsetX = shdi.ptOffset.x;
+ }
+ event.offsetY = shdi.ptOffset.y;
+ long hImage = shdi.hbmpDragImage;
+ if (hImage != 0) {
+ BITMAP bm = new BITMAP ();
+ OS.GetObject (hImage, BITMAP.sizeof, bm);
+ int srcWidth = bm.bmWidth;
+ int srcHeight = bm.bmHeight;
+
+ /* Create resources */
+ long hdc = OS.GetDC (0);
+ long srcHdc = OS.CreateCompatibleDC (hdc);
+ long oldSrcBitmap = OS.SelectObject (srcHdc, hImage);
+ long memHdc = OS.CreateCompatibleDC (hdc);
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = srcWidth;
+ bmiHeader.biHeight = -srcHeight;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = 32;
+ bmiHeader.biCompression = OS.BI_RGB;
+ byte [] bmi = new byte[BITMAPINFOHEADER.sizeof];
+ OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ long [] pBits = new long [1];
+ long memDib = OS.CreateDIBSection (0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
+ if (memDib == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+ long oldMemBitmap = OS.SelectObject (memHdc, memDib);
+
+ BITMAP dibBM = new BITMAP ();
+ OS.GetObject (memDib, BITMAP.sizeof, dibBM);
+ int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
+
+ /* Get the foreground pixels */
+ OS.BitBlt (memHdc, 0, 0, srcWidth, srcHeight, srcHdc, 0, 0, OS.SRCCOPY);
+ byte[] srcData = new byte [sizeInBytes];
+ OS.MoveMemory (srcData, dibBM.bmBits, sizeInBytes);
+
+ PaletteData palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ ImageData data = new ImageData(srcWidth, srcHeight, bm.bmBitsPixel, palette, bm.bmWidthBytes, srcData);
+ if (shdi.crColorKey == -1) {
+ byte[] alphaData = new byte[srcWidth * srcHeight];
+ int spinc = dibBM.bmWidthBytes - srcWidth * 4;
+ int ap = 0, sp = 3;
+ for (int y = 0; y < srcHeight; ++y) {
+ for (int x = 0; x < srcWidth; ++x) {
+ alphaData [ap++] = srcData [sp];
+ sp += 4;
+ }
+ sp += spinc;
+ }
+ data.alphaData = alphaData;
+ } else {
+ data.transparentPixel = shdi.crColorKey << 8;
+ }
+ Display display = control.getDisplay ();
+ dragSourceImage = new Image (display, new AutoScaleImageDataProvider(display, data, DPIUtil.getDeviceZoom()));
+ OS.SelectObject (memHdc, oldMemBitmap);
+ OS.DeleteDC (memHdc);
+ OS.DeleteObject (memDib);
+ OS.SelectObject (srcHdc, oldSrcBitmap);
+ OS.DeleteDC (srcHdc);
+ OS.ReleaseDC (0, hdc);
+ OS.DeleteObject (hImage);
+ return dragSourceImage;
+ }
+ }
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TreeDropTargetEffect.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TreeDropTargetEffect.java
new file mode 100644
index 000000000..87385adfd
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/TreeDropTargetEffect.java
@@ -0,0 +1,284 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides a default drag under effect (eg. select, insert, scroll and expand)
+ * when a drag occurs over a Tree
.
+ *
+ * Tree
+ * can extend the TreeDropTargetEffect
class and override any applicable methods
+ * in TreeDropTargetEffect
to display their own drag under effect.super
method to get the default drag under effect implementation.
+ *
+ * DND
which is applicable to instances of this class,
+ * or it must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those DND
effect constants.
+ *
+ *
+ * TreeDropTargetEffect
to handle the drag under effect on the specified
+ * Tree
.
+ *
+ * @param tree the Tree
over which the user positions the cursor to drop the data
+ */
+ public TreeDropTargetEffect(Tree tree) {
+ super(tree);
+ }
+
+ int checkEffect(int effect) {
+ // Some effects are mutually exclusive. Make sure that only one of the mutually exclusive effects has been specified.
+ if ((effect & DND.FEEDBACK_SELECT) != 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE;
+ if ((effect & DND.FEEDBACK_INSERT_BEFORE) != 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER;
+ return effect;
+ }
+
+ /**
+ * This implementation of dragEnter
provides a default drag under effect
+ * for the feedback specified in event.feedback
.
+ *
+ * For additional information see DropTargetAdapter.dragEnter
.
+ *
+ * Subclasses that override this method should call super.dragEnter(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag enter event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ @Override
+ public void dragEnter(DropTargetEvent event) {
+ dropIndex = -1;
+ insertItem = null;
+ expandBeginTime = 0;
+ expandIndex = -1;
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+
+ /**
+ * This implementation of dragLeave
provides a default drag under effect
+ * for the feedback specified in event.feedback
.
+ *
+ * For additional information see DropTargetAdapter.dragLeave
.
+ *
+ * Subclasses that override this method should call super.dragLeave(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag leave event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ @Override
+ public void dragLeave(DropTargetEvent event) {
+ Tree tree = (Tree) control;
+ long handle = tree.handle;
+ if (dropIndex != -1) {
+ TVITEM tvItem = new TVITEM ();
+ tvItem.hItem = dropIndex;
+ tvItem.mask = OS.TVIF_STATE;
+ tvItem.stateMask = OS.TVIS_DROPHILITED;
+ tvItem.state = 0;
+ OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
+ dropIndex = -1;
+ }
+ if (insertItem != null) {
+ tree.setInsertMark(null, false);
+ insertItem = null;
+ }
+ expandBeginTime = 0;
+ expandIndex = -1;
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+
+ /**
+ * This implementation of dragOver
provides a default drag under effect
+ * for the feedback specified in event.feedback
.
+ *
+ * For additional information see DropTargetAdapter.dragOver
.
+ *
+ * Subclasses that override this method should call super.dragOver(event)
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag over event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ * @see DND#FEEDBACK_SELECT
+ * @see DND#FEEDBACK_INSERT_BEFORE
+ * @see DND#FEEDBACK_INSERT_AFTER
+ * @see DND#FEEDBACK_SCROLL
+ */
+ @Override
+ public void dragOver(DropTargetEvent event) {
+ Tree tree = (Tree) getControl();
+ int effect = checkEffect(event.feedback);
+ long handle = tree.handle;
+ Point coordinates = new Point(event.x, event.y);
+ coordinates = DPIUtil.autoScaleUp(tree.toControl(coordinates)); // To Pixels
+ TVHITTESTINFO lpht = new TVHITTESTINFO ();
+ lpht.x = coordinates.x;
+ lpht.y = coordinates.y;
+ OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
+ long hItem = lpht.hItem;
+ if ((effect & DND.FEEDBACK_SCROLL) == 0) {
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ } else {
+ if (hItem != -1 && scrollIndex == hItem && scrollBeginTime != 0) {
+ if (System.currentTimeMillis() >= scrollBeginTime) {
+ long topItem = OS.SendMessage(handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
+ long nextItem = OS.SendMessage(handle, OS.TVM_GETNEXTITEM, hItem == topItem ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE, hItem);
+ boolean scroll = true;
+ if (hItem == topItem) {
+ scroll = nextItem != 0;
+ } else {
+ RECT itemRect = new RECT ();
+ if (OS.TreeView_GetItemRect (handle, nextItem, itemRect, true)) {
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ POINT pt = new POINT ();
+ pt.x = itemRect.left;
+ pt.y = itemRect.top;
+ if (OS.PtInRect (rect, pt)) {
+ pt.y = itemRect.bottom;
+ if (OS.PtInRect (rect, pt)) scroll = false;
+ }
+ }
+ }
+ if (scroll) {
+ OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, nextItem);
+ tree.redraw();
+ }
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+ } else {
+ scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+ scrollIndex = hItem;
+ }
+ }
+ if ((effect & DND.FEEDBACK_EXPAND) == 0) {
+ expandBeginTime = 0;
+ expandIndex = -1;
+ } else {
+ if (hItem != -1 && expandIndex == hItem && expandBeginTime != 0) {
+ if (System.currentTimeMillis() >= expandBeginTime) {
+ if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem) != 0) {
+ TreeItem item = (TreeItem)tree.getDisplay().findWidget(tree.handle, hItem);
+ if (item != null && !item.getExpanded()) {
+ item.setExpanded(true);
+ tree.redraw();
+ Event expandEvent = new Event ();
+ expandEvent.item = item;
+ tree.notifyListeners(SWT.Expand, expandEvent);
+ }
+ }
+ expandBeginTime = 0;
+ expandIndex = -1;
+ }
+ } else {
+ expandBeginTime = System.currentTimeMillis() + EXPAND_HYSTERESIS;
+ expandIndex = hItem;
+ }
+ }
+ if (dropIndex != -1 && (dropIndex != hItem || (effect & DND.FEEDBACK_SELECT) == 0)) {
+ TVITEM tvItem = new TVITEM ();
+ tvItem.hItem = dropIndex;
+ tvItem.mask = OS.TVIF_STATE;
+ tvItem.stateMask = OS.TVIS_DROPHILITED;
+ tvItem.state = 0;
+ OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
+ dropIndex = -1;
+ }
+ if (hItem != -1 && hItem != dropIndex && (effect & DND.FEEDBACK_SELECT) != 0) {
+ TVITEM tvItem = new TVITEM ();
+ tvItem.hItem = hItem;
+ tvItem.mask = OS.TVIF_STATE;
+ tvItem.stateMask = OS.TVIS_DROPHILITED;
+ tvItem.state = OS.TVIS_DROPHILITED;
+ OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
+ dropIndex = hItem;
+ }
+ if ((effect & DND.FEEDBACK_INSERT_BEFORE) != 0 || (effect & DND.FEEDBACK_INSERT_AFTER) != 0) {
+ boolean before = (effect & DND.FEEDBACK_INSERT_BEFORE) != 0;
+ /*
+ * Bug in Windows. When TVM_SETINSERTMARK is used to set
+ * an insert mark for a tree and an item is expanded or
+ * collapsed near the insert mark, the tree does not redraw
+ * the insert mark properly. The fix is to hide and show
+ * the insert mark whenever an item is expanded or collapsed.
+ * Since the insert mark can not be queried from the tree,
+ * use the Tree API rather than calling the OS directly.
+ */
+ TreeItem item = (TreeItem)tree.getDisplay().findWidget(tree.handle, hItem);
+ if (item != null) {
+ if (item != insertItem || before != insertBefore) {
+ tree.setInsertMark(item, before);
+ }
+ insertItem = item;
+ insertBefore = before;
+ } else {
+ if (insertItem != null) {
+ tree.setInsertMark(null, false);
+ }
+ insertItem = null;
+ }
+ } else {
+ if (insertItem != null) {
+ tree.setInsertMark(null, false);
+ }
+ insertItem = null;
+ }
+ }
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/URLTransfer.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/URLTransfer.java
new file mode 100644
index 000000000..1581e80a1
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/dnd/URLTransfer.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 20007 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * The class URLTransfer
provides a platform specific mechanism
+ * for converting text in URL format represented as a java String
+ * to a platform specific representation of the data and vice versa. The string
+ * must contain a fully specified url.
+ *
+ * String
containing a URL is shown below:
+ *
+ * @see Transfer
+ * @since 3.4
+ */
+public class URLTransfer extends ByteArrayTransfer {
+
+ static URLTransfer _instance = new URLTransfer();
+ static final String CFSTR_INETURLW = "UniformResourceLocatorW"; //$NON-NLS-1$
+ static final int CFSTR_INETURLIDW = registerType(CFSTR_INETURLW);
+ static final String CFSTR_INETURL = "UniformResourceLocator"; //$NON-NLS-1$
+ static final int CFSTR_INETURLID = registerType(CFSTR_INETURL);
+
+private URLTransfer() {}
+
+/**
+ * Returns the singleton instance of the URLTransfer class.
+ *
+ * @return the singleton instance of the URLTransfer class
+ */
+public static URLTransfer getInstance () {
+ return _instance;
+}
+
+/**
+ * This implementation of
+ * String url = "http://www.eclipse.org";
+ *
javaToNative
converts a URL
+ * represented by a java String
to a platform specific representation.
+ *
+ * @param object a java String
containing a URL
+ * @param transferData an empty TransferData
object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+@Override
+public void javaToNative (Object object, TransferData transferData){
+ if (!checkURL(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ transferData.result = COM.E_FAIL;
+ // URL is stored as a null terminated byte array
+ String url = ((String)object);
+ if (transferData.type == CFSTR_INETURLIDW) {
+ int charCount = url.length ();
+ char[] chars = new char[charCount+1];
+ url.getChars (0, charCount, chars, 0);
+ int byteCount = chars.length * 2;
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, byteCount);
+ OS.MoveMemory(newPtr, chars, byteCount);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = newPtr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ } else if (transferData.type == CFSTR_INETURLID) {
+ int count = url.length();
+ char[] chars = new char[count + 1];
+ url.getChars(0, count, chars, 0);
+ int codePage = OS.GetACP();
+ int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+ if (cchMultiByte == 0) {
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.DV_E_STGMEDIUM;
+ return;
+ }
+ long lpMultiByteStr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, cchMultiByte);
+ OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = lpMultiByteStr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ }
+}
+
+/**
+ * This implementation of nativeToJava
converts a platform
+ * specific representation of a URL to a java String
.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java String
containing a URL if the conversion was successful;
+ * otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+@Override
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ FORMATETC formatetc = transferData.formatetc;
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ long hMem = stgmedium.unionField;
+ try {
+ if (transferData.type == CFSTR_INETURLIDW) {
+ /* Ensure byteCount is a multiple of 2 bytes */
+ int size = OS.GlobalSize(hMem) / 2 * 2;
+ if (size == 0) return null;
+ char[] chars = new char[size/2];
+ long ptr = OS.GlobalLock(hMem);
+ if (ptr == 0) return null;
+ try {
+ OS.MoveMemory(chars, ptr, size);
+ int length = chars.length;
+ for (int i=0; i
+Package Specification
+This package contains the classes which make up the public API of the SWT
+Drag and Drop support.
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ArmEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ArmEvent.java
new file mode 100644
index 000000000..5c1650603
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ArmEvent.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.events;
+
+
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * Instances of this class are sent as a result of
+ * a widget such as a menu item being armed.
+ *
+ * @see ArmListener
+ * @see Sample code and further information
+ */
+
+public final class ArmEvent extends TypedEvent {
+
+ static final long serialVersionUID = 3258126964249212217L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public ArmEvent(Event e) {
+ super(e);
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ArmListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ArmListener.java
new file mode 100644
index 000000000..bd4a4d3a4
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ArmListener.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel addArmListener
method and removed using
+ * the removeArmListener
method. When the
+ * widget is armed, the widgetArmed method will be invoked.
+ * ControlListener
interface.
+ * ControlEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * Shell
s).
+ * The default behavior is to do nothing.
+ *
+ * @param e an event containing information about the move
+ */
+@Override
+public void controlMoved(ControlEvent e) {
+}
+
+/**
+ * Sent when the size (width, height) of a control changes.
+ * The default behavior is to do nothing.
+ *
+ * @param e an event containing information about the resize
+ */
+@Override
+public void controlResized(ControlEvent e) {
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ControlEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ControlEvent.java
new file mode 100644
index 000000000..3818e4dd5
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ControlEvent.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.events;
+
+
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * Instances of this class are sent as a result of
+ * controls being moved or resized.
+ *
+ * @see ControlListener
+ * @see Sample code and further information
+ */
+
+public final class ControlEvent extends TypedEvent {
+
+ static final long serialVersionUID = 3258132436155119161L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public ControlEvent(Event e) {
+ super(e);
+}
+
+}
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ControlListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ControlListener.java
new file mode 100644
index 000000000..d5fd210ec
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ControlListener.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.events;
+
+
+import java.util.function.*;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * Classes which implement this interface provide methods
+ * that deal with the events that are generated by moving
+ * and resizing controls.
+ * addControlListener
method and removed using
+ * the removeControlListener
method. When a
+ * control is moved or resized, the appropriate method will
+ * be invoked.
+ * Shell
s).
+ *
+ * @param e an event containing information about the move
+ */
+void controlMoved(ControlEvent e);
+
+/**
+ * Sent when the size (width, height) of a control changes.
+ *
+ * @param e an event containing information about the resize
+ */
+void controlResized(ControlEvent e);
+
+/**
+ * Static helper method to create a ControlListener
for the
+ * {@link #controlMoved(ControlEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return ControlListener
+ * @since 3.107
+ */
+static ControlListener controlMovedAdapter(ConsumerControlListener
for the
+ * {@link #controlResized(ControlEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return ControlListener
+ * @since 3.107
+ */
+static ControlListener controlResizedAdapter(ConsumeraddDisposeListener
method and removed using
+ * the removeDisposeListener
method. When a
+ * widget is disposed, the widgetDisposed method will
+ * be invoked.
+ * addDragDetectListener
method and removed using
+ * the removeDragDetectListener
method. When the
+ * drag is detected, the drageDetected method will be invoked.
+ * ExpandListener
interface.
+ * ExpandEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * ExpandItem
s being expanded or collapsed.
+ *
+ * @see ExpandListener
+ * @see Sample code and further information
+ *
+ * @since 3.2
+ */
+
+public class ExpandEvent extends SelectionEvent {
+
+ static final long serialVersionUID = 3976735856884987356L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public ExpandEvent(Event e) {
+ super(e);
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ExpandListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ExpandListener.java
new file mode 100644
index 000000000..3829a9f64
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ExpandListener.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.events;
+
+
+import java.util.function.*;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * Classes which implement this interface provide methods
+ * that deal with the expanding and collapsing of ExpandItem
s.
+ *
+ * ExpandBar
+ * control using the addExpandListener
method and
+ * removed using the removeExpandListener
method.
+ * When a item of the ExpandBar
is expanded or
+ * collapsed, the appropriate method will be invoked.
+ * ExpandListener
for the
+ * {@link #itemCollapsed(ExpandEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return ExpandListener
+ * @since 3.107
+ */
+static ExpandListener itemCollapsedAdapter(ConsumerExpandListener
for the
+ * {@link #itemExpanded(ExpandEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return ExpandListener
+ * @since 3.107
+ */
+static ExpandListener itemExpandedAdapter(ConsumerFocusListener
interface.
+ * FocusEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * addFocusListener
method and removed using
+ * the removeFocusListener
method. When a
+ * control gains or loses focus, the appropriate method
+ * will be invoked.
+ * FocusListener
for the
+ * {@link #focusGained(FocusEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return FocusListener
+ * @since 3.106
+ */
+static FocusListener focusGainedAdapter(ConsumerFocusListener
for the
+ * {@link #focusLost(FocusEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return FocusListener
+ * @since 3.106
+*/
+static FocusListener focusLostAdapter(Consumer
+ *
+ *
+ * This field determines the GestureEvent
fields that contain valid data.
+ */
+ public int detail;
+
+ /**
+ * The meaning of this field is dependent on the value of the detail
field
+ * and the platform. It can represent either the x coordinate of the centroid of the
+ * touches that make up the gesture, or the x coordinate of the cursor at the time the
+ * gesture was performed.
+ */
+ public int x;
+
+ /**
+ * The meaning of this field is dependent on the value of the detail
field
+ * and the platform. It can represent either the y coordinate of the centroid of the
+ * touches that make up the gesture, or the y coordinate of the cursor at the time the
+ * gesture was performed.
+ */
+ public int y;
+
+ /**
+ * This field is valid when the detail
field is set to GESTURE_ROTATE
.
+ * It specifies the number of degrees rotated on the device since the gesture started. Positive
+ * values indicate counter-clockwise rotation, and negative values indicate clockwise rotation.
+ */
+ public double rotation;
+
+ /**
+ * This field is valid when the detail
field is set to GESTURE_SWIPE
+ * or GESTURE_PAN
. Both xDirection
and yDirection
+ * can be valid for an individual gesture. The meaning of this field is dependent on the value
+ * of the detail
field.
+ * detail
is GESTURE_SWIPE
then a positive value indicates a swipe
+ * to the right and a negative value indicates a swipe to the left.
+ *
+ * If detail
is GESTURE_PAN
then a positive value indicates a pan to
+ * the right by this field's count of points and a negative value indicates a pan to the left
+ * by this field's count of points.
+ */
+ public int xDirection;
+
+ /**
+ * This field is valid when the detail
field is set to GESTURE_SWIPE
+ * or GESTURE_PAN
. Both xDirection
and yDirection
+ * can be valid for an individual gesture. The meaning of this field is dependent on the value
+ * of the detail
field.
+ *
+ * If detail
is GESTURE_SWIPE
then a positive value indicates a downward
+ * swipe and a negative value indicates an upward swipe.
+ *
+ * If detail
is GESTURE_PAN
then a positive value indicates a downward
+ * pan by this field's count of points and a negative value indicates an upward pan by this
+ * field's count of points.
+ */
+ public int yDirection;
+
+ /**
+ * This field is valid when the detail
field is set to GESTURE_MAGNIFY
.
+ * This is the scale factor to be applied. This value will be 1.0 in the first received event with
+ * GESTURE_MAGNIFY
, and will then fluctuate in subsequent events as the user moves
+ * their fingers.
+ */
+ public double magnification;
+
+ /**
+ * This flag indicates whether the operation should be allowed.
+ * Setting it to false
will cancel the operation.
+ */
+ public boolean doit;
+
+ static final long serialVersionUID = -8348741538373572182L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public GestureEvent(Event e) {
+ super(e);
+ this.stateMask = e.stateMask;
+ this.x = e.x;
+ this.y = e.y;
+ this.detail = e.detail;
+ this.rotation = e.rotation;
+ this.xDirection = e.xDirection;
+ this.yDirection = e.yDirection;
+ this.magnification = e.magnification;
+ this.doit = e.doit;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " stateMask=0x" + Integer.toHexString(stateMask)
+ + " detail=" + detail
+ + " x=" + x
+ + " y=" + y
+ + " rotation=" + rotation
+ + " xDirection=" + xDirection
+ + " yDirection=" + yDirection
+ + " magnification=" + magnification
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/GestureListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/GestureListener.java
new file mode 100644
index 000000000..7193e78ef
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/GestureListener.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel addGestureListener
method and removed using
+ * the removeGestureListener
method. When a
+ * gesture is triggered, the appropriate method will be invoked.
+ * addHelpListener
method and removed using
+ * the removeHelpListener
method. When help
+ * is requested for a control, the helpRequested method
+ * will be invoked.
+ * KeyListener
interface.
+ * KeyEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * SWT
.
+ * When the character field of the event is ambiguous, this field
+ * contains the unicode value of the original character. For example,
+ * typing Ctrl+M or Return both result in the character '\r' but the
+ * keyCode field will also contain '\r' when Return was typed.
+ *
+ * @see org.eclipse.swt.SWT
+ */
+ public int keyCode;
+
+ /**
+ * depending on the event, the location of key specified by the
+ * keyCode or character. The possible values for this field are
+ * SWT.LEFT
, SWT.RIGHT
, SWT.KEYPAD
,
+ * or SWT.NONE
representing the main keyboard area.
+ * false
will cancel the operation.
+ */
+ public boolean doit;
+
+ static final long serialVersionUID = 3256442491011412789L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public KeyEvent(Event e) {
+ super(e);
+ this.character = e.character;
+ this.keyCode = e.keyCode;
+ this.keyLocation = e.keyLocation;
+ this.stateMask = e.stateMask;
+ this.doit = e.doit;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " character='" + ((character == 0) ? "\\0" : String.valueOf(character)) + "'=0x" + Integer.toHexString(character)
+ + " keyCode=0x" + Integer.toHexString(keyCode)
+ + " keyLocation=0x" + Integer.toHexString(keyLocation)
+ + " stateMask=0x" + Integer.toHexString(stateMask)
+ + " doit=" + doit
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/KeyListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/KeyListener.java
new file mode 100644
index 000000000..8d55ef280
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/KeyListener.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel addKeyListener
method and removed using
+ * the removeKeyListener
method. When a
+ * key is pressed or released, the appropriate method will
+ * be invoked.
+ * KeyListener
for the
+ * {@link #keyPressed(KeyEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return KeyListener
+ * @since 3.106
+ */
+static KeyListener keyPressedAdapter(ConsumerKeyListener
for the
+ * {@link #keyReleased(KeyEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return KeyListener
+ * @since 3.106
+*/
+static KeyListener keyReleasedAdapter(ConsumerMenuListener
interface.
+ * MenuEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * false
will cancel the operation.
+ */
+ public boolean doit;
+
+ /**
+ * The context menu trigger type.
+ *
+ *
+ *
+ * A field indicating whether the context menu was triggered by a
+ * pointing device such as a mouse (indicated by MENU_MOUSE
),
+ * or by a focus-based device such as a keyboard (MENU_KEYBOARD
).
+ * If the trigger was MENU_KEYBOARD
, then the application should
+ * provide new display-relative x and y coordinates based on the current
+ * selection or the current focus.
+ *
+ * @since 3.8
+ */
+ public int detail;
+
+
+ private static final long serialVersionUID = -3061660596590828941L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public MenuDetectEvent(Event e) {
+ super(e);
+ this.x = e.x;
+ this.y = e.y;
+ this.doit = e.doit;
+ this.detail = e.detail;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " x=" + x
+ + " y=" + y
+ + " doit=" + doit
+ + " detail=" + detail
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/MenuDetectListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/MenuDetectListener.java
new file mode 100644
index 000000000..41d0f3f74
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/MenuDetectListener.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel addMenuDetectListener
method and
+ * removed using the removeMenuDetectListener
method.
+ * When the context menu trigger occurs, the
+ * menuDetected
method will be invoked.
+ * addMenuListener
method and removed using
+ * the removeMenuListener
method. When the
+ * menu is hidden or shown, the appropriate method will
+ * be invoked.
+ * MenuListener
for the
+ * {@link #menuHidden(MenuEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return MenuListener
+ * @since 3.107
+ */
+static MenuListener menuHiddenAdapter(ConsumerMenuListener
for the
+ * {@link #menuShown(MenuEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return MenuListener
+ * @since 3.107
+ */
+static MenuListener menuShownAdapter(ConsumeraddModifyListener
method and removed using
+ * the removeModifyListener
method. When the
+ * text is modified, the modifyText method will be invoked.
+ * MouseListener
interface.
+ * MouseEvent
s
+ * which occur as mouse buttons are pressed and released can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * button
field is an integer that
+ * represents the mouse button number. This is not the same
+ * as the SWT
mask constants BUTTONx
.
+ *
+ *
+ */
+ public int button;
+
+ /**
+ * the state of the keyboard modifier keys and mouse masks
+ * at the time the event was generated.
+ *
+ * @see org.eclipse.swt.SWT#MODIFIER_MASK
+ * @see org.eclipse.swt.SWT#BUTTON_MASK
+ */
+ public int stateMask;
+
+ /**
+ * the widget-relative, x coordinate of the pointer
+ * at the time the mouse button was pressed or released
+ */
+ public int x;
+
+ /**
+ * the widget-relative, y coordinate of the pointer
+ * at the time the mouse button was pressed or released
+ */
+ public int y;
+
+ /**
+ * the number times the mouse has been clicked, as defined
+ * by the operating system; 1 for the first click, 2 for the
+ * second click and so on.
+ *
+ * @since 3.3
+ */
+ public int count;
+
+ static final long serialVersionUID = 3257288037011566898L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public MouseEvent(Event e) {
+ super(e);
+ this.x = e.x;
+ this.y = e.y;
+ this.button = e.button;
+ this.stateMask = e.stateMask;
+ this.count = e.count;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " button=" + button
+ + " stateMask=0x" + Integer.toHexString(stateMask)
+ + " x=" + x
+ + " y=" + y
+ + " count=" + count
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/MouseListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/MouseListener.java
new file mode 100644
index 000000000..ec7c13d45
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/MouseListener.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel addMouseListener
method and removed using
+ * the removeMouseListener
method. When a
+ * mouse button is pressed or released, the appropriate method
+ * will be invoked.
+ * MouseListener
for the
+ * {@link #mouseDoubleClick(MouseEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return MouseListener
+ * @since 3.106
+ */
+
+static MouseListener mouseDoubleClickAdapter(ConsumerMouseListener
for the
+ * {@link #mouseDown(MouseEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return MouseListener
+ * @since 3.106
+ */
+
+static MouseListener mouseDownAdapter(ConsumerMouseListener
for the
+ * {@link #mouseUp(MouseEvent e)}) method with a lambda expression.
+ *
+ * @param c the consumer of the event
+ * @return MouseListener
+ * @since 3.106
+ */
+
+static MouseListener mouseUpAdapter(ConsumeraddMouseMoveListener
method and removed using
+ * the removeMouseMoveListener
method. As the
+ * mouse moves, the mouseMove method will be invoked.
+ * MouseTrackListener
interface.
+ * MouseEvent
s which
+ * occur as the mouse pointer passes (or hovers) over controls can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * addMouseTrackListener
method and removed using
+ * the removeMouseTrackListener
method. When the
+ * mouse pointer passes into or out of the area of the screen
+ * covered by a control or pauses while over a control, the
+ * appropriate method will be invoked.
+ * MouseTrackListener
for the
+ * {@link #mouseEnter(MouseEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return MouseTrackListener
+ * @since 3.107
+ */
+static MouseTrackListener mouseEnterAdapter(ConsumerMouseTrackListener
for the
+ * {@link #mouseExit(MouseEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return MouseTrackListener
+ * @since 3.107
+ */
+static MouseTrackListener mouseExitAdapter(ConsumerMouseTrackListener
for the
+ * {@link #mouseHover(MouseEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return MouseTrackListener
+ * @since 3.107
+ */
+static MouseTrackListener mouseHoverAdapter(ConsumeraddMouseWheelListener
method and removed using
+ * the removeMouseWheelListener
method. When the
+ * mouse wheel is scrolled the mouseScrolled
method
+ * will be invoked.
+ * addPaintListener
method and removed using
+ * the removePaintListener
method. When a
+ * paint event occurs, the paintControl method will be
+ * invoked.
+ *
+ *
+ * In addition, the first element may be set to zero and the last element may
+ * be set to the end of the line but this is not required.
+ *
+ * stored text = "R1R2R3" + "R4R5R6"
+ * R1 to R6 are right-to-left characters. The quotation marks
+ * are part of the text. The text is 13 characters long.
+ *
+ * segments = null:
+ * entire text content will be reordered and thus the two R2L segments
+ * swapped (as per the bidi algorithm).
+ * visual display (rendered on screen) = "R6R5R4" + "R3R2R1"
+ *
+ * segments = [0, 5, 8]
+ * "R1R2R3" will be reordered, followed by [blank]+[blank] and
+ * "R4R5R6".
+ * visual display = "R3R2R1" + "R6R5R4"
+ *
+ *
+ *
+ *
+ *
+ * @since 3.8
+ */
+
+public class SegmentEvent extends TypedEvent {
+
+ /**
+ * The start offset of the lineText
relative to text (always zero for single line widget)
+ */
+ public int lineOffset;
+
+ /**
+ * Text used to calculate the segments
+ */
+ public String lineText;
+
+ /**
+ * Text ranges that should be treated as separate segments (e.g. for bidi reordering)
+ */
+ public int[] segments;
+
+ /**
+ * Characters to be used in the segment boundaries (optional)
+ */
+ public char[] segmentsChars;
+
+ static final long serialVersionUID = -2414889726745247762L;
+
+ public SegmentEvent(Event e) {
+ super(e);
+ lineText = e.text;
+ lineOffset = e.detail;
+ }
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/SegmentListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/SegmentListener.java
new file mode 100644
index 000000000..37016ee94
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/SegmentListener.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016s IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel
+ *
+ *
+ * @param event the given event
+ * @see SegmentEvent
+ */
+void getSegments(SegmentEvent event);
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/SelectionAdapter.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/SelectionAdapter.java
new file mode 100644
index 000000000..12452bead
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/SelectionAdapter.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.events;
+
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the SelectionListener
interface.
+ * SelectionEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+ public int detail;
+
+ /**
+ * The x location of the selected area.
+ */
+ public int x;
+
+ /**
+ * The y location of selected area.
+ */
+ public int y;
+
+ /**
+ * The width of selected area.
+ */
+ public int width;
+
+ /**
+ * The height of selected area.
+ */
+ public int height;
+
+ /**
+ * The state of the keyboard modifier keys and mouse masks
+ * at the time the event was generated.
+ * false
will cancel the
+ * operation, depending on the widget.
+ */
+ public boolean doit;
+
+ static final long serialVersionUID = 3976735856884987953L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public SelectionEvent(Event e) {
+ super(e);
+ this.item = e.item;
+ this.x = e.x;
+ this.y = e.y;
+ this.width = e.width;
+ this.height = e.height;
+ this.detail = e.detail;
+ this.stateMask = e.stateMask;
+ this.text = e.text;
+ this.doit = e.doit;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " item=" + item
+ + " detail=" + detail
+ + " x=" + x
+ + " y=" + y
+ + " width=" + width
+ + " height=" + height
+ + " stateMask=0x" + Integer.toHexString(stateMask)
+ + " text=" + text
+ + " doit=" + doit
+ + "}";
+}
+}
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/SelectionListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/SelectionListener.java
new file mode 100644
index 000000000..44e0af963
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/SelectionListener.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel addSelectionListener
method and removed using
+ * the removeSelectionListener
method. When
+ * selection occurs in a control the appropriate method
+ * will be invoked.
+ * SelectionListener
for the
+ * {@link #widgetSelected(SelectionEvent e)}) method, given a lambda expression
+ * or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return SelectionListener
+ * @since 3.106
+ */
+static SelectionListener widgetSelectedAdapter(ConsumerSelectionListener
for the
+ * {@link #widgetDefaultSelected(SelectionEvent e)}) method, given a lambda expression
+ * or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return SelectionListener
+ * @since 3.106
+*/
+static SelectionListener widgetDefaultSelectedAdapter(ConsumerShellListener
interface.
+ * ShellEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * false
will cancel the operation.
+ */
+ public boolean doit;
+
+ static final long serialVersionUID = 3257569490479888441L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public ShellEvent(Event e) {
+ super(e);
+ this.doit = e.doit;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " doit=" + doit
+ + "}";
+}
+}
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ShellListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ShellListener.java
new file mode 100644
index 000000000..fc30f65ee
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/ShellListener.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.events;
+
+
+import java.util.function.*;
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * Classes which implement this interface provide methods
+ * that deal with changes in state of Shell
s.
+ * addShellListener
method and removed using
+ * the removeShellListener
method. When the
+ * state of the shell changes, the appropriate method will
+ * be invoked.
+ * ShellListener
for the
+ * {@link #shellActivated(ShellEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return ShellListener
+ * @since 3.107
+ */
+static ShellListener shellActivatedAdapter(ConsumerShellListener
for the
+ * {@link #shellClosed(ShellEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return ShellListener
+ * @since 3.107
+ */
+static ShellListener shellClosedAdapter(ConsumerShellListener
for the
+ * {@link #shellDeactivated(ShellEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return ShellListener
+ * @since 3.107
+ */
+static ShellListener shellDeactivatedAdapter(ConsumerShellListener
for the
+ * {@link #shellDeiconified(ShellEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return ShellListener
+ * @since 3.107
+ */
+static ShellListener shellDeiconifiedAdapter(ConsumerShellListener
for the
+ * {@link #shellIconified(ShellEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return ShellListener
+ * @since 3.107
+ */
+static ShellListener shellIconifiedAdapter(ConsumeraddTouchListener
method and removed using
+ * the removeTouchListener
method. When a
+ * touch occurs or changes state, the touch
method
+ * will be invoked.
+ * detail
and doit
.
+ * TRAVERSE_ARROW_NEXT
+ * and the doit field is false
, indicating that the system
+ * will not traverse to the next tab item and the arrow key will be
+ * delivered to the text control. If the same key is pressed in a radio
+ * button, the doit field will be true
, indicating that
+ * traversal is to proceed to the next tab item, possibly another radio
+ * button in the group and that the arrow key is not to be delivered
+ * to the radio button.
+ * TRAVERSE_TAB_NEXT
and the doit field will be
+ * false
. The default behavior of the system is to
+ * provide no traversal for canvas controls. This means that by
+ * default in a canvas, a key listener will see every key that the
+ * user types, including traversal keys. To understand why this
+ * is so, it is important to understand that only the widget implementor
+ * can decide which traversal is appropriate for the widget. Returning
+ * to the TRAVERSE_TAB_NEXT
example, a text widget implemented
+ * by a canvas would typically want to use the tab key to insert a
+ * tab character into the widget. A list widget implementation, on the
+ * other hand, would like the system default traversal behavior. Using
+ * only the doit flag, both implementations are possible. The text widget
+ * implementor sets doit to false
, ensuring that the system
+ * will not traverse and that the tab key will be delivered to key listeners.
+ * The list widget implementor sets doit to true
, indicating
+ * that the system should perform tab traversal and that the key should not
+ * be delivered to the list widget.
+ * TRAVERSE_RETURN
and the doit field
+ * is true
. This means that the return key will be processed
+ * by the default button, not the text widget. If the text widget has
+ * a default selection listener, it will not run because the return key
+ * will be processed by the default button. Imagine that the text control
+ * is being used as an in-place editor and return is used to dispose the
+ * widget. Setting doit to false
will stop the system from
+ * activating the default button but the key will be delivered to the text
+ * control, running the key and selection listeners for the text. How
+ * can TRAVERSE_RETURN
be implemented so that the default button
+ * will not be activated and the text widget will not see the return key?
+ * This is achieved by setting doit to true
, and the detail
+ * to TRAVERSE_NONE
.
+ *
+ *
+ *
+ * Setting this field will change the type of traversal.
+ * For example, setting the detail to TRAVERSE_NONE
+ * causes no traversal action to be taken.
+ *
+ * When used in conjunction with the doit
field, the
+ * traversal detail field can be useful when overriding the default
+ * traversal mechanism for a control. For example, setting the doit
+ * field to false
will cancel the operation and allow
+ * the traversal key stroke to be delivered to the control. Setting
+ * the doit field to true
indicates that the traversal
+ * described by the detail field is to be performed.
+ */
+ public int detail;
+
+ static final long serialVersionUID = 3257565105301239349L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public TraverseEvent(Event e) {
+ super(e);
+ this.detail = e.detail;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " detail=" + detail
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/TraverseListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/TraverseListener.java
new file mode 100644
index 000000000..14a51d788
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/events/TraverseListener.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel addTraverseListener
method and removed using
+ * the removeTraverseListener
method. When a
+ * traverse event occurs in a control, the keyTraversed method
+ * will be invoked.
+ * TRAVERSE_
are defined
+ * in the SWT
class.
+ * TreeListener
interface.
+ * TreeEvent
s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * addTreeListener
method and removed using
+ * the removeTreeListener
method. When a branch
+ * of the tree is expanded or collapsed, the appropriate method
+ * will be invoked.
+ * TreeListener
for the
+ * {@link #treeCollapsed(TreeEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return TreeListener
+ * @since 3.107
+ */
+static TreeListener treeCollapsedAdapter(ConsumerTreeListener
for the
+ * {@link #treeExpanded(TreeEvent e)}) method, given a lambda expression or a method reference.
+ *
+ * @param c the consumer of the event
+ * @return TreeListener
+ * @since 3.107
+ */
+static TreeListener treeExpandedAdapter(ConsumeraddVerifyListener
method and removed using
+ * the removeVerifyListener
method. When the
+ * text is about to be modified, the verifyText method
+ * will be invoked.
+ *
+Package Specification
+This package provides the typed events and listener interfaces and,
+where appropriate, matching adapter classes which make up the
+"high level" typed listener support provided by SWT.
+org.eclipse.swt.widgets.Event
and interface
+org.eclipse.swt.widgets.Listener
, and the
+addListener
and removeListener
methods in
+class org.eclipse.swt.widgets.Widget
.
+RGB
or RGBA
.
+ * Color.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ *
+ *
+ *
+ * @see #dispose
+ */
+public Color (Device device, int red, int green, int blue) {
+ super(device);
+ init(red, green, blue, 255);
+ init();
+}
+
+/**
+ * Constructs a new instance of this class given a device and the
+ * desired red, green, blue & alpha values expressed as ints in the range
+ * 0 to 255 (where 0 is black and 255 is full brightness). On limited
+ * color devices, the color instance created by this call may not have
+ * the same RGB values as the ones specified by the arguments. The
+ * RGB values on the returned instance will be the color values of
+ * the operating system color.
+ *
+ *
+ *
+ * @see #dispose
+ * @since 3.104
+ */
+public Color (Device device, int red, int green, int blue, int alpha) {
+ super(device);
+ init(red, green, blue, alpha);
+ init();
+}
+
+/**
+ * Constructs a new instance of this class given a device and an
+ * RGB
describing the desired red, green and blue values.
+ * On limited color devices, the color instance created by this call
+ * may not have the same RGB values as the ones specified by the
+ * argument. The RGB values on the returned instance will be the color
+ * values of the operating system color.
+ *
+ *
+ *
+ * @see #dispose
+ */
+public Color (Device device, RGB rgb) {
+ super(device);
+ if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(rgb.red, rgb.green, rgb.blue, 255);
+ init();
+}
+
+/**
+ * Constructs a new instance of this class given a device and an
+ * RGBA
describing the desired red, green, blue & alpha values.
+ * On limited color devices, the color instance created by this call
+ * may not have the same RGBA values as the ones specified by the
+ * argument. The RGBA values on the returned instance will be the color
+ * values of the operating system color + alpha.
+ *
+ *
+ *
+ * @see #dispose
+ * @since 3.104
+ */
+public Color(Device device, RGBA rgba) {
+ super(device);
+ if (rgba == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(rgba.rgb.red, rgba.rgb.green, rgba.rgb.blue, rgba.alpha);
+ init();
+}
+
+/**
+ * Constructs a new instance of this class given a device, an
+ * RGB
describing the desired red, green and blue values,
+ * alpha specifying the level of transparency.
+ * On limited color devices, the color instance created by this call
+ * may not have the same RGB values as the ones specified by the
+ * argument. The RGB values on the returned instance will be the color
+ * values of the operating system color.
+ *
+ *
+ *
+ * @see #dispose
+ * @since 3.104
+ */
+public Color(Device device, RGB rgb, int alpha) {
+ super(device);
+ if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(rgb.red, rgb.green, rgb.blue, alpha);
+ init();
+}
+
+@Override
+void destroy() {
+ handle = -1;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the same object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Color)) return false;
+ Color color = (Color) object;
+ return device == color.device && (handle & 0xFFFFFF) == (color.handle & 0xFFFFFF) && (alpha == color.alpha);
+}
+
+/**
+ * Returns the amount of alpha in the color, from 0 (transparent) to 255 (opaque).
+ *
+ * @return the alpha component of the color
+ *
+ * @exception SWTException
+ *
+ * @since 3.104
+ */
+public int getAlpha () {
+ return this.alpha;
+}
+
+/**
+ * Returns the amount of blue in the color, from 0 to 255.
+ *
+ * @return the blue component of the color
+ *
+ * @exception SWTException
+ *
+ */
+public int getBlue () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return (handle & 0xFF0000) >> 16;
+}
+
+/**
+ * Returns the amount of green in the color, from 0 to 255.
+ *
+ * @return the green component of the color
+ *
+ * @exception SWTException
+ *
+ */
+public int getGreen () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return (handle & 0xFF00) >> 8 ;
+}
+
+/**
+ * Returns the amount of red in the color, from 0 to 255.
+ *
+ * @return the red component of the color
+ *
+ * @exception SWTException
+ *
+ */
+public int getRed () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return handle & 0xFF;
+}
+
+/**
+ * Returns an RGB
representing the receiver.
+ *
+ * @return the RGB for the color
+ *
+ * @exception SWTException
+ *
+ */
+public RGB getRGB () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return new RGB(handle & 0xFF, (handle & 0xFF00) >> 8, (handle & 0xFF0000) >> 16);
+}
+
+/**
+ * Returns an RGBA
representing the receiver.
+ *
+ * @return the RGBA for the color
+ *
+ * @exception SWTException
+ *
+ * @since 3.104
+ */
+public RGBA getRGBA () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return new RGBA(handle & 0xFF, (handle & 0xFF00) >> 8, (handle & 0xFF0000) >> 16, alpha);
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+@Override
+public int hashCode () {
+ return handle ^ alpha;
+}
+
+/**
+ * Allocates the operating system resources associated
+ * with the receiver.
+ *
+ * @param device the device on which to allocate the color
+ * @param red the amount of red in the color
+ * @param green the amount of green in the color
+ * @param blue the amount of blue in the color
+ * @param alpha the amount of alpha in the color. Currently, SWT only honors extreme values for alpha i.e. 0 (transparent) or 255 (opaque).
+ *
+ * @exception IllegalArgumentException
+ *
+ *
+ * @see #dispose
+ */
+void init(int red, int green, int blue, int alpha) {
+ if (red > 255 || red < 0 || green > 255 || green < 0 || blue > 255 || blue < 0 || alpha > 255 || alpha < 0) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ handle = (red & 0xFF) | ((green & 0xFF) << 8) | ((blue & 0xFF) << 16);
+ this.alpha = alpha;
+}
+
+/**
+ * Returns true
if the color has been disposed,
+ * and false
otherwise.
+ * true
when the color is disposed and false
otherwise
+ */
+@Override
+public boolean isDisposed() {
+ return handle == -1;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+@Override
+public String toString () {
+ if (isDisposed()) return "Color {*DISPOSED*}"; //$NON-NLS-1$
+ return "Color {" + getRed() + ", " + getGreen() + ", " + getBlue() + ", " + getAlpha() + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new color.
+ * Color
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * Color
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * Cursor.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ *
+ *
+ *
+ *
+ * @exception SWTError
+ *
+ *
+ * @see SWT#CURSOR_ARROW
+ * @see SWT#CURSOR_WAIT
+ * @see SWT#CURSOR_CROSS
+ * @see SWT#CURSOR_APPSTARTING
+ * @see SWT#CURSOR_HELP
+ * @see SWT#CURSOR_SIZEALL
+ * @see SWT#CURSOR_SIZENESW
+ * @see SWT#CURSOR_SIZENS
+ * @see SWT#CURSOR_SIZENWSE
+ * @see SWT#CURSOR_SIZEWE
+ * @see SWT#CURSOR_SIZEN
+ * @see SWT#CURSOR_SIZES
+ * @see SWT#CURSOR_SIZEE
+ * @see SWT#CURSOR_SIZEW
+ * @see SWT#CURSOR_SIZENE
+ * @see SWT#CURSOR_SIZESE
+ * @see SWT#CURSOR_SIZESW
+ * @see SWT#CURSOR_SIZENW
+ * @see SWT#CURSOR_UPARROW
+ * @see SWT#CURSOR_IBEAM
+ * @see SWT#CURSOR_NO
+ * @see SWT#CURSOR_HAND
+ * @see #dispose()
+ */
+public Cursor(Device device, int style) {
+ super(device);
+ long lpCursorName = 0;
+ switch (style) {
+ case SWT.CURSOR_HAND: lpCursorName = OS.IDC_HAND; break;
+ case SWT.CURSOR_ARROW: lpCursorName = OS.IDC_ARROW; break;
+ case SWT.CURSOR_WAIT: lpCursorName = OS.IDC_WAIT; break;
+ case SWT.CURSOR_CROSS: lpCursorName = OS.IDC_CROSS; break;
+ case SWT.CURSOR_APPSTARTING: lpCursorName = OS.IDC_APPSTARTING; break;
+ case SWT.CURSOR_HELP: lpCursorName = OS.IDC_HELP; break;
+ case SWT.CURSOR_SIZEALL: lpCursorName = OS.IDC_SIZEALL; break;
+ case SWT.CURSOR_SIZENESW: lpCursorName = OS.IDC_SIZENESW; break;
+ case SWT.CURSOR_SIZENS: lpCursorName = OS.IDC_SIZENS; break;
+ case SWT.CURSOR_SIZENWSE: lpCursorName = OS.IDC_SIZENWSE; break;
+ case SWT.CURSOR_SIZEWE: lpCursorName = OS.IDC_SIZEWE; break;
+ case SWT.CURSOR_SIZEN: lpCursorName = OS.IDC_SIZENS; break;
+ case SWT.CURSOR_SIZES: lpCursorName = OS.IDC_SIZENS; break;
+ case SWT.CURSOR_SIZEE: lpCursorName = OS.IDC_SIZEWE; break;
+ case SWT.CURSOR_SIZEW: lpCursorName = OS.IDC_SIZEWE; break;
+ case SWT.CURSOR_SIZENE: lpCursorName = OS.IDC_SIZENESW; break;
+ case SWT.CURSOR_SIZESE: lpCursorName = OS.IDC_SIZENWSE; break;
+ case SWT.CURSOR_SIZESW: lpCursorName = OS.IDC_SIZENESW; break;
+ case SWT.CURSOR_SIZENW: lpCursorName = OS.IDC_SIZENWSE; break;
+ case SWT.CURSOR_UPARROW: lpCursorName = OS.IDC_UPARROW; break;
+ case SWT.CURSOR_IBEAM: lpCursorName = OS.IDC_IBEAM; break;
+ case SWT.CURSOR_NO: lpCursorName = OS.IDC_NO; break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ handle = OS.LoadCursor(0, lpCursorName);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+}
+
+/**
+ * Constructs a new cursor given a device, image and mask
+ * data describing the desired cursor appearance, and the x
+ * and y coordinates of the hotspot (that is, the point
+ * within the area covered by the cursor which is considered
+ * to be where the on-screen pointer is "pointing").
+ *
+ *
+ * @exception SWTError
+ *
+ *
+ * @see #dispose()
+ */
+public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
+ super(device);
+ if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (mask == null) {
+ if (source.getTransparencyType() != SWT.TRANSPARENCY_MASK) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ mask = source.getTransparencyMask();
+ }
+ /* Check the bounds. Mask must be the same size as source */
+ if (mask.width != source.width || mask.height != source.height) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ /* Check the hotspots */
+ if (hotspotX >= source.width || hotspotX < 0 ||
+ hotspotY >= source.height || hotspotY < 0) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ /* Convert depth to 1 */
+ mask = ImageData.convertMask(mask);
+ source = ImageData.convertMask(source);
+
+ /* Make sure source and mask scanline pad is 2 */
+ byte[] sourceData = ImageData.convertPad(source.data, source.width, source.height, source.depth, source.scanlinePad, 2);
+ byte[] maskData = ImageData.convertPad(mask.data, mask.width, mask.height, mask.depth, mask.scanlinePad, 2);
+
+ /* Create the cursor */
+ long hInst = OS.GetModuleHandle(null);
+ handle = OS.CreateCursor(hInst, hotspotX, hotspotY, source.width, source.height, sourceData, maskData);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+}
+
+/**
+ * Constructs a new cursor given a device, image data describing
+ * the desired cursor appearance, and the x and y coordinates of
+ * the hotspot (that is, the point within the area
+ * covered by the cursor which is considered to be where the
+ * on-screen pointer is "pointing").
+ *
+ *
+ * @exception SWTError
+ *
+ *
+ * @see #dispose()
+ *
+ * @since 3.0
+ */
+public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
+ super(device);
+ if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ /* Check the hotspots */
+ if (hotspotX >= source.width || hotspotX < 0 ||
+ hotspotY >= source.height || hotspotY < 0) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ long hBitmap = 0;
+ long hMask = 0;
+ if (source.maskData == null && source.transparentPixel == -1 && (source.alpha != -1 || source.alphaData != null)) {
+ PaletteData palette = source.palette;
+ PaletteData newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ ImageData img = new ImageData(source.width, source.height, 32, newPalette);
+ if (palette.isDirect) {
+ ImageData.blit(ImageData.BLIT_SRC,
+ source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, palette.redMask, palette.greenMask, palette.blueMask,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ img.data, img.depth, img.bytesPerLine, img.getByteOrder(), 0, 0, img.width, img.height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask,
+ false, false);
+ } else {
+ RGB[] rgbs = palette.getRGBs();
+ int length = rgbs.length;
+ byte[] srcReds = new byte[length];
+ byte[] srcGreens = new byte[length];
+ byte[] srcBlues = new byte[length];
+ for (int i = 0; i < rgbs.length; i++) {
+ RGB rgb = rgbs[i];
+ if (rgb == null) continue;
+ srcReds[i] = (byte)rgb.red;
+ srcGreens[i] = (byte)rgb.green;
+ srcBlues[i] = (byte)rgb.blue;
+ }
+ ImageData.blit(ImageData.BLIT_SRC,
+ source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, srcReds, srcGreens, srcBlues,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ img.data, img.depth, img.bytesPerLine, img.getByteOrder(), 0, 0, img.width, img.height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask,
+ false, false);
+ }
+ hBitmap = Image.createDIB(source.width, source.height, 32);
+ if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ BITMAP dibBM = new BITMAP();
+ OS.GetObject(hBitmap, BITMAP.sizeof, dibBM);
+ byte[] srcData = img.data;
+ if (source.alpha != -1) {
+ for (int i = 3; i < srcData.length; i+=4) {
+ srcData[i] = (byte)source.alpha;
+ }
+ } else if (source.alphaData != null) {
+ for (int sp = 3, ap=0; sp < srcData.length; sp+=4, ap++) {
+ srcData[sp] = source.alphaData[ap];
+ }
+ }
+ OS.MoveMemory(dibBM.bmBits, srcData, srcData.length);
+ hMask = OS.CreateBitmap(source.width, source.height, 1, 1, new byte[(((source.width + 7) / 8) + 3) / 4 * 4 * source.height]);
+ if (hMask == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ } else {
+ ImageData mask = source.getTransparencyMask();
+ long [] result = Image.init(this.device, null, source, mask);
+ hBitmap = result[0];
+ hMask = result[1];
+ }
+ /* Create the icon */
+ ICONINFO info = new ICONINFO();
+ info.fIcon = false;
+ info.hbmColor = hBitmap;
+ info.hbmMask = hMask;
+ info.xHotspot = hotspotX;
+ info.yHotspot = hotspotY;
+ handle = OS.CreateIconIndirect(info);
+ OS.DeleteObject(hBitmap);
+ OS.DeleteObject(hMask);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ isIcon = true;
+ init();
+}
+
+@Override
+void destroy () {
+ /*
+ * It is an error in Windows to destroy the current
+ * cursor. Check that the cursor that is about to
+ * be destroyed is the current cursor. If so, set
+ * the current cursor to be IDC_ARROW. Note that
+ * Windows shares predefined cursors so the call to
+ * LoadCursor() does not leak.
+ */
+ // TEMPORARY CODE
+// if (OS.GetCursor() == handle) {
+// OS.SetCursor(OS.LoadCursor(0, OS.IDC_ARROW));
+// }
+
+ if (isIcon) {
+ OS.DestroyIcon(handle);
+ } else {
+ /*
+ * The MSDN states that one should not destroy a shared
+ * cursor, that is, one obtained from LoadCursor.
+ * However, it does not appear to do any harm, so rather
+ * than keep track of how a cursor was created, we just
+ * destroy them all. If this causes problems in the future,
+ * put the flag back in.
+ */
+ OS.DestroyCursor(handle);
+ }
+ handle = 0;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the same object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Cursor)) return false;
+ Cursor cursor = (Cursor) object;
+ return device == cursor.device && handle == cursor.handle;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+@Override
+public int hashCode () {
+ return (int)handle;
+}
+
+/**
+ * Returns true
if the cursor has been disposed,
+ * and false
otherwise.
+ * true
when the cursor is disposed and false
otherwise
+ */
+@Override
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+@Override
+public String toString () {
+ if (isDisposed()) return "Cursor {*DISPOSED*}";
+ return "Cursor {" + handle + "}";
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new cursor.
+ * Cursor
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * isDisposed()
and dispose()
) on a
+ * device that has had its dispose()
method called.
+ *
+ *
+ */
+protected void checkDevice () {
+ if (disposed) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
+}
+
+void checkGDIP() {
+ if (gdipToken != null) return;
+ long [] token = new long [1];
+ GdiplusStartupInput input = new GdiplusStartupInput ();
+ input.GdiplusVersion = 1;
+ if (Gdip.GdiplusStartup (token, input, 0) != 0) SWT.error (SWT.ERROR_NO_HANDLES);
+ gdipToken = token;
+ if (loadedFonts != null) {
+ fontCollection = Gdip.PrivateFontCollection_new();
+ if (fontCollection == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ for (int i = 0; i < loadedFonts.length; i++) {
+ String path = loadedFonts[i];
+ if (path == null) break;
+ int length = path.length();
+ char [] buffer = new char [length + 1];
+ path.getChars(0, length, buffer, 0);
+ Gdip.PrivateFontCollection_AddFontFile(fontCollection, buffer);
+ }
+ loadedFonts = null;
+ }
+}
+
+/**
+ * Creates the device in the operating system. If the device
+ * does not have a handle, this method may do nothing depending
+ * on the device.
+ * init
.
+ * super
implementation.
+ * release
.
+ * super
implementation.
+ * true
when sent the message
+ * isDisposed()
.
+ *
+ * @see #release
+ * @see #destroy
+ * @see #checkDevice
+ */
+public void dispose () {
+ synchronized (Device.class) {
+ if (isDisposed()) return;
+ checkDevice ();
+ release ();
+ destroy ();
+ disposed = true;
+ if (tracking) {
+ synchronized (trackingLock) {
+ printErrors ();
+ objects = null;
+ errors = null;
+ trackingLock = null;
+ }
+ }
+ }
+}
+
+void dispose_Object (Object object) {
+ synchronized (trackingLock) {
+ for (int i=0; i
+ *
+ */
+public Rectangle getBounds() {
+ checkDevice ();
+ return DPIUtil.autoScaleDown(getBoundsInPixels());
+}
+
+private Rectangle getBoundsInPixels () {
+ long hDC = internal_new_GC (null);
+ int width = OS.GetDeviceCaps (hDC, OS.HORZRES);
+ int height = OS.GetDeviceCaps (hDC, OS.VERTRES);
+ internal_dispose_GC (hDC, null);
+ return new Rectangle (0, 0, width, height);
+}
+
+/**
+ * Returns a DeviceData
based on the receiver.
+ * Modifications made to this DeviceData
will not
+ * affect the receiver.
+ *
+ * @return a DeviceData
containing the device's data and attributes
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DeviceData
+ */
+public DeviceData getDeviceData () {
+ checkDevice();
+ DeviceData data = new DeviceData ();
+ data.debug = debug;
+ data.tracking = tracking;
+ if (tracking) {
+ synchronized (trackingLock) {
+ int count = 0, length = objects.length;
+ for (int i=0; i
+ *
+ */
+public int getDepth () {
+ checkDevice ();
+ long hDC = internal_new_GC (null);
+ int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
+ int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
+ internal_dispose_GC (hDC, null);
+ return bits * planes;
+}
+
+/**
+ * Returns a point whose x coordinate is the logical horizontal
+ * dots per inch of the display, and whose y coordinate
+ * is the logical vertical dots per inch of the display.
+ *
+ * @return the horizontal and vertical DPI
+ *
+ * @exception SWTException
+ *
+ */
+public Point getDPI () {
+ checkDevice ();
+ long hDC = internal_new_GC (null);
+ int dpiX = OS.GetDeviceCaps (hDC, OS.LOGPIXELSX);
+ int dpiY = OS.GetDeviceCaps (hDC, OS.LOGPIXELSY);
+ internal_dispose_GC (hDC, null);
+ return DPIUtil.autoScaleDown(new Point (dpiX, dpiY));
+}
+
+/**
+ * Returns DPI in x direction. In the modern monitors DPI for
+ * X and Y directions is same.
+ *
+ * @return the horizontal DPI
+ */
+int _getDPIx () {
+ long hDC = internal_new_GC (null);
+ int dpi = OS.GetDeviceCaps (hDC, OS.LOGPIXELSX);
+ internal_dispose_GC (hDC, null);
+ return dpi;
+}
+/**
+ * Returns FontData
objects which describe
+ * the fonts that match the given arguments. If the
+ * faceName
is null, all fonts will be returned.
+ *
+ * @param faceName the name of the font to look for, or null
+ * @param scalable if true only scalable fonts are returned, otherwise only non-scalable fonts are returned.
+ * @return the matching font data
+ *
+ * @exception SWTException
+ *
+ */
+public FontData [] getFontList (String faceName, boolean scalable) {
+ checkDevice ();
+
+ /* Create the callback */
+ Callback callback = new Callback (this, "EnumFontFamProc", 4); //$NON-NLS-1$
+ long lpEnumFontFamProc = callback.getAddress ();
+ if (lpEnumFontFamProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+ /* Initialize the instance variables */
+ metrics = new TEXTMETRIC ();
+ pixels = new int[nFonts];
+ logFonts = new LOGFONT [nFonts];
+ for (int i=0; i
+ *
+ *
+ * @see SWT
+ */
+public Color getSystemColor (int id) {
+ checkDevice ();
+ int pixel = 0x00000000;
+ int alpha = 255;
+ switch (id) {
+ case SWT.COLOR_TRANSPARENT: alpha = 0;
+ case SWT.COLOR_WHITE: pixel = 0x00FFFFFF; break;
+ case SWT.COLOR_BLACK: pixel = 0x00000000; break;
+ case SWT.COLOR_RED: pixel = 0x000000FF; break;
+ case SWT.COLOR_DARK_RED: pixel = 0x00000080; break;
+ case SWT.COLOR_GREEN: pixel = 0x0000FF00; break;
+ case SWT.COLOR_DARK_GREEN: pixel = 0x00008000; break;
+ case SWT.COLOR_YELLOW: pixel = 0x0000FFFF; break;
+ case SWT.COLOR_DARK_YELLOW: pixel = 0x00008080; break;
+ case SWT.COLOR_BLUE: pixel = 0x00FF0000; break;
+ case SWT.COLOR_DARK_BLUE: pixel = 0x00800000; break;
+ case SWT.COLOR_MAGENTA: pixel = 0x00FF00FF; break;
+ case SWT.COLOR_DARK_MAGENTA: pixel = 0x00800080; break;
+ case SWT.COLOR_CYAN: pixel = 0x00FFFF00; break;
+ case SWT.COLOR_DARK_CYAN: pixel = 0x00808000; break;
+ case SWT.COLOR_GRAY: pixel = 0x00C0C0C0; break;
+ case SWT.COLOR_DARK_GRAY: pixel = 0x00808080; break;
+ }
+ return Color.win32_new (this, pixel, alpha);
+}
+
+/**
+ * Returns a reasonable font for applications to use.
+ * On some platforms, this will match the "default font"
+ * or "system font" if such can be found. This font
+ * should not be freed because it was allocated by the
+ * system, not the application.
+ *
+ *
+ */
+public Font getSystemFont () {
+ checkDevice ();
+ long hFont = OS.GetStockObject (OS.SYSTEM_FONT);
+ return Font.win32_new (this, hFont);
+}
+
+/**
+ * Returns true
if the underlying window system prints out
+ * warning messages on the console, and setWarnings
+ * had previously been called with true
.
+ *
+ * @return true
if warnings are being handled, and false
otherwise
+ *
+ * @exception SWTException
+ *
+ */
+public boolean getWarnings () {
+ checkDevice ();
+ return false;
+}
+
+/**
+ * Initializes any internal resources needed by the
+ * device.
+ * create
.
+ * super
implementation.
+ * Device
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * Device
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * true
if the device has been disposed,
+ * and false
otherwise.
+ * true
when the device is disposed and false
otherwise
+ */
+public boolean isDisposed () {
+ synchronized (Device.class) {
+ return disposed;
+ }
+}
+
+/**
+ * Loads the font specified by a file. The font will be
+ * present in the list of fonts available to the application.
+ *
+ * @param path the font file path
+ * @return whether the font was successfully loaded
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Font
+ *
+ * @since 3.3
+ */
+public boolean loadFont (String path) {
+ checkDevice();
+ if (path == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ TCHAR lpszFilename = new TCHAR (0, path, true);
+ boolean loaded = OS.AddFontResourceEx (lpszFilename, OS.FR_PRIVATE, 0) != 0;
+ if (loaded) {
+ if (gdipToken != null) {
+ if (fontCollection == 0) {
+ fontCollection = Gdip.PrivateFontCollection_new();
+ if (fontCollection == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+ int length = path.length();
+ char [] buffer = new char [length + 1];
+ path.getChars(0, length, buffer, 0);
+ Gdip.PrivateFontCollection_AddFontFile(fontCollection, buffer);
+ } else {
+ addFont(path);
+ }
+ }
+ return loaded;
+}
+
+void new_Object (Object object) {
+ synchronized (trackingLock) {
+ for (int i=0; irelease
. Also,to assist the garbage
+ * collector and minimize the amount of memory that is not
+ * reclaimed when the programmer keeps a reference to a
+ * disposed device, all fields except the handle are zero'd.
+ * The handle is needed by destroy
.
+ *
destroy
.
+ *
+ * If subclasses reimplement this method, they must
+ * call the super
implementation.
+ *
false
prevents these
+ * messages from being printed. If the argument is true
then
+ * message printing is not blocked.
+ *
+ * @param warnings true
if warnings should be printed, and false
otherwise
+ *
+ * @exception SWTException Drawable
can have a graphics context (GC)
+ * created for them, and then they can be drawn on by sending messages to
+ * their associated GC. SWT images, and device objects such as the Display
+ * device and the Printer device, are drawables.
+ * + * IMPORTANT: This interface is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It should never be + * referenced from application code. + *
+ * + * @see Device + * @see Image + * @see GC + */ +public interface Drawable { + +/** + * Invokes platform specific functionality to allocate a new GC handle. + *
+ * IMPORTANT: This method is not part of the public
+ * API for Drawable
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for Drawable
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
true
iff coordinates can be auto-scaled on this
+ * drawable and false
if not. E.g. a {@link GC} method should not
+ * auto-scale the bounds of a figure drawn on a Printer device, but it may have
+ * to auto-scale when drawing on a high-DPI Display monitor.
+ *
+ * @return true
if auto-scaling is enabled for this drawable
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ */
+default boolean isAutoScalable () {
+ return true;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Font.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Font.java
new file mode 100644
index 000000000..1223d1621
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Font.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class manage operating system resources that
+ * define how text looks when it is displayed. Fonts may be constructed
+ * by providing a device and either name, size and style information
+ * or a FontData
object which encapsulates this data.
+ *
+ * Application code must explicitly invoke the Font.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ *
+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public long handle; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Font(Device device) { + super(device); +} + +/** + * Constructs a new font given a device and font data + * which describes the desired font's appearance. + *+ * You must dispose the font when it is no longer required. + *
+ * + * @param device the device to create the font on + * @param fd the FontData that describes the desired font (must not be null) + * + * @exception IllegalArgumentException+ * You must dispose the font when it is no longer required. + *
+ * + * @param device the device to create the font on + * @param fds the array of FontData that describes the desired font (must not be null) + * + * @exception IllegalArgumentExceptiontrue
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode
+ */
+@Override
+public boolean equals(Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Font)) return false;
+ Font font = (Font) object;
+ return device == font.device && handle == font.handle;
+}
+
+/**
+ * Returns an array of FontData
s representing the receiver.
+ * On Windows, only one FontData will be returned per font. On X however,
+ * a Font
object may be composed of multiple X
+ * fonts. To support this case, we return an array of font data objects.
+ *
+ * @return an array of font data objects describing the receiver
+ *
+ * @exception SWTException true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+@Override
+public int hashCode () {
+ return (int)handle;
+}
+
+void init (FontData fd) {
+ if (fd == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ LOGFONT logFont = fd.data;
+ int lfHeight = logFont.lfHeight;
+ logFont.lfHeight = device.computePixels(fd.height);
+ handle = OS.CreateFontIndirect(logFont);
+ logFont.lfHeight = lfHeight;
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+}
+
+/**
+ * Returns true
if the font has been disposed,
+ * and false
otherwise.
+ *
+ * This method gets the dispose state for the font.
+ * When a font has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the font.
+ *
+ * @return true
when the font is disposed and false
otherwise
+ */
+@Override
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+@Override
+public String toString () {
+ if (isDisposed()) return "Font {*DISPOSED*}";
+ return "Font {" + handle + "}";
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new font.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for Font
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ * For platform-independent behaviour, use the get and set methods + * corresponding to the following properties: + *
FontData
+ * corresponds to a Windows LOGFONT
structure whose fields
+ * may be retrieved and modified.FontData
correspond
+ * to the entries in the font's XLFD name and may be retrieved and modified.
+ * dispose()
method is provided.
+ *
+ * @see Font
+ * @see Sample code and further information
+ */
+public final class FontData {
+
+ /**
+ * A Win32 LOGFONT struct
+ * (Warning: This field is platform dependent)
+ * + * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public LOGFONT data; + + /** + * The height of the font data in points + * (Warning: This field is platform dependent) + *+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public float height; + + /** + * The locales of the font + */ + String lang, country, variant; + +/** + * Constructs a new uninitialized font data. + */ +public FontData() { + data = new LOGFONT (); + // We set the charset field so that + // wildcard searching will work properly + // out of the box + data.lfCharSet = (byte)OS.DEFAULT_CHARSET; + height = 12; +} + +/** + * Constructs a new font data given the WindowsLOGFONT
+ * that it should represent.
+ *
+ * @param data the LOGFONT
for the result
+ */
+FontData(LOGFONT data, float height) {
+ this.data = data;
+ this.height = height;
+}
+
+/**
+ * Constructs a new FontData given a string representation
+ * in the form generated by the FontData.toString
+ * method.
+ * + * Note that the representation varies between platforms, + * and a FontData can only be created from a string that was + * generated on the same platform. + *
+ * + * @param string the string representation of aFontData
(must not be null)
+ *
+ * @exception IllegalArgumentException true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof FontData)) return false;
+ FontData fd = (FontData)object;
+ LOGFONT lf = fd.data;
+ return data.lfCharSet == lf.lfCharSet &&
+ /*
+ * This code is intentionally commented. When creating
+ * a FontData, lfHeight is not necessarily set. Instead
+ * we check the height field which is always set.
+ */
+// data.lfHeight == lf.lfHeight &&
+ height == fd.height &&
+ data.lfWidth == lf.lfWidth &&
+ data.lfEscapement == lf.lfEscapement &&
+ data.lfOrientation == lf.lfOrientation &&
+ data.lfWeight == lf.lfWeight &&
+ data.lfItalic == lf.lfItalic &&
+ data.lfUnderline == lf.lfUnderline &&
+ data.lfStrikeOut == lf.lfStrikeOut &&
+ data.lfCharSet == lf.lfCharSet &&
+ data.lfOutPrecision == lf.lfOutPrecision &&
+ data.lfClipPrecision == lf.lfClipPrecision &&
+ data.lfQuality == lf.lfQuality &&
+ data.lfPitchAndFamily == lf.lfPitchAndFamily &&
+ getName().equals(fd.getName());
+}
+
+long EnumLocalesProc(long lpLocaleString) {
+
+ /* Get the locale ID */
+ int length = 8;
+ TCHAR buffer = new TCHAR(0, length);
+ int byteCount = length * TCHAR.sizeof;
+ OS.MoveMemory(buffer, lpLocaleString, byteCount);
+ int lcid = Integer.parseInt(buffer.toString(0, buffer.strlen ()), 16);
+
+ /* Check the language */
+ int size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO639LANGNAME, buffer, length);
+ if (size <= 0 || !lang.equals(buffer.toString(0, size - 1))) return 1;
+
+ /* Check the country */
+ if (country != null) {
+ size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO3166CTRYNAME, buffer, length);
+ if (size <= 0 || !country.equals(buffer.toString(0, size - 1))) return 1;
+ }
+
+ /* Get the charset */
+ size = OS.GetLocaleInfo(lcid, OS.LOCALE_IDEFAULTANSICODEPAGE, buffer, length);
+ if (size <= 0) return 1;
+ int cp = Integer.parseInt(buffer.toString(0, size - 1));
+ int [] lpCs = new int[8];
+ OS.TranslateCharsetInfo(cp, lpCs, OS.TCI_SRCCODEPAGE);
+ data.lfCharSet = (byte)lpCs[0];
+
+ return 0;
+}
+
+/**
+ * Returns the height of the receiver in points.
+ *
+ * @return the height of this FontData
+ *
+ * @see #setHeight(int)
+ */
+public int getHeight() {
+ return (int)(0.5f + height);
+}
+
+/*public*/ float getHeightF() {
+ return height;
+}
+
+/**
+ * Returns the locale of the receiver.
+ * + * The locale determines which platform character set this + * font is going to use. Widgets and graphics operations that + * use this font will convert UNICODE strings to the platform + * character set of the specified locale. + *
+ *+ * On platforms where there are multiple character sets for a + * given language/country locale, the variant portion of the + * locale will determine the character set. + *
+ * + * @return theString
representing a Locale object
+ * @since 3.0
+ */
+public String getLocale () {
+ StringBuilder buffer = new StringBuilder ();
+ char sep = '_';
+ if (lang != null) {
+ buffer.append (lang);
+ buffer.append (sep);
+ }
+ if (country != null) {
+ buffer.append (country);
+ buffer.append (sep);
+ }
+ if (variant != null) {
+ buffer.append (variant);
+ }
+
+ String result = buffer.toString ();
+ int length = result.length ();
+ if (length > 0) {
+ if (result.charAt (length - 1) == sep) {
+ result = result.substring (0, length - 1);
+ }
+ }
+ return result;
+}
+
+/**
+ * Returns the name of the receiver.
+ * On platforms that support font foundries, the return value will
+ * be the foundry followed by a dash ("-") followed by the face name.
+ *
+ * @return the name of this FontData
+ *
+ * @see #setName
+ */
+public String getName() {
+ char[] chars = data.lfFaceName;
+ int index = 0;
+ while (index < chars.length) {
+ if (chars [index] == 0) break;
+ index++;
+ }
+ return new String (chars, 0, index);
+}
+
+/**
+ * Returns the style of the receiver which is a bitwise OR of
+ * one or more of the SWT
constants NORMAL, BOLD
+ * and ITALIC.
+ *
+ * @return the style of this FontData
+ *
+ * @see #setStyle
+ */
+public int getStyle() {
+ int style = SWT.NORMAL;
+ if (data.lfWeight == 700) style |= SWT.BOLD;
+ if (data.lfItalic != 0) style |= SWT.ITALIC;
+ return style;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+@Override
+public int hashCode () {
+ return data.lfCharSet ^ getHeight() << 8 ^ data.lfWidth ^ data.lfEscapement ^
+ data.lfOrientation ^ data.lfWeight ^ data.lfItalic ^ data.lfUnderline ^
+ data.lfStrikeOut ^ data.lfCharSet ^ data.lfOutPrecision ^
+ data.lfClipPrecision ^ data.lfQuality ^ data.lfPitchAndFamily ^
+ getName().hashCode();
+}
+
+/**
+ * Sets the height of the receiver. The parameter is
+ * specified in terms of points, where a point is one
+ * seventy-second of an inch.
+ *
+ * @param height the height of the FontData
+ *
+ * @exception IllegalArgumentException + * The locale determines which platform character set this + * font is going to use. Widgets and graphics operations that + * use this font will convert UNICODE strings to the platform + * character set of the specified locale. + *
+ *+ * On platforms where there are multiple character sets for a + * given language/country locale, the variant portion of the + * locale will determine the character set. + *
+ * + * @param locale theString
representing a Locale object
+ * @see java.util.Locale#toString
+ */
+public void setLocale(String locale) {
+ lang = country = variant = null;
+ if (locale != null) {
+ char sep = '_';
+ int length = locale.length();
+ int firstSep, secondSep;
+
+ firstSep = locale.indexOf(sep);
+ if (firstSep == -1) {
+ firstSep = secondSep = length;
+ } else {
+ secondSep = locale.indexOf(sep, firstSep + 1);
+ if (secondSep == -1) secondSep = length;
+ }
+ if (firstSep > 0) lang = locale.substring(0, firstSep);
+ if (secondSep > firstSep + 1) country = locale.substring(firstSep + 1, secondSep);
+ if (length > secondSep + 1) variant = locale.substring(secondSep + 1);
+ }
+ if (lang == null) {
+ data.lfCharSet = (byte)OS.DEFAULT_CHARSET;
+ } else {
+ Callback callback = new Callback (this, "EnumLocalesProc", 1); //$NON-NLS-1$
+ long lpEnumLocalesProc = callback.getAddress ();
+ if (lpEnumLocalesProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ OS.EnumSystemLocales(lpEnumLocalesProc, OS.LCID_SUPPORTED);
+ callback.dispose ();
+ }
+}
+
+/**
+ * Sets the name of the receiver.
+ * + * Some platforms support font foundries. On these platforms, the name + * of the font specified in setName() may have one of the following forms:
+ *+ * In either case, the name returned from getName() will include the + * foundry. + *
+ *
+ * On platforms that do not support font foundries, only the face name
+ * (for example, "courier") is used in setName()
and
+ * getName()
.
+ *
SWT
+ * constants NORMAL, BOLD and ITALIC. All other style bits are
+ * ignored.
+ *
+ * @param style the new style for this FontData
+ *
+ * @see #getStyle
+ */
+public void setStyle(int style) {
+ if ((style & SWT.BOLD) == SWT.BOLD) {
+ data.lfWeight = 700;
+ } else {
+ data.lfWeight = 0;
+ }
+ if ((style & SWT.ITALIC) == SWT.ITALIC) {
+ data.lfItalic = 1;
+ } else {
+ data.lfItalic = 0;
+ }
+}
+
+/**
+ * Returns a string representation of the receiver which is suitable
+ * for constructing an equivalent instance using the
+ * FontData(String)
constructor.
+ *
+ * @return a string representation of the FontData
+ *
+ * @see FontData
+ */
+@Override
+public String toString() {
+ StringBuilder buffer = new StringBuilder(128);
+ buffer.append("1|"); //$NON-NLS-1$
+ String name = getName();
+ buffer.append(name);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(getHeightF());
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(getStyle());
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append("WINDOWS|1|"); //$NON-NLS-1$
+ buffer.append(data.lfHeight);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfWidth);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfEscapement);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfOrientation);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfWeight);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfItalic);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfUnderline);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfStrikeOut);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfCharSet);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfOutPrecision);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfClipPrecision);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfQuality);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfPitchAndFamily);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(name);
+ return buffer.toString();
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new font data.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for FontData
. It is marked public only so that
+ * it can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
LOGFONT
for the font data
+ * @param height the height of the font data
+ * @return a new font data object containing the specified LOGFONT
and height
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ */
+public static FontData win32_new(LOGFONT data, float height) {
+ return new FontData(data, height);
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/FontMetrics.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/FontMetrics.java
new file mode 100644
index 000000000..5bca68c12
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/FontMetrics.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class provide measurement information
+ * about fonts including ascent, descent, height, leading
+ * space between rows, and average character width.
+ * FontMetrics
are obtained from GC
s
+ * using the getFontMetrics()
method.
+ *
+ * @see GC#getFontMetrics
+ * @see Sample code and further information
+ */
+public final class FontMetrics {
+
+ /**
+ * On Windows, handle is a Win32 TEXTMETRIC struct
+ * (Warning: This field is platform dependent)
+ * + * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public TEXTMETRIC handle; + +/** + * Prevents instances from being created outside the package. + */ +FontMetrics() { +} + +/** + * Compares the argument to the receiver, and returns true + * if they represent the same object using a class + * specific comparison. + * + * @param object the object to compare with this object + * @returntrue
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof FontMetrics)) return false;
+ TEXTMETRIC metric = ((FontMetrics)object).handle;
+ return handle.tmHeight == metric.tmHeight &&
+ handle.tmAscent == metric.tmAscent &&
+ handle.tmDescent == metric.tmDescent &&
+ handle.tmInternalLeading == metric.tmInternalLeading &&
+ handle.tmExternalLeading == metric.tmExternalLeading &&
+ handle.tmAveCharWidth == metric.tmAveCharWidth &&
+ handle.tmMaxCharWidth == metric.tmMaxCharWidth &&
+ handle.tmWeight == metric.tmWeight &&
+ handle.tmOverhang == metric.tmOverhang &&
+ handle.tmDigitizedAspectX == metric.tmDigitizedAspectX &&
+ handle.tmDigitizedAspectY == metric.tmDigitizedAspectY &&
+// handle.tmFirstChar == metric.tmFirstChar &&
+// handle.tmLastChar == metric.tmLastChar &&
+// handle.tmDefaultChar == metric.tmDefaultChar &&
+// handle.tmBreakChar == metric.tmBreakChar &&
+ handle.tmItalic == metric.tmItalic &&
+ handle.tmUnderlined == metric.tmUnderlined &&
+ handle.tmStruckOut == metric.tmStruckOut &&
+ handle.tmPitchAndFamily == metric.tmPitchAndFamily &&
+ handle.tmCharSet == metric.tmCharSet;
+}
+
+/**
+ * Returns the ascent of the font described by the receiver. A
+ * font's ascent is the distance from the baseline to the
+ * top of actual characters, not including any of the leading area,
+ * measured in points.
+ *
+ * @return the ascent of the font
+ */
+public int getAscent() {
+ return DPIUtil.autoScaleDown(handle.tmAscent - handle.tmInternalLeading);
+}
+
+/**
+ * Returns the average character width, measured in points,
+ * of the font described by the receiver.
+ *
+ * @return the average character width of the font
+ * @since 3.107
+ */
+public double getAverageCharacterWidth() {
+ return getAverageCharWidth();
+}
+
+/**
+ * Returns the average character width, measured in points,
+ * of the font described by the receiver.
+ *
+ * @return the average character width of the font
+ * @deprecated Use getAverageCharacterWidth() instead
+ */
+public int getAverageCharWidth() {
+ return DPIUtil.autoScaleDown(handle.tmAveCharWidth);
+}
+
+/**
+ * Returns the descent of the font described by the receiver. A
+ * font's descent is the distance from the baseline to the
+ * bottom of actual characters, not including any of the leading area,
+ * measured in points.
+ *
+ * @return the descent of the font
+ */
+public int getDescent() {
+ return DPIUtil.autoScaleDown(handle.tmDescent);
+}
+
+/**
+ * Returns the height of the font described by the receiver,
+ * measured in points. A font's height is the sum of
+ * its ascent, descent and leading area.
+ *
+ * @return the height of the font
+ *
+ * @see #getAscent
+ * @see #getDescent
+ * @see #getLeading
+ */
+public int getHeight() {
+ return DPIUtil.autoScaleDown(handle.tmHeight);
+}
+
+/**
+ * Returns the leading area of the font described by the
+ * receiver. A font's leading area is the space
+ * above its ascent which may include accents or other marks.
+ *
+ * @return the leading space of the font
+ */
+public int getLeading() {
+ /*
+ * HiHPI rounding problem (bug 490743 comment 17):
+ *
+ * API clients expect this invariant:
+ * getHeight() == getLeading() + getAscent() + getDescent()
+ *
+ * Separate rounding of each RHS term can break the invariant.
+ *
+ * An additional problem is that ascent and descent are more important to
+ * be as close as possible to the real value. Any necessary rounding
+ * adjustment should go into leading, that's why compute this as a derived
+ * value here:
+ */
+ return getHeight() - getAscent() - getDescent();
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+@Override
+public int hashCode() {
+ return handle.tmHeight ^ handle.tmAscent ^ handle.tmDescent ^
+ handle.tmInternalLeading ^ handle.tmExternalLeading ^
+ handle.tmAveCharWidth ^ handle.tmMaxCharWidth ^ handle.tmWeight ^
+ handle.tmOverhang ^ handle.tmDigitizedAspectX ^ handle.tmDigitizedAspectY ^
+// handle.tmFirstChar ^ handle.tmLastChar ^ handle.tmDefaultChar ^ handle.tmBreakChar ^
+ handle.tmItalic ^ handle.tmUnderlined ^ handle.tmStruckOut ^
+ handle.tmPitchAndFamily ^ handle.tmCharSet;
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new font metrics.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for FontMetrics
. It is marked public only so that
+ * it can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
TEXTMETRIC
containing information about a font
+ * @return a new font metrics object containing the specified TEXTMETRIC
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ */
+public static FontMetrics win32_new(TEXTMETRIC handle) {
+ FontMetrics fontMetrics = new FontMetrics();
+ fontMetrics.handle = handle;
+ return fontMetrics;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/GC.java
new file mode 100644
index 000000000..2db1ba826
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/GC.java
@@ -0,0 +1,5053 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Class GC
is where all of the drawing capabilities that are
+ * supported by SWT are located. Instances are used to draw on either an
+ * Image
, a Control
, or directly on a Display
.
+ * + * The SWT drawing coordinate system is the two-dimensional space with the origin + * (0,0) at the top left corner of the drawing area and with (x,y) values increasing + * to the right and downward respectively. + *
+ * + *+ * The result of drawing on an image that was created with an indexed + * palette using a color that is not in the palette is platform specific. + * Some platforms will match to the nearest color while other will draw + * the color itself. This happens because the allocated image might use + * a direct palette on platforms that do not support indexed palette. + *
+ * + *
+ * Application code must explicitly invoke the GC.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required. This is particularly
+ * important on Windows95 and Windows98 where the operating system has a limited
+ * number of device contexts available.
+ *
+ * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified. + *
+ * + * @see org.eclipse.swt.events.PaintEvent + * @see GC snippets + * @see SWT Examples: GraphicsExample, PaintExample + * @see Sample code and further information + */ +public final class GC extends Resource { + + /** + * the handle to the OS device context + * (Warning: This field is platform dependent) + *+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public long handle; + + Drawable drawable; + GCData data; + + static final int FOREGROUND = 1 << 0; + static final int BACKGROUND = 1 << 1; + static final int FONT = 1 << 2; + static final int LINE_STYLE = 1 << 3; + static final int LINE_WIDTH = 1 << 4; + static final int LINE_CAP = 1 << 5; + static final int LINE_JOIN = 1 << 6; + static final int LINE_MITERLIMIT = 1 << 7; + static final int FOREGROUND_TEXT = 1 << 8; + static final int BACKGROUND_TEXT = 1 << 9; + static final int BRUSH = 1 << 10; + static final int PEN = 1 << 11; + static final int NULL_BRUSH = 1 << 12; + static final int NULL_PEN = 1 << 13; + static final int DRAW_OFFSET = 1 << 14; + + static final int DRAW = FOREGROUND | LINE_STYLE | LINE_WIDTH | LINE_CAP | LINE_JOIN | LINE_MITERLIMIT | PEN | NULL_BRUSH | DRAW_OFFSET; + static final int FILL = BACKGROUND | BRUSH | NULL_PEN; + + static final float[] LINE_DOT_ZERO = new float[]{3, 3}; + static final float[] LINE_DASH_ZERO = new float[]{18, 6}; + static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6}; + static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3}; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +GC() { +} + +/** + * Constructs a new instance of this class which has been + * configured to draw on the specified drawable. Sets the + * foreground color, background color and font in the GC + * to match those in the drawable. + *+ * You must dispose the graphics context when it is no longer required. + *
+ * @param drawable the drawable to draw on + * @exception IllegalArgumentException+ * You must dispose the graphics context when it is no longer required. + *
+ * + * @param drawable the drawable to draw on + * @param style the style of GC to construct + * + * @exception IllegalArgumentExceptionSWT.BITMAP
.
+ *
+ * @param image the image to copy into
+ * @param x the x coordinate in the receiver of the area to be copied
+ * @param y the y coordinate in the receiver of the area to be copied
+ *
+ * @exception IllegalArgumentException true
paint events will be generated for old and obscured areas
+ *
+ * @exception SWTException
+ * The resulting arc begins at startAngle
and extends
+ * for arcAngle
degrees, using the current color.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ *
+ * The center of the arc is the center of the rectangle whose origin
+ * is (x
, y
) and whose size is specified by the
+ * width
and height
arguments.
+ *
+ * The resulting arc covers an area width + 1
points wide
+ * by height + 1
points tall.
+ *
x1
, y1
) and (x2
, y2
).
+ *
+ * @param x1 the first point's x coordinate
+ * @param y1 the first point's y coordinate
+ * @param x2 the second point's x coordinate
+ * @param y2 the second point's y coordinate
+ *
+ * @exception SWTException
+ * The result is a circle or ellipse that fits within the
+ * rectangle specified by the x
, y
,
+ * width
, and height
arguments.
+ *
+ * The oval covers an area that is width + 1
+ * points wide and height + 1
points tall.
+ *
+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * + * @param path the path to draw + * + * @exception IllegalArgumentExceptionx
, y
).
+ * + * Note that the receiver's line attributes do not affect this + * operation. + *
+ * + * @param x the point's x coordinate + * @param y the point's y coordinate + * + * @exception SWTExceptionx
and x + width
.
+ * The top and bottom edges are at y
and y + height
.
+ *
+ * @param x the x coordinate of the rectangle to be drawn
+ * @param y the y coordinate of the rectangle to be drawn
+ * @param width the width of the rectangle to be drawn
+ * @param height the height of the rectangle to be drawn
+ *
+ * @exception SWTException rect.x
and rect.x + rect.width
. The top
+ * and bottom edges are at rect.y
and
+ * rect.y + rect.height
.
+ *
+ * @param rect the rectangle to draw
+ *
+ * @exception IllegalArgumentException x
and x + width
.
+ * The top and bottom edges are at y
and y + height
.
+ * The roundness of the corners is specified by the
+ * arcWidth
and arcHeight
arguments, which
+ * are respectively the width and height of the ellipse used to draw
+ * the corners.
+ *
+ * @param x the x coordinate of the rectangle to be drawn
+ * @param y the y coordinate of the rectangle to be drawn
+ * @param width the width of the rectangle to be drawn
+ * @param height the height of the rectangle to be drawn
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ *
+ * @exception SWTException isTransparent
is true
,
+ * then the background of the rectangular area where the string is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param isTransparent if true
the background will be transparent, otherwise it will be opaque
+ *
+ * @exception IllegalArgumentException isTransparent
is true
,
+ * then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param isTransparent if true
the background will be transparent, otherwise it will be opaque
+ *
+ * @exception IllegalArgumentException flags
includes DRAW_TRANSPARENT
,
+ * then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ *
+ * The parameter flags
may be a combination of:
+ *
true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode
+ */
+@Override
+public boolean equals (Object object) {
+ return (object == this) || ((object instanceof GC) && (handle == ((GC)object).handle));
+}
+
+/**
+ * Fills the interior of a circular or elliptical arc within
+ * the specified rectangular area, with the receiver's background
+ * color.
+ *
+ * The resulting arc begins at startAngle
and extends
+ * for arcAngle
degrees, using the current color.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ *
+ * The center of the arc is the center of the rectangle whose origin
+ * is (x
, y
) and whose size is specified by the
+ * width
and height
arguments.
+ *
+ * The resulting arc covers an area width + 1
points wide
+ * by height + 1
points tall.
+ *
+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * + * @param path the path to fill + * + * @exception IllegalArgumentException+ * The advance width is defined as the horizontal distance the cursor + * should move after printing the character in the selected font. + *
+ * + * @param ch the character to measure + * @return the distance in the x direction to move past the character before painting the next + * + * @exception SWTExceptiontrue
if receiver is using the operating system's
+ * advanced graphics subsystem. Otherwise, false
is returned
+ * to indicate that normal graphics are in use.
+ *
+ * Advanced graphics may not be installed for the operating system. In this
+ * case, false
is always returned. Some operating system have
+ * only one graphics subsystem. If this subsystem supports advanced graphics,
+ * then true
is always returned. If any graphics operation such
+ * as alpha, antialias, patterns, interpolation, paths, clipping or transformation
+ * has caused the receiver to switch from regular to advanced graphics mode,
+ * true
is returned. If the receiver has been explicitly switched
+ * to advanced mode and this mode is supported, true
is returned.
+ *
SWT.DEFAULT
, SWT.OFF
or
+ * SWT.ON
. Note that this controls anti-aliasing for all
+ * non-text drawing operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception SWTException null
.
+ *
+ * @return the receiver's background pattern
+ *
+ * @exception SWTException + * The width is defined as the space taken up by the actual + * character, not including the leading and tailing whitespace + * or overhang. + *
+ * + * @param ch the character to measure + * @return the width of the character + * + * @exception SWTExceptionSWT.FILL_EVEN_ODD
or SWT.FILL_WINDING
.
+ *
+ * @return the receiver's fill rule
+ *
+ * @exception SWTException null
.
+ *
+ * @return the receiver's foreground pattern
+ *
+ * @exception SWTException
+ * IMPORTANT: This method is not part of the public
+ * API for GC
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
SWT.DEFAULT
, SWT.NONE
,
+ * SWT.LOW
or SWT.HIGH
.
+ *
+ * @return the receiver's interpolation setting
+ *
+ * @exception SWTException SWT.CAP_FLAT
, SWT.CAP_ROUND
,
+ * or SWT.CAP_SQUARE
.
+ *
+ * @return the cap style used for drawing lines
+ *
+ * @exception SWTException null
.
+ *
+ * @return the line dash style used for drawing lines
+ *
+ * @exception SWTException SWT.JOIN_MITER
, SWT.JOIN_ROUND
,
+ * or SWT.JOIN_BEVEL
.
+ *
+ * @return the join style used for drawing lines
+ *
+ * @exception SWTException SWT.LINE_SOLID
, SWT.LINE_DASH
,
+ * SWT.LINE_DOT
, SWT.LINE_DASHDOT
or
+ * SWT.LINE_DASHDOTDOT
.
+ *
+ * @return the style used for drawing lines
+ *
+ * @exception SWTException drawLine
, drawRectangle
,
+ * drawPolyline
, and so forth.
+ *
+ * @return the receiver's line width
+ *
+ * @exception SWTException + * Note that the value which is returned by this method may + * not match the value which was provided to the constructor + * when the receiver was created. This can occur when the underlying + * operating system does not support a particular combination of + * requested styles. + *
+ * + * @return the style bits + * + * @exception SWTExceptionSWT.DEFAULT
, SWT.OFF
or
+ * SWT.ON
. Note that this controls anti-aliasing
+ * only for text drawing operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception SWTException true
if this GC is drawing in the mode
+ * where the resulting color in the destination is the
+ * exclusive or of the color values in the source
+ * and the destination, and false
if it is
+ * drawing in the mode where the destination color is being
+ * replaced with the source color value.
+ *
+ * @return true
true if the receiver is in XOR mode, and false otherwise
+ *
+ * @exception SWTException true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @exception SWTException true
if the receiver has a clipping
+ * region set into it, and false
otherwise.
+ * If this method returns false, the receiver will draw on all
+ * available space in the destination. If it returns true,
+ * it will draw only in the area that is covered by the region
+ * that can be accessed with getClipping(region)
.
+ *
+ * @return true
if the GC has a clipping region, and false
otherwise
+ *
+ * @exception SWTException true
if the GC has been disposed,
+ * and false
otherwise.
+ *
+ * This method gets the dispose state for the GC.
+ * When a GC has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the GC.
+ *
+ * @return true
when the GC is disposed and false
otherwise
+ */
+@Override
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+float measureSpace(long font, long format) {
+ PointF pt = new PointF();
+ RectF bounds = new RectF();
+ Gdip.Graphics_MeasureString(data.gdipGraphics, new char[]{' '}, 1, font, pt, format, bounds);
+ return bounds.Width;
+}
+
+/**
+ * Sets the receiver to always use the operating system's advanced graphics
+ * subsystem for all graphics operations if the argument is true
.
+ * If the argument is false
, the advanced graphics subsystem is
+ * no longer used, advanced graphics state is cleared and the normal graphics
+ * subsystem is used from now on.
+ *
+ * Normally, the advanced graphics subsystem is invoked automatically when + * any one of the alpha, antialias, patterns, interpolation, paths, clipping + * or transformation operations in the receiver is requested. When the receiver + * is switched into advanced mode, the advanced graphics subsystem performs both + * advanced and normal graphics operations. Because the two subsystems are + * different, their output may differ. Switching to advanced graphics before + * any graphics operations are performed ensures that the output is consistent. + *
+ * Advanced graphics may not be installed for the operating system. In this + * case, this operation does nothing. Some operating system have only one + * graphics subsystem, so switching from normal to advanced graphics does + * nothing. However, switching from advanced to normal graphics will always + * clear the advanced graphics state, even for operating systems that have + * only one graphics subsystem. + *
+ * + * @param advanced the new advanced graphics state + * + * @exception SWTExceptionSWT.DEFAULT
, SWT.OFF
+ * or SWT.ON
. Note that this controls anti-aliasing for all
+ * non-text drawing operations.
+ * + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * + * @param antialias the anti-aliasing setting + * + * @exception IllegalArgumentExceptionSWT.DEFAULT
,
+ * SWT.OFF
or SWT.ON
+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * @param alpha the alpha value + * + * @exception SWTExceptionnull
.
+ * + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * + * @param pattern the new background pattern + * + * @exception IllegalArgumentException+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * + * @param path the clipping path. + * + * @exception IllegalArgumentExceptionnull
for the
+ * rectangle reverts the receiver's clipping area to its
+ * original value.
+ *
+ * @param rect the clipping rectangle or null
+ *
+ * @exception SWTException null
for the
+ * region reverts the receiver's clipping area to its
+ * original value.
+ *
+ * @param region the clipping region or null
+ *
+ * @exception IllegalArgumentException SWT.FILL_EVEN_ODD
or SWT.FILL_WINDING
.
+ *
+ * @param rule the new fill rule
+ *
+ * @exception IllegalArgumentException SWT.FILL_EVEN_ODD
+ * or SWT.FILL_WINDING
null
.
+ * + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * @param pattern the new foreground pattern + * + * @exception IllegalArgumentExceptionSWT.DEFAULT
, SWT.NONE
,
+ * SWT.LOW
or SWT.HIGH
.
+ * + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * + * @param interpolation the new interpolation setting + * + * @exception IllegalArgumentExceptionSWT.DEFAULT
,
+ * SWT.NONE
, SWT.LOW
or SWT.HIGH
+ * + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * @param attributes the line attributes + * + * @exception IllegalArgumentExceptionSWT.CAP_FLAT
, SWT.CAP_ROUND
,
+ * or SWT.CAP_SQUARE
.
+ *
+ * @param cap the cap style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException null
. If the argument is not null
,
+ * the receiver's line style is set to SWT.LINE_CUSTOM
, otherwise
+ * it is set to SWT.LINE_SOLID
.
+ *
+ * @param dashes the dash style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException SWT.JOIN_MITER
, SWT.JOIN_ROUND
,
+ * or SWT.JOIN_BEVEL
.
+ *
+ * @param join the join style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException SWT.LINE_SOLID
, SWT.LINE_DASH
,
+ * SWT.LINE_DOT
, SWT.LINE_DASHDOT
or
+ * SWT.LINE_DASHDOTDOT
.
+ *
+ * @param lineStyle the style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException drawLine
, drawRectangle
,
+ * drawPolyline
, and so forth.
+ * + * Note that line width of zero is used as a hint to + * indicate that the fastest possible line drawing + * algorithms should be used. This means that the + * output may be different from line width one and + * specially at high DPI it's not recommended to mix + * line width zero with other line widths. + *
+ * + * @param lineWidth the width of a line + * + * @exception SWTExceptiontrue
, puts the receiver
+ * in a drawing mode where the resulting color in the destination
+ * is the exclusive or of the color values in the source
+ * and the destination, and if the argument is false
,
+ * puts the receiver in a drawing mode where the destination color
+ * is replaced with the source color value.
+ *
+ * @param xor if true
, then xor mode is used, otherwise source copy mode is used
+ *
+ * @exception SWTException SWT.DEFAULT
, SWT.OFF
+ * or SWT.ON
. Note that this controls anti-aliasing only
+ * for all text drawing operations.
+ * + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * + * @param antialias the anti-aliasing setting + * + * @exception IllegalArgumentExceptionSWT.DEFAULT
,
+ * SWT.OFF
or SWT.ON
null
, the current transform is set to
+ * the identity transform.
+ * + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ * + * @param transform the transform to set + * + * @exception IllegalArgumentException+ * The extent of a string is the width and height of + * the rectangular area it would cover if drawn in a particular + * font (in this case, the current font in the receiver). + *
+ * + * @param string the string to measure + * @return a point containing the extent of the string + * + * @exception IllegalArgumentException+ * The extent of a string is the width and height of + * the rectangular area it would cover if drawn in a particular + * font (in this case, the current font in the receiver). + *
+ * + * @param string the string to measure + * @return a point containing the extent of the string + * + * @exception IllegalArgumentException+ * The extent of a string is the width and height of + * the rectangular area it would cover if drawn in a particular + * font (in this case, the current font in the receiver). + *
+ * + * @param string the string to measure + * @param flags the flags specifying how to process the text + * @return a point containing the extent of the string + * + * @exception IllegalArgumentException
+ * IMPORTANT: This method is not part of the public
+ * API for GC
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
GC
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ */
+public static GC win32_new(Drawable drawable, GCData data) {
+ GC gc = new GC();
+ long hDC = drawable.internal_new_GC(data);
+ gc.device = data.device;
+ gc.init(drawable, data, hDC);
+ return gc;
+}
+
+/**
+ * Invokes platform specific functionality to wrap a graphics context.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for GC
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
GC
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ */
+public static GC win32_new(long hDC, GCData data) {
+ GC gc = new GC();
+ gc.device = data.device;
+ data.style |= SWT.LEFT_TO_RIGHT;
+ int flags = OS.GetLayout (hDC);
+ if ((flags & OS.LAYOUT_RTL) != 0) {
+ data.style |= SWT.RIGHT_TO_LEFT | SWT.MIRRORED;
+ }
+ gc.init(null, data, hDC);
+ return gc;
+}
+
+/**
+ * Answers the length of the side adjacent to the given angle
+ * of a right triangle. In other words, it returns the integer
+ * conversion of length * cos (angle).
+ *
+ * @param angle the angle in degrees
+ * @param length the length of the triangle's hypotenuse
+ * @return the integer conversion of length * cos (angle)
+ */
+private static int cos(int angle, int length) {
+ return (int)(Math.cos(angle * (Math.PI/180)) * length);
+}
+
+/**
+ * Answers the length of the side opposite to the given angle
+ * of a right triangle. In other words, it returns the integer
+ * conversion of length * sin (angle).
+ *
+ * @param angle the angle in degrees
+ * @param length the length of the triangle's hypotenuse
+ * @return the integer conversion of length * sin (angle)
+ */
+private static int sin(int angle, int length) {
+ return (int)(Math.sin(angle * (Math.PI/180)) * length);
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/GCData.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/GCData.java
new file mode 100644
index 000000000..8f03afbe2
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/GCData.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class are descriptions of GCs in terms
+ * of unallocated platform-specific data fields.
+ * + * IMPORTANT: This class is not part of the public + * API for SWT. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + *
+ * @see Sample code and further information + * @noreference This class is not intended to be referenced by clients + */ +public final class GCData { + public Device device; + public int style, state = -1; + public int foreground = -1; + public int background = -1; + public Font font; + public Pattern foregroundPattern; + public Pattern backgroundPattern; + public int lineStyle = SWT.LINE_SOLID; + public float lineWidth; + public int lineCap = SWT.CAP_FLAT; + public int lineJoin = SWT.JOIN_MITER; + public float lineDashesOffset; + public float[] lineDashes; + public float lineMiterLimit = 10; + public int alpha = 0xFF; + + public Image image; + public PAINTSTRUCT ps; + public int layout = -1; + public long hPen, hOldPen, hBrush, hOldBrush, hNullBitmap, + hwnd, gdipGraphics, gdipPen, gdipBrush, gdipFgBrush, gdipBgBrush, + gdipFont, hGDIFont; + public float gdipXOffset, gdipYOffset; + public int uiState = 0; + public boolean focusDrawn; +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/GlyphMetrics.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/GlyphMetrics.java new file mode 100644 index 000000000..7d55d3c95 --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/GlyphMetrics.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2000, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import org.eclipse.swt.*; +import org.eclipse.swt.internal.*; + +/** + * Instances of this class represent glyph metrics. + *+ * The hashCode() method in this class uses the values of the public + * fields to compute the hash value. When storing instances of the + * class in hashed collections, do not modify these fields after the + * object has been inserted. + *
+ *
+ * Application code does not need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no dispose()
method is provided.
+ *
true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof GlyphMetrics)) return false;
+ GlyphMetrics metrics = (GlyphMetrics)object;
+ return metrics.ascent == ascent && metrics.descent == descent && metrics.width == width;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+@Override
+public int hashCode () {
+ return ascent ^ descent ^ width;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the GlyphMetrics
+ */
+@Override
+public String toString () {
+ return "GlyphMetrics {" + ascent + ", " + descent + ", " + width + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Image.java
new file mode 100644
index 000000000..65d972929
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Image.java
@@ -0,0 +1,2148 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class are graphics which have been prepared
+ * for display on a specific device. That is, they are ready
+ * to paint using methods such as GC.drawImage()
+ * and display on widgets with, for example, Button.setImage()
.
+ *
+ * If loaded from a file format that supports it, an
+ * Image
may have transparency, meaning that certain
+ * pixels are specified as being transparent when drawn. Examples
+ * of file formats that support transparency are GIF and PNG.
+ *
+ * There are two primary ways to use Images
.
+ * The first is to load a graphic file from disk and create an
+ * Image
from it. This is done using an Image
+ * constructor, for example:
+ *
+ * Image i = new Image(device, "C:\\graphic.bmp"); + *+ * A graphic file may contain a color table specifying which + * colors the image was intended to possess. In the above example, + * these colors will be mapped to the closest available color in + * SWT. It is possible to get more control over the mapping of + * colors as the image is being created, using code of the form: + *
+ * ImageData data = new ImageData("C:\\graphic.bmp"); + * RGB[] rgbs = data.getRGBs(); + * // At this point, rgbs contains specifications of all + * // the colors contained within this image. You may + * // allocate as many of these colors as you wish by + * // using the Color constructor Color(RGB), then + * // create the image: + * Image i = new Image(device, data); + *+ *
+ * Applications which require even greater control over the image
+ * loading process should use the support provided in class
+ * ImageLoader
.
+ *
+ * Application code must explicitly invoke the Image.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ *
SWT.BITMAP
, SWT.ICON
)
+ * + * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public int type; + + /** + * the handle to the OS image resource + * (Warning: This field is platform dependent) + *+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public long handle; + + /** + * specifies the transparent pixel + */ + int transparentPixel = -1, transparentColor = -1; + + /** + * the GC which is drawing on the image + */ + GC memGC; + + /** + * the alpha data for the image + */ + byte[] alphaData; + + /** + * the global alpha value to be used for every pixel + */ + int alpha = -1; + + /** + * ImageFileNameProvider to provide file names at various Zoom levels + */ + private ImageFileNameProvider imageFileNameProvider; + + /** + * ImageDataProvider to provide ImageData at various Zoom levels + */ + private ImageDataProvider imageDataProvider; + + /** + * Style flag used to differentiate normal, gray-scale and disabled images based + * on image data providers. Without this, a normal and a disabled image of the + * same image data provider would be considered equal. + */ + private int styleFlag = SWT.IMAGE_COPY; + + /** + * Attribute to cache current device zoom level + */ + private int currentDeviceZoom = 100; + + /** + * width of the image + */ + int width = -1; + + /** + * height of the image + */ + int height = -1; + + /** + * specifies the default scanline padding + */ + static final int DEFAULT_SCANLINE_PAD = 4; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Image (Device device) { + super(device); + currentDeviceZoom = DPIUtil.getDeviceZoom (); +} + +/** + * Constructs an empty instance of this class with the + * specified width and height. The result may be drawn upon + * by creating a GC and using any of its drawing operations, + * as shown in the following example: + *+ * Image i = new Image(device, width, height); + * GC gc = new GC(i); + * gc.drawRectangle(0, 0, 50, 50); + * gc.dispose(); + *+ *
+ * Note: Some platforms may have a limitation on the size + * of image that can be created (size depends on width, height, + * and depth). For example, Windows 95, 98, and ME do not allow + * images larger than 16M. + *
+ *+ * You must dispose the image when it is no longer required. + *
+ * + * @param device the device on which to create the image + * @param width the width of the new image + * @param height the height of the new image + * + * @exception IllegalArgumentException+ * You must dispose the image when it is no longer required. + *
+ * + * @param device the device on which to create the image + * @param srcImage the image to use as the source + * @param flag the style, eitherIMAGE_COPY
, IMAGE_DISABLE
or IMAGE_GRAY
+ *
+ * @exception IllegalArgumentException IMAGE_COPY
, IMAGE_DISABLE
or IMAGE_GRAY
+ * Image i = new Image(device, boundsRectangle); + * GC gc = new GC(i); + * gc.drawRectangle(0, 0, 50, 50); + * gc.dispose(); + *+ *
+ * Note: Some platforms may have a limitation on the size + * of image that can be created (size depends on width, height, + * and depth). For example, Windows 95, 98, and ME do not allow + * images larger than 16M. + *
+ *+ * You must dispose the image when it is no longer required. + *
+ * + * @param device the device on which to create the image + * @param bounds a rectangle specifying the image's width and height (must not be null) + * + * @exception IllegalArgumentExceptionImageData
.
+ * + * You must dispose the image when it is no longer required. + *
+ * + * @param device the device on which to create the image + * @param data the image data to create the image from (must not be null) + * + * @exception IllegalArgumentExceptionSWT.ICON
, from the two given ImageData
+ * objects. The two images must be the same size. Pixel transparency
+ * in either image will be ignored.
+ * + * The mask image should contain white wherever the icon is to be visible, + * and black wherever the icon is to be transparent. In addition, + * the source image should contain black wherever the icon is to be + * transparent. + *
+ *+ * You must dispose the image when it is no longer required. + *
+ * + * @param device the device on which to create the icon + * @param source the color data for the icon + * @param mask the mask data for the icon + * + * @exception IllegalArgumentException
+ * This constructor is provided for convenience when loading a single
+ * image only. If the stream contains multiple images, only the first
+ * one will be loaded. To load multiple images, use
+ * ImageLoader.load()
.
+ *
+ * This constructor may be used to load a resource as follows: + *
+ *+ * static Image loadImage (Display display, Class clazz, String string) { + * InputStream stream = clazz.getResourceAsStream (string); + * if (stream == null) return null; + * Image image = null; + * try { + * image = new Image (display, stream); + * } catch (SWTException ex) { + * } finally { + * try { + * stream.close (); + * } catch (IOException ex) {} + * } + * return image; + * } + *+ *
+ * You must dispose the image when it is no longer required. + *
+ * + * @param device the device on which to create the image + * @param stream the input stream to load the image from + * + * @exception IllegalArgumentException+ * This constructor is provided for convenience when loading + * a single image only. If the specified file contains + * multiple images, only the first one will be used. + *
+ * You must dispose the image when it is no longer required. + *
+ * + * @param device the device on which to create the image + * @param filename the name of the file to load the image from + * + * @exception IllegalArgumentException+ * This constructor is provided for convenience for loading image as + * per DPI level. + * + * @param device the device on which to create the image + * @param imageFileNameProvider the ImageFileNameProvider object that is + * to be used to get the file name + * + * @exception IllegalArgumentException
+ * This constructor is provided for convenience for loading image as + * per DPI level. + * + * @param device the device on which to create the image + * @param imageDataProvider the ImageDataProvider object that is + * to be used to get the ImageData + * + * @exception IllegalArgumentException
true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Image)) return false;
+ Image image = (Image) object;
+ if (device != image.device || transparentPixel != image.transparentPixel) return false;
+ if (imageDataProvider != null && image.imageDataProvider != null) {
+ return (styleFlag == image.styleFlag) && imageDataProvider.equals (image.imageDataProvider);
+ } else if (imageFileNameProvider != null && image.imageFileNameProvider != null) {
+ return (styleFlag == image.styleFlag) && imageFileNameProvider.equals (image.imageFileNameProvider);
+ } else {
+ return handle == image.handle;
+ }
+}
+
+/**
+ * Returns the color to which to map the transparent pixel, or null if
+ * the receiver has no transparent pixel.
+ * + * There are certain uses of Images that do not support transparency + * (for example, setting an image into a button or label). In these cases, + * it may be desired to simulate transparency by using the background + * color of the widget to paint the transparent pixels of the image. + * Use this method to check which color will be used in these cases + * in place of transparency. This value may be set with setBackground(). + *
+ * + * @return the background color of the image, or null if there is no transparency in the image + * + * @exception SWTException
ImageData
based on the receiver.
+ * Modifications made to this ImageData
will not
+ * affect the Image.
+ *
+ * @return an ImageData
containing the image's data and
+ * attributes at 100% zoom level.
+ *
+ * @exception SWTException + * Note that this method is mainly intended to be used by custom + * implementations of {@link ImageDataProvider} that draw a composite image + * at the requested zoom level based on other images. For custom zoom + * levels, the image data may be an auto-scaled version of the native image + * and may look more blurred or mangled than expected. + *
+ *+ * Modifications made to the returned {@code ImageData} will not affect this + * {@code Image}. + *
+ * + * @param zoom + * The zoom level in % of the standard resolution (which is 1 + * physical monitor pixel == 1 SWT logical point). Typically 100, + * 150, or 200. + * @return anImageData
containing the image's data and
+ * attributes at the given zoom level
+ *
+ * @exception SWTException ImageData
based on the receiver.
+ * Modifications made to this ImageData
will not
+ * affect the Image.
+ *
+ * @return an ImageData
containing the image's data
+ * and attributes at the current zoom level.
+ *
+ * @exception SWTException true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+@Override
+public int hashCode () {
+ if (imageDataProvider != null) {
+ return imageDataProvider.hashCode();
+ } else if (imageFileNameProvider != null) {
+ return imageFileNameProvider.hashCode();
+ } else {
+ return (int)handle;
+ }
+}
+
+void init(int width, int height) {
+ if (width <= 0 || height <= 0) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ type = SWT.BITMAP;
+ long hDC = device.internal_new_GC(null);
+ handle = OS.CreateCompatibleBitmap(hDC, width, height);
+ /*
+ * Feature in Windows. CreateCompatibleBitmap() may fail
+ * for large images. The fix is to create a DIB section
+ * in that case.
+ */
+ if (handle == 0) {
+ int bits = OS.GetDeviceCaps(hDC, OS.BITSPIXEL);
+ int planes = OS.GetDeviceCaps(hDC, OS.PLANES);
+ int depth = bits * planes;
+ if (depth < 16) depth = 16;
+ handle = createDIB(width, height, depth);
+ }
+ if (handle != 0) {
+ long memDC = OS.CreateCompatibleDC(hDC);
+ long hOldBitmap = OS.SelectObject(memDC, handle);
+ OS.PatBlt(memDC, 0, 0, width, height, OS.PATCOPY);
+ OS.SelectObject(memDC, hOldBitmap);
+ OS.DeleteDC(memDC);
+ }
+ device.internal_dispose_GC(hDC, null);
+ if (handle == 0) {
+ SWT.error(SWT.ERROR_NO_HANDLES, null, device.getLastError());
+ }
+}
+
+static long createDIB(int width, int height, int depth) {
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = width;
+ bmiHeader.biHeight = -height;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = (short)depth;
+ bmiHeader.biCompression = OS.BI_RGB;
+ byte[] bmi = new byte[BITMAPINFOHEADER.sizeof];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ long[] pBits = new long[1];
+ return OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
+}
+
+static long [] init(Device device, Image image, ImageData i) {
+ /* Windows does not support 2-bit images. Convert to 4-bit image. */
+ if (i.depth == 2) {
+ ImageData img = new ImageData(i.width, i.height, 4, i.palette);
+ ImageData.blit(ImageData.BLIT_SRC,
+ i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, null, null, null,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ img.data, img.depth, img.bytesPerLine, i.getByteOrder(), 0, 0, img.width, img.height, null, null, null,
+ false, false);
+ img.transparentPixel = i.transparentPixel;
+ img.maskPad = i.maskPad;
+ img.maskData = i.maskData;
+ img.alpha = i.alpha;
+ img.alphaData = i.alphaData;
+ i = img;
+ }
+ /*
+ * Windows supports 16-bit mask of (0x7C00, 0x3E0, 0x1F),
+ * 24-bit mask of (0xFF0000, 0xFF00, 0xFF) and 32-bit mask
+ * (0x00FF0000, 0x0000FF00, 0x000000FF) as documented in
+ * MSDN BITMAPINFOHEADER. Make sure the image is
+ * Windows-supported.
+ */
+ if (i.palette.isDirect) {
+ final PaletteData palette = i.palette;
+ final int redMask = palette.redMask;
+ final int greenMask = palette.greenMask;
+ final int blueMask = palette.blueMask;
+ int newDepth = i.depth;
+ int newOrder = ImageData.MSB_FIRST;
+ PaletteData newPalette = null;
+
+ switch (i.depth) {
+ case 8:
+ newDepth = 16;
+ newOrder = ImageData.LSB_FIRST;
+ newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
+ break;
+ case 16:
+ newOrder = ImageData.LSB_FIRST;
+ if (!(redMask == 0x7C00 && greenMask == 0x3E0 && blueMask == 0x1F)) {
+ newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
+ }
+ break;
+ case 24:
+ if (!(redMask == 0xFF && greenMask == 0xFF00 && blueMask == 0xFF0000)) {
+ newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
+ }
+ break;
+ case 32:
+ if (!(redMask == 0xFF00 && greenMask == 0xFF0000 && blueMask == 0xFF000000)) {
+ newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ }
+ break;
+ default:
+ SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
+ if (newPalette != null) {
+ ImageData img = new ImageData(i.width, i.height, newDepth, newPalette);
+ ImageData.blit(ImageData.BLIT_SRC,
+ i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, redMask, greenMask, blueMask,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ img.data, img.depth, img.bytesPerLine, newOrder, 0, 0, img.width, img.height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask,
+ false, false);
+ if (i.transparentPixel != -1) {
+ img.transparentPixel = newPalette.getPixel(palette.getRGB(i.transparentPixel));
+ }
+ img.maskPad = i.maskPad;
+ img.maskData = i.maskData;
+ img.alpha = i.alpha;
+ img.alphaData = i.alphaData;
+ i = img;
+ }
+ }
+ /* Construct bitmap info header by hand */
+ RGB[] rgbs = i.palette.getRGBs();
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = i.width;
+ bmiHeader.biHeight = -i.height;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = (short)i.depth;
+ bmiHeader.biCompression = OS.BI_RGB;
+ bmiHeader.biClrUsed = rgbs == null ? 0 : rgbs.length;
+ byte[] bmi;
+ if (i.palette.isDirect)
+ bmi = new byte[BITMAPINFOHEADER.sizeof];
+ else
+ bmi = new byte[BITMAPINFOHEADER.sizeof + rgbs.length * 4];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ /* Set the rgb colors into the bitmap info */
+ int offset = BITMAPINFOHEADER.sizeof;
+ if (!i.palette.isDirect) {
+ for (int j = 0; j < rgbs.length; j++) {
+ bmi[offset] = (byte)rgbs[j].blue;
+ bmi[offset + 1] = (byte)rgbs[j].green;
+ bmi[offset + 2] = (byte)rgbs[j].red;
+ bmi[offset + 3] = 0;
+ offset += 4;
+ }
+ }
+ long[] pBits = new long[1];
+ long hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
+ if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ /* In case of a scanline pad other than 4, do the work to convert it */
+ byte[] data = i.data;
+ if (i.scanlinePad != 4 && (i.bytesPerLine % 4 != 0)) {
+ data = ImageData.convertPad(data, i.width, i.height, i.depth, i.scanlinePad, 4);
+ }
+ OS.MoveMemory(pBits[0], data, data.length);
+
+ long [] result = null;
+ if (i.getTransparencyType() == SWT.TRANSPARENCY_MASK) {
+ /* Get the HDC for the device */
+ long hDC = device.internal_new_GC(null);
+
+ /* Create the color bitmap */
+ long hdcSrc = OS.CreateCompatibleDC(hDC);
+ OS.SelectObject(hdcSrc, hDib);
+ long hBitmap = OS.CreateCompatibleBitmap(hDC, i.width, i.height);
+ if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ long hdcDest = OS.CreateCompatibleDC(hDC);
+ OS.SelectObject(hdcDest, hBitmap);
+ OS.BitBlt(hdcDest, 0, 0, i.width, i.height, hdcSrc, 0, 0, OS.SRCCOPY);
+
+ /* Release the HDC for the device */
+ device.internal_dispose_GC(hDC, null);
+
+ /* Create the mask. Windows requires icon masks to have a scanline pad of 2. */
+ byte[] maskData = ImageData.convertPad(i.maskData, i.width, i.height, 1, i.maskPad, 2);
+ long hMask = OS.CreateBitmap(i.width, i.height, 1, 1, maskData);
+ if (hMask == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.SelectObject(hdcSrc, hMask);
+ OS.PatBlt(hdcSrc, 0, 0, i.width, i.height, OS.DSTINVERT);
+ OS.DeleteDC(hdcSrc);
+ OS.DeleteDC(hdcDest);
+ OS.DeleteObject(hDib);
+
+ if (image == null) {
+ result = new long []{hBitmap, hMask};
+ } else {
+ /* Create the icon */
+ ICONINFO info = new ICONINFO();
+ info.fIcon = true;
+ info.hbmColor = hBitmap;
+ info.hbmMask = hMask;
+ long hIcon = OS.CreateIconIndirect(info);
+ if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.DeleteObject(hBitmap);
+ OS.DeleteObject(hMask);
+ image.handle = hIcon;
+ image.type = SWT.ICON;
+ }
+ } else {
+ if (image == null) {
+ result = new long []{hDib};
+ } else {
+ image.handle = hDib;
+ image.type = SWT.BITMAP;
+ image.transparentPixel = i.transparentPixel;
+ if (image.transparentPixel == -1) {
+ image.alpha = i.alpha;
+ if (i.alpha == -1 && i.alphaData != null) {
+ int length = i.alphaData.length;
+ image.alphaData = new byte[length];
+ System.arraycopy(i.alphaData, 0, image.alphaData, 0, length);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static long [] init(Device device, Image image, ImageData source, ImageData mask) {
+ /* Create a temporary image and locate the black pixel */
+ ImageData imageData;
+ int blackIndex = 0;
+ if (source.palette.isDirect) {
+ imageData = new ImageData(source.width, source.height, source.depth, source.palette);
+ } else {
+ RGB black = new RGB(0, 0, 0);
+ RGB[] rgbs = source.getRGBs();
+ if (source.transparentPixel != -1) {
+ /*
+ * The source had transparency, so we can use the transparent pixel
+ * for black.
+ */
+ RGB[] newRGBs = new RGB[rgbs.length];
+ System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length);
+ if (source.transparentPixel >= newRGBs.length) {
+ /* Grow the palette with black */
+ rgbs = new RGB[source.transparentPixel + 1];
+ System.arraycopy(newRGBs, 0, rgbs, 0, newRGBs.length);
+ for (int i = newRGBs.length; i <= source.transparentPixel; i++) {
+ rgbs[i] = new RGB(0, 0, 0);
+ }
+ } else {
+ newRGBs[source.transparentPixel] = black;
+ rgbs = newRGBs;
+ }
+ blackIndex = source.transparentPixel;
+ imageData = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs));
+ } else {
+ while (blackIndex < rgbs.length) {
+ if (rgbs[blackIndex].equals(black)) break;
+ blackIndex++;
+ }
+ if (blackIndex == rgbs.length) {
+ /*
+ * We didn't find black in the palette, and there is no transparent
+ * pixel we can use.
+ */
+ if ((1 << source.depth) > rgbs.length) {
+ /* We can grow the palette and add black */
+ RGB[] newRGBs = new RGB[rgbs.length + 1];
+ System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length);
+ newRGBs[rgbs.length] = black;
+ rgbs = newRGBs;
+ } else {
+ /* No room to grow the palette */
+ blackIndex = -1;
+ }
+ }
+ imageData = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs));
+ }
+ }
+ if (blackIndex == -1) {
+ /* There was no black in the palette, so just copy the data over */
+ System.arraycopy(source.data, 0, imageData.data, 0, imageData.data.length);
+ } else {
+ /* Modify the source image to contain black wherever the mask is 0 */
+ int[] imagePixels = new int[imageData.width];
+ int[] maskPixels = new int[mask.width];
+ for (int y = 0; y < imageData.height; y++) {
+ source.getPixels(0, y, imageData.width, imagePixels, 0);
+ mask.getPixels(0, y, mask.width, maskPixels, 0);
+ for (int i = 0; i < imagePixels.length; i++) {
+ if (maskPixels[i] == 0) imagePixels[i] = blackIndex;
+ }
+ imageData.setPixels(0, y, source.width, imagePixels, 0);
+ }
+ }
+ imageData.maskPad = mask.scanlinePad;
+ imageData.maskData = mask.data;
+ return init(device, image, imageData);
+}
+void init(ImageData i) {
+ if (i == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(device, this, i);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for Image
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for Image
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
true
if the image has been disposed,
+ * and false
otherwise.
+ *
+ * This method gets the dispose state for the image.
+ * When an image has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the image.
+ *
+ * @return true
when the image is disposed and false
otherwise
+ */
+@Override
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Sets the color to which to map the transparent pixel.
+ *
+ * There are certain uses of Images
that do not support
+ * transparency (for example, setting an image into a button or label).
+ * In these cases, it may be desired to simulate transparency by using
+ * the background color of the widget to paint the transparent pixels
+ * of the image. This method specifies the color that will be used in
+ * these cases. For example:
+ * Button b = new Button(); + * image.setBackground(b.getBackground()); + * b.setImage(image); + *+ *
+ * The image may be modified by this operation (in effect, the + * transparent regions may be filled with the supplied color). Hence + * this operation is not reversible and it is not legal to call + * this function twice or with a null argument. + *
+ * This method has no effect if the receiver does not have a transparent + * pixel value. + *
+ * + * @param color the color to use when a transparent pixel is specified + * + * @exception IllegalArgumentException
+ * IMPORTANT: This method is not part of the public
+ * API for Image
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
SWT.BITMAP
or SWT.ICON
)
+ * @param handle the OS handle for the image
+ * @return a new image object containing the specified device, type and handle
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ */
+public static Image win32_new(Device device, int type, long handle) {
+ Image image = new Image(device);
+ image.type = type;
+ image.handle = handle;
+ return image;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageData.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageData.java
new file mode 100644
index 000000000..2811d5480
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageData.java
@@ -0,0 +1,3704 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+
+/**
+ * Instances of this class are device-independent descriptions
+ * of images. They are typically used as an intermediate format
+ * between loading from or writing to streams and creating an
+ * Image
.
+ *
+ * Note that the public fields x
, y
,
+ * disposalMethod
and delayTime
are
+ * typically only used when the image is in a set of images used
+ * for animation.
+ *
+ * Note that a depth of 8 or less does not necessarily + * mean that the image is palette indexed, or + * conversely that a depth greater than 8 means that + * the image is direct color. Check the associated + * PaletteData's isDirect field for such determinations. + */ + public int depth; + + /** + * The scanline padding. + *
+ * If one scanline of the image is not a multiple of + * this number, it will be padded with zeros until it is. + *
+ */ + public int scanlinePad; + + /** + * The number of bytes per scanline. + *+ * This is a multiple of the scanline padding. + *
+ */ + public int bytesPerLine; + + /** + * The pixel data of the image. + *+ * Note that for 16 bit depth images the pixel data is stored + * in least significant byte order; however, for 24bit and + * 32bit depth images the pixel data is stored in most + * significant byte order. + *
+ */ + public byte[] data; + + /** + * The color table for the image. + */ + public PaletteData palette; + + /** + * The transparent pixel. + *+ * Pixels with this value are transparent. + *
+ * The default is -1 which means 'no transparent pixel'. + *
+ */ + public int transparentPixel; + + /** + * An icon-specific field containing the data from the icon mask. + *+ * This is a 1 bit bitmap stored with the most significant + * bit first. The number of bytes per scanline is + * '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'. + *
+ * The default is null which means 'no transparency mask'. + *
+ */ + public byte[] maskData; + + /** + * An icon-specific field containing the scanline pad of the mask. + *+ * If one scanline of the transparency mask is not a + * multiple of this number, it will be padded with zeros until + * it is. + *
+ */ + public int maskPad; + + /** + * The alpha data of the image. + *+ * Every pixel can have an alpha blending value that + * varies from 0, meaning fully transparent, to 255 meaning + * fully opaque. The number of bytes per scanline is + * 'width'. + *
+ */ + public byte[] alphaData; + + /** + * The global alpha value to be used for every pixel. + *
+ * If this value is set, the alphaData
field
+ * is ignored and when the image is rendered each pixel
+ * will be blended with the background an amount
+ * proportional to this value.
+ *
+ * The default is -1 which means 'no global alpha value' + *
+ */ + public int alpha; + + /** + * The type of file from which the image was read. + * + * It is expressed as one of the following values: + *IMAGE_BMP
IMAGE_BMP_RLE
IMAGE_GIF
IMAGE_ICO
IMAGE_JPEG
IMAGE_PNG
DM_UNSPECIFIED
DM_FILL_NONE
DM_FILL_BACKGROUND
DM_FILL_PREVIOUS
ImageData
loaded from the specified
+ * input stream. Throws an error if an error occurs while loading
+ * the image, or if the image has an unsupported type. Application
+ * code is still responsible for closing the input stream.
+ *
+ * This constructor is provided for convenience when loading a single
+ * image only. If the stream contains multiple images, only the first
+ * one will be loaded. To load multiple images, use
+ * ImageLoader.load()
.
+ *
+ * This constructor may be used to load a resource as follows: + *
+ *+ * static ImageData loadImageData (Class clazz, String string) { + * InputStream stream = clazz.getResourceAsStream (string); + * if (stream == null) return null; + * ImageData imageData = null; + * try { + * imageData = new ImageData (stream); + * } catch (SWTException ex) { + * } finally { + * try { + * stream.close (); + * } catch (IOException ex) {} + * } + * return imageData; + * } + *+ * + * @param stream the input stream to load the image from (must not be null) + * + * @exception IllegalArgumentException
ImageData
loaded from a file with the
+ * specified name. Throws an error if an error occurs loading the
+ * image, or if the image has an unsupported type.
+ *
+ * This constructor is provided for convenience when loading a single
+ * image only. If the file contains multiple images, only the first
+ * one will be loaded. To load multiple images, use
+ * ImageLoader.load()
.
+ *
+ * This method is for internal use, and is not described further. + *
+ */ +ImageData( + int width, int height, int depth, PaletteData palette, + int scanlinePad, byte[] data, int maskPad, byte[] maskData, + byte[] alphaData, int alpha, int transparentPixel, int type, + int x, int y, int disposalMethod, int delayTime) +{ + + if (palette == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (!(depth == 1 || depth == 2 || depth == 4 || depth == 8 + || depth == 16 || depth == 24 || depth == 32)) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (width <= 0 || height <= 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (scanlinePad == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO); + + int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1)) + / scanlinePad * scanlinePad; + + /* + * When the image is being loaded from a PNG, we need to use the theoretical minimum + * number of bytes per line to check whether there is enough data, because the actual + * number of bytes per line is calculated based on the given depth, which may be larger + * than the actual depth of the PNG. + */ + int minBytesPerLine = type == SWT.IMAGE_PNG ? ((((width + 7) / 8) + 3) / 4) * 4 : bytesPerLine; + if (data != null && data.length < minBytesPerLine * height) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + setAllFields( + width, + height, + depth, + scanlinePad, + bytesPerLine, + data != null ? data : new byte[bytesPerLine * height], + palette, + transparentPixel, + maskData, + maskPad, + alphaData, + alpha, + type, + x, + y, + disposalMethod, + delayTime); +} + +/** + * Initializes all fields in the receiver. This method must be called + * by all public constructors to ensure that all fields are initialized + * for a new ImageData object. If a new field is added to the class, + * then it must be added to this method. + *+ * This method is for internal use, and is not described further. + *
+ */ +void setAllFields(int width, int height, int depth, int scanlinePad, + int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel, + byte[] maskData, int maskPad, byte[] alphaData, int alpha, + int type, int x, int y, int disposalMethod, int delayTime) { + + this.width = width; + this.height = height; + this.depth = depth; + this.scanlinePad = scanlinePad; + this.bytesPerLine = bytesPerLine; + this.data = data; + this.palette = palette; + this.transparentPixel = transparentPixel; + this.maskData = maskData; + this.maskPad = maskPad; + this.alphaData = alphaData; + this.alpha = alpha; + this.type = type; + this.x = x; + this.y = y; + this.disposalMethod = disposalMethod; + this.delayTime = delayTime; +} + +/** + * Invokes internal SWT functionality to create a new instance of + * this class. + *
+ * IMPORTANT: This method is not part of the public
+ * API for ImageData
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is subject
+ * to change without notice, and should never be called from
+ * application code.
+ *
+ * This method is for internal use, and is not described further. + *
+ * + * @noreference This method is not intended to be referenced by clients. + */ +public static ImageData internal_new( + int width, int height, int depth, PaletteData palette, + int scanlinePad, byte[] data, int maskPad, byte[] maskData, + byte[] alphaData, int alpha, int transparentPixel, int type, + int x, int y, int disposalMethod, int delayTime) +{ + return new ImageData( + width, height, depth, palette, scanlinePad, data, maskPad, maskData, + alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime); +} + +ImageData colorMaskImage(int pixel) { + ImageData mask = new ImageData(width, height, 1, bwPalette(), + 2, null, 0, null, null, -1, -1, SWT.IMAGE_UNDEFINED, + 0, 0, 0, 0); + int[] row = new int[width]; + for (int y = 0; y < height; y++) { + getPixels(0, y, width, row, 0); + for (int i = 0; i < width; i++) { + if (pixel != -1 && row[i] == pixel) { + row[i] = 0; + } else { + row[i] = 1; + } + } + mask.setPixels(0, y, width, row, 0); + } + return mask; +} + +static byte[] checkData(byte [] data) { + if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + return data; +} + +/** + * Returns a new instance of the same class as the receiver, + * whose slots have been filled in with copies of + * the values in the slots of the receiver. That is, the + * returned object is a deep copy of the receiver. + * + * @return a copy of the receiver. + */ +@Override +public Object clone() { + byte[] cloneData = new byte[data.length]; + System.arraycopy(data, 0, cloneData, 0, data.length); + byte[] cloneMaskData = null; + if (maskData != null) { + cloneMaskData = new byte[maskData.length]; + System.arraycopy(maskData, 0, cloneMaskData, 0, maskData.length); + } + byte[] cloneAlphaData = null; + if (alphaData != null) { + cloneAlphaData = new byte[alphaData.length]; + System.arraycopy(alphaData, 0, cloneAlphaData, 0, alphaData.length); + } + return new ImageData( + width, + height, + depth, + palette, + scanlinePad, + cloneData, + maskPad, + cloneMaskData, + cloneAlphaData, + alpha, + transparentPixel, + type, + x, + y, + disposalMethod, + delayTime); +} + +/** + * Returns the alpha value at offsetx
in
+ * scanline y
in the receiver's alpha data.
+ * The alpha value is between 0 (transparent) and
+ * 255 (opaque).
+ *
+ * @param x the x coordinate of the pixel to get the alpha value of
+ * @param y the y coordinate of the pixel to get the alpha value of
+ * @return the alpha value at the given coordinates
+ *
+ * @exception IllegalArgumentException getWidth
alpha values starting at offset
+ * x
in scanline y
in the receiver's alpha
+ * data starting at startIndex
. The alpha values
+ * are unsigned, between (byte)0
(transparent) and
+ * (byte)255
(opaque).
+ *
+ * @param x the x position of the pixel to begin getting alpha values
+ * @param y the y position of the pixel to begin getting alpha values
+ * @param getWidth the width of the data to get
+ * @param alphas the buffer in which to put the alpha values
+ * @param startIndex the offset into the image to begin getting alpha values
+ *
+ * @exception IndexOutOfBoundsException if getWidth is too large
+ * @exception IllegalArgumentException x
in
+ * scanline y
in the receiver's data.
+ *
+ * @param x the x position of the pixel to get
+ * @param y the y position of the pixel to get
+ * @return the pixel at the given coordinates
+ *
+ * @exception IllegalArgumentException getWidth
pixel values starting at offset
+ * x
in scanline y
in the receiver's
+ * data starting at startIndex
.
+ *
+ * @param x the x position of the first pixel to get
+ * @param y the y position of the first pixel to get
+ * @param getWidth the width of the data to get
+ * @param pixels the buffer in which to put the pixels
+ * @param startIndex the offset into the byte array to begin storing pixels
+ *
+ * @exception IndexOutOfBoundsException if getWidth is too large
+ * @exception IllegalArgumentException getWidth
pixel values starting at offset
+ * x
in scanline y
in the receiver's
+ * data starting at startIndex
.
+ *
+ * @param x the x position of the first pixel to get
+ * @param y the y position of the first pixel to get
+ * @param getWidth the width of the data to get
+ * @param pixels the buffer in which to put the pixels
+ * @param startIndex the offset into the buffer to begin storing pixels
+ *
+ * @exception IndexOutOfBoundsException if getWidth is too large
+ * @exception IllegalArgumentException RGB
s which comprise the
+ * indexed color table of the receiver, or null if the receiver
+ * has a direct color model.
+ *
+ * @return the RGB values for the image or null if direct color
+ *
+ * @see PaletteData#getRGBs()
+ */
+public RGB[] getRGBs() {
+ return palette.getRGBs();
+}
+
+/**
+ * Returns an ImageData
which specifies the
+ * transparency mask information for the receiver. If the
+ * receiver has no transparency or is not an icon, returns
+ * an opaque mask.
+ *
+ * @return the transparency mask
+ */
+public ImageData getTransparencyMask() {
+ int transparencyType = getTransparencyType();
+ switch (transparencyType) {
+ case SWT.TRANSPARENCY_ALPHA: return getTransparencyMaskFromAlphaData();
+ case SWT.TRANSPARENCY_MASK: return new ImageData(width, height, 1, bwPalette(), maskPad, maskData);
+ case SWT.TRANSPARENCY_PIXEL: return colorMaskImage(transparentPixel);
+ default: return colorMaskImage(transparentPixel);
+ }
+}
+
+ImageData getTransparencyMaskFromAlphaData() {
+ ImageData mask = new ImageData(width, height, 1, bwPalette(), 2, null, 0, null, null, -1, -1, SWT.IMAGE_UNDEFINED, 0, 0, 0, 0);
+ int offset = 0;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ byte a = alphaData[offset++];
+ if (a == 0) {
+ mask.setPixel(x, y, 0);
+ } else {
+ mask.setPixel(x, y, 1);
+ }
+ }
+ }
+ return mask;
+}
+
+/**
+ * Returns the image transparency type, which will be one of
+ * SWT.TRANSPARENCY_NONE
, SWT.TRANSPARENCY_MASK
,
+ * SWT.TRANSPARENCY_PIXEL
or SWT.TRANSPARENCY_ALPHA
.
+ *
+ * @return the receiver's transparency type
+ */
+public int getTransparencyType() {
+ if (maskData != null) return SWT.TRANSPARENCY_MASK;
+ if (transparentPixel != -1) return SWT.TRANSPARENCY_PIXEL;
+ if (alphaData != null) return SWT.TRANSPARENCY_ALPHA;
+ return SWT.TRANSPARENCY_NONE;
+}
+
+/**
+ * Returns the byte order of the receiver.
+ *
+ * @return MSB_FIRST or LSB_FIRST
+ */
+int getByteOrder() {
+ return depth != 16 ? MSB_FIRST : LSB_FIRST;
+}
+
+/**
+ * Returns a copy of the receiver which has been stretched or
+ * shrunk to the specified size. If either the width or height
+ * is negative, the resulting image will be inverted in the
+ * associated axis.
+ *
+ * @param width the width of the new ImageData
+ * @param height the height of the new ImageData
+ * @return a scaled copy of the image
+ */
+public ImageData scaledTo(int width, int height) {
+ /* Create a destination image with no data */
+ final boolean flipX = (width < 0);
+ if (flipX) width = - width;
+ final boolean flipY = (height < 0);
+ if (flipY) height = - height;
+
+ ImageData dest = new ImageData(
+ width, height, depth, palette,
+ scanlinePad, null, 0, null,
+ null, -1, transparentPixel, type,
+ x, y, disposalMethod, delayTime);
+
+ /* Scale the image contents */
+ if (palette.isDirect) blit(BLIT_SRC,
+ this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, 0, 0, 0,
+ ALPHA_OPAQUE, null, 0, 0, 0,
+ dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, 0, 0, 0,
+ flipX, flipY);
+ else blit(BLIT_SRC,
+ this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, null, null, null,
+ ALPHA_OPAQUE, null, 0, 0, 0,
+ dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, null, null, null,
+ flipX, flipY);
+
+ /* Scale the image mask or alpha */
+ if (maskData != null) {
+ dest.maskPad = this.maskPad;
+ int destBpl = (dest.width + 7) / 8;
+ destBpl = (destBpl + (dest.maskPad - 1)) / dest.maskPad * dest.maskPad;
+ dest.maskData = new byte[destBpl * dest.height];
+ int srcBpl = (this.width + 7) / 8;
+ srcBpl = (srcBpl + (this.maskPad - 1)) / this.maskPad * this.maskPad;
+ blit(BLIT_SRC,
+ this.maskData, 1, srcBpl, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
+ ALPHA_OPAQUE, null, 0, 0, 0,
+ dest.maskData, 1, destBpl, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
+ flipX, flipY);
+ } else if (alpha != -1) {
+ dest.alpha = this.alpha;
+ } else if (alphaData != null) {
+ dest.alphaData = new byte[dest.width * dest.height];
+ blit(BLIT_SRC,
+ this.alphaData, 8, this.width, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
+ ALPHA_OPAQUE, null, 0, 0, 0,
+ dest.alphaData, 8, dest.width, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
+ flipX, flipY);
+ }
+ return dest;
+}
+
+/**
+ * Sets the alpha value at offset x
in
+ * scanline y
in the receiver's alpha data.
+ * The alpha value must be between 0 (transparent)
+ * and 255 (opaque).
+ *
+ * @param x the x coordinate of the alpha value to set
+ * @param y the y coordinate of the alpha value to set
+ * @param alpha the value to set the alpha to
+ *
+ * @exception IllegalArgumentException x
in
+ * scanline y
in the receiver's alpha data to the
+ * values from the array alphas
starting at
+ * startIndex
. The alpha values must be between
+ * (byte)0
(transparent) and (byte)255
(opaque)
+ *
+ * @param x the x coordinate of the pixel to being setting the alpha values
+ * @param y the y coordinate of the pixel to being setting the alpha values
+ * @param putWidth the width of the alpha values to set
+ * @param alphas the alpha values to set
+ * @param startIndex the index at which to begin setting
+ *
+ * @exception IndexOutOfBoundsException if putWidth is too large
+ * @exception IllegalArgumentException x
in
+ * scanline y
in the receiver's data.
+ *
+ * @param x the x coordinate of the pixel to set
+ * @param y the y coordinate of the pixel to set
+ * @param pixelValue the value to set the pixel to
+ *
+ * @exception IllegalArgumentException x
in
+ * scanline y
in the receiver's data to the
+ * values from the array pixels
starting at
+ * startIndex
.
+ *
+ * @param x the x position of the pixel to set
+ * @param y the y position of the pixel to set
+ * @param putWidth the width of the pixels to set
+ * @param pixels the pixels to set
+ * @param startIndex the index at which to begin setting
+ *
+ * @exception IndexOutOfBoundsException if putWidth is too large
+ * @exception IllegalArgumentException x
in
+ * scanline y
in the receiver's data to the
+ * values from the array pixels
starting at
+ * startIndex
.
+ *
+ * @param x the x position of the pixel to set
+ * @param y the y position of the pixel to set
+ * @param putWidth the width of the pixels to set
+ * @param pixels the pixels to set
+ * @param startIndex the index at which to begin setting
+ *
+ * @exception IndexOutOfBoundsException if putWidth is too large
+ * @exception IllegalArgumentException + * Note: When the source and destination depth, order and masks + * are pairwise equal and the blitter operation is BLIT_SRC, + * the masks are ignored. Hence when not changing the image + * data format, 0 may be specified for the masks. + *
+ * + * @param op the blitter operation: a combination of BLIT_xxx flags + * (see BLIT_xxx constants) + * @param srcData the source byte array containing image data + * @param srcDepth the source depth: one of 8, 16, 24, 32 + * @param srcStride the source number of bytes per line + * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if srcDepth is not 16 or 32 + * @param srcX the top-left x-coord of the source blit region + * @param srcY the top-left y-coord of the source blit region + * @param srcWidth the width of the source blit region + * @param srcHeight the height of the source blit region + * @param srcRedMask the source red channel mask + * @param srcGreenMask the source green channel mask + * @param srcBlueMask the source blue channel mask + * @param alphaMode the alpha blending or mask mode, may be + * an integer 0-255 for global alpha; ignored if BLIT_ALPHA + * not specified in the blitter operations + * (see ALPHA_MODE_xxx constants) + * @param alphaData the alpha blending or mask data, varies depending + * on the value of alphaMode and sometimes ignored + * @param alphaStride the alpha data number of bytes per line + * @param alphaX the top-left x-coord of the alpha blit region + * @param alphaY the top-left y-coord of the alpha blit region + * @param destData the destination byte array containing image data + * @param destDepth the destination depth: one of 8, 16, 24, 32 + * @param destStride the destination number of bytes per line + * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if destDepth is not 16 or 32 + * @param destX the top-left x-coord of the destination blit region + * @param destY the top-left y-coord of the destination blit region + * @param destWidth the width of the destination blit region + * @param destHeight the height of the destination blit region + * @param destRedMask the destination red channel mask + * @param destGreenMask the destination green channel mask + * @param destBlueMask the destination blue channel mask + * @param flipX if true the resulting image is flipped along the vertical axis + * @param flipY if true the resulting image is flipped along the horizontal axis + */ +static void blit(int op, + byte[] srcData, int srcDepth, int srcStride, int srcOrder, + int srcX, int srcY, int srcWidth, int srcHeight, + int srcRedMask, int srcGreenMask, int srcBlueMask, + int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY, + byte[] destData, int destDepth, int destStride, int destOrder, + int destX, int destY, int destWidth, int destHeight, + int destRedMask, int destGreenMask, int destBlueMask, + boolean flipX, boolean flipY) { + if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return; + + // these should be supplied as params later + int srcAlphaMask = 0, destAlphaMask = 0; + + /*** Prepare scaling data ***/ + final int dwm1 = destWidth - 1; + final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0; + final int dhm1 = destHeight - 1; + final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0; + + /*** Prepare source-related data ***/ + final int sbpp, stype; + switch (srcDepth) { + case 8: + sbpp = 1; + stype = TYPE_GENERIC_8; + break; + case 16: + sbpp = 2; + stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB; + break; + case 24: + sbpp = 3; + stype = TYPE_GENERIC_24; + break; + case 32: + sbpp = 4; + stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int spr = srcY * srcStride + srcX * sbpp; + + /*** Prepare destination-related data ***/ + final int dbpp, dtype; + switch (destDepth) { + case 8: + dbpp = 1; + dtype = TYPE_GENERIC_8; + break; + case 16: + dbpp = 2; + dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB; + break; + case 24: + dbpp = 3; + dtype = TYPE_GENERIC_24; + break; + case 32: + dbpp = 4; + dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid destination type"); + return; + } + int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp; + final int dprxi = (flipX) ? -dbpp : dbpp; + final int dpryi = (flipY) ? -destStride : destStride; + + /*** Prepare special processing data ***/ + int apr; + if ((op & BLIT_ALPHA) != 0) { + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: + case ALPHA_CHANNEL_SEPARATE: + if (alphaData == null) alphaMode = 0x10000; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_PACKED: + if (alphaData == null) alphaMode = 0x10000; + alphaStride <<= 3; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_INDEX: + //throw new IllegalArgumentException("Invalid alpha type"); + return; + case ALPHA_MASK_RGB: + if (alphaData == null) alphaMode = 0x10000; + apr = 0; + break; + default: + alphaMode = (alphaMode << 16) / 255; // prescale + case ALPHA_CHANNEL_SOURCE: + apr = 0; + break; + } + } else { + alphaMode = 0x10000; + apr = 0; + } + + /*** Blit ***/ + int dp = dpr; + int sp = spr; + if ((alphaMode == 0x10000) && (stype == dtype) && + (srcRedMask == destRedMask) && (srcGreenMask == destGreenMask) && + (srcBlueMask == destBlueMask) && (srcAlphaMask == destAlphaMask)) { + /*** Fast blit (straight copy) ***/ + switch (sbpp) { + case 1: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = srcData[sp]; + sp += (sfx >>> 16); + } + } + break; + case 2: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = srcData[sp]; + destData[dp + 1] = srcData[sp + 1]; + sp += (sfx >>> 16) * 2; + } + } + break; + case 3: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = srcData[sp]; + destData[dp + 1] = srcData[sp + 1]; + destData[dp + 2] = srcData[sp + 2]; + sp += (sfx >>> 16) * 3; + } + } + break; + case 4: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = srcData[sp]; + destData[dp + 1] = srcData[sp + 1]; + destData[dp + 2] = srcData[sp + 2]; + destData[dp + 3] = srcData[sp + 3]; + sp += (sfx >>> 16) * 4; + } + } + break; + } + return; + } + /*Fast 32 to 32 blit */ + if (alphaMode == 0x10000 && stype == TYPE_GENERIC_32_MSB && dtype == TYPE_GENERIC_32_MSB) { + if (srcRedMask == 0xFF00 && srcGreenMask == 0xff0000 && srcBlueMask == 0xff000000 && destRedMask == 0xFF0000 && destGreenMask == 0xff00 && destBlueMask == 0xff) { + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = srcData[sp + 3]; + destData[dp + 1] = srcData[sp + 2]; + destData[dp + 2] = srcData[sp + 1]; + destData[dp + 3] = srcData[sp]; + sp += (sfx >>> 16) * 4; + } + } + return; + } + } + /*Fast 24 to 32 blit */ + if (alphaMode == 0x10000 && stype == TYPE_GENERIC_24 && dtype == TYPE_GENERIC_32_MSB) { + if (srcRedMask == 0xFF && srcGreenMask == 0xff00 && srcBlueMask == 0xff0000 && destRedMask == 0xFF0000 && destGreenMask == 0xff00 && destBlueMask == 0xff) { + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = 0; + destData[dp + 1] = srcData[sp + 2]; + destData[dp + 2] = srcData[sp + 1]; + destData[dp + 3] = srcData[sp]; + sp += (sfx >>> 16) * 3; + } + } + return; + } + } + + /*** Comprehensive blit (apply transformations) ***/ + final int srcRedShift = getChannelShift(srcRedMask); + final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)]; + final int srcGreenShift = getChannelShift(srcGreenMask); + final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)]; + final int srcBlueShift = getChannelShift(srcBlueMask); + final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)]; + final int srcAlphaShift = getChannelShift(srcAlphaMask); + final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)]; + + final int destRedShift = getChannelShift(destRedMask); + final int destRedWidth = getChannelWidth(destRedMask, destRedShift); + final byte[] destReds = ANY_TO_EIGHT[destRedWidth]; + final int destRedPreShift = 8 - destRedWidth; + final int destGreenShift = getChannelShift(destGreenMask); + final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift); + final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth]; + final int destGreenPreShift = 8 - destGreenWidth; + final int destBlueShift = getChannelShift(destBlueMask); + final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift); + final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth]; + final int destBluePreShift = 8 - destBlueWidth; + final int destAlphaShift = getChannelShift(destAlphaMask); + final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift); + final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth]; + final int destAlphaPreShift = 8 - destAlphaWidth; + + int ap = apr, alpha = alphaMode; + int r = 0, g = 0, b = 0, a = 0; + int rq = 0, gq = 0, bq = 0, aq = 0; + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + ap = apr += (sfy >>> 16) * alphaStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_GENERIC_8: { + final int data = srcData[sp] & 0xff; + sp += (sfx >>> 16); + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_MSB: { + final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff); + sp += (sfx >>> 16) * 2; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_LSB: { + final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff); + sp += (sfx >>> 16) * 2; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_24: { + final int data = (( ((srcData[sp] & 0xff) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp + 2] & 0xff); + sp += (sfx >>> 16) * 3; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_MSB: { + final int data = (( (( ((srcData[sp] & 0xff) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp + 2] & 0xff)) << 8) | + (srcData[sp + 3] & 0xff); + sp += (sfx >>> 16) * 4; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_LSB: { + final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) | + (srcData[sp + 2] & 0xff)) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp] & 0xff); + sp += (sfx >>> 16) * 4; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + } + + /*** DO SPECIAL PROCESSING IF REQUIRED ***/ + switch (alphaMode) { + case ALPHA_CHANNEL_SEPARATE: + alpha = ((alphaData[ap] & 0xff) << 16) / 255; + ap += (sfx >> 16); + break; + case ALPHA_CHANNEL_SOURCE: + alpha = (a << 16) / 255; + break; + case ALPHA_MASK_UNPACKED: + alpha = (alphaData[ap] != 0) ? 0x10000 : 0; + ap += (sfx >> 16); + break; + case ALPHA_MASK_PACKED: + alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000; + ap += (sfx >> 16); + break; + case ALPHA_MASK_RGB: + alpha = 0x10000; + for (int i = 0; i < alphaData.length; i += 3) { + if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) { + alpha = 0x0000; + break; + } + } + break; + } + if (alpha != 0x10000) { + if (alpha == 0x0000) continue; + switch (dtype) { + case TYPE_GENERIC_8: { + final int data = destData[dp] & 0xff; + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_MSB: { + final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_LSB: { + final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_24: { + final int data = (( ((destData[dp] & 0xff) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp + 2] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_MSB: { + final int data = (( (( ((destData[dp] & 0xff) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp + 2] & 0xff)) << 8) | + (destData[dp + 3] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_LSB: { + final int data = (( (( ((destData[dp + 3] & 0xff) << 8) | + (destData[dp + 2] & 0xff)) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + } + // Perform alpha blending + a = aq + ((a - aq) * alpha >> 16); + r = rq + ((r - rq) * alpha >> 16); + g = gq + ((g - gq) * alpha >> 16); + b = bq + ((b - bq) * alpha >> 16); + } + + /*** WRITE NEXT PIXEL ***/ + final int data = + (r >>> destRedPreShift << destRedShift) | + (g >>> destGreenPreShift << destGreenShift) | + (b >>> destBluePreShift << destBlueShift) | + (a >>> destAlphaPreShift << destAlphaShift); + switch (dtype) { + case TYPE_GENERIC_8: { + destData[dp] = (byte) data; + } break; + case TYPE_GENERIC_16_MSB: { + destData[dp] = (byte) (data >>> 8); + destData[dp + 1] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_16_LSB: { + destData[dp] = (byte) (data & 0xff); + destData[dp + 1] = (byte) (data >>> 8); + } break; + case TYPE_GENERIC_24: { + destData[dp] = (byte) (data >>> 16); + destData[dp + 1] = (byte) (data >>> 8); + destData[dp + 2] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_32_MSB: { + destData[dp] = (byte) (data >>> 24); + destData[dp + 1] = (byte) (data >>> 16); + destData[dp + 2] = (byte) (data >>> 8); + destData[dp + 3] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_32_LSB: { + destData[dp] = (byte) (data & 0xff); + destData[dp + 1] = (byte) (data >>> 8); + destData[dp + 2] = (byte) (data >>> 16); + destData[dp + 3] = (byte) (data >>> 24); + } break; + } + } + } +} + +/** + * Blits an index palette image into an index palette image. + *+ * Note: The source and destination red, green, and blue + * arrays may be null if no alpha blending or dither is to be + * performed. + *
+ * + * @param op the blitter operation: a combination of BLIT_xxx flags + * (see BLIT_xxx constants) + * @param srcData the source byte array containing image data + * @param srcDepth the source depth: one of 1, 2, 4, 8 + * @param srcStride the source number of bytes per line + * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if srcDepth is not 1 + * @param srcX the top-left x-coord of the source blit region + * @param srcY the top-left y-coord of the source blit region + * @param srcWidth the width of the source blit region + * @param srcHeight the height of the source blit region + * @param srcReds the source palette red component intensities + * @param srcGreens the source palette green component intensities + * @param srcBlues the source palette blue component intensities + * @param alphaMode the alpha blending or mask mode, may be + * an integer 0-255 for global alpha; ignored if BLIT_ALPHA + * not specified in the blitter operations + * (see ALPHA_MODE_xxx constants) + * @param alphaData the alpha blending or mask data, varies depending + * on the value of alphaMode and sometimes ignored + * @param alphaStride the alpha data number of bytes per line + * @param alphaX the top-left x-coord of the alpha blit region + * @param alphaY the top-left y-coord of the alpha blit region + * @param destData the destination byte array containing image data + * @param destDepth the destination depth: one of 1, 2, 4, 8 + * @param destStride the destination number of bytes per line + * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if destDepth is not 1 + * @param destX the top-left x-coord of the destination blit region + * @param destY the top-left y-coord of the destination blit region + * @param destWidth the width of the destination blit region + * @param destHeight the height of the destination blit region + * @param destReds the destination palette red component intensities + * @param destGreens the destination palette green component intensities + * @param destBlues the destination palette blue component intensities + * @param flipX if true the resulting image is flipped along the vertical axis + * @param flipY if true the resulting image is flipped along the horizontal axis + */ +static void blit(int op, + byte[] srcData, int srcDepth, int srcStride, int srcOrder, + int srcX, int srcY, int srcWidth, int srcHeight, + byte[] srcReds, byte[] srcGreens, byte[] srcBlues, + int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY, + byte[] destData, int destDepth, int destStride, int destOrder, + int destX, int destY, int destWidth, int destHeight, + byte[] destReds, byte[] destGreens, byte[] destBlues, + boolean flipX, boolean flipY) { + if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return; + + /*** Prepare scaling data ***/ + final int dwm1 = destWidth - 1; + final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0; + final int dhm1 = destHeight - 1; + final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0; + + /*** Prepare source-related data ***/ + final int stype; + switch (srcDepth) { + case 8: + stype = TYPE_INDEX_8; + break; + case 4: + srcStride <<= 1; + stype = TYPE_INDEX_4; + break; + case 2: + srcStride <<= 2; + stype = TYPE_INDEX_2; + break; + case 1: + srcStride <<= 3; + stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int spr = srcY * srcStride + srcX; + + /*** Prepare destination-related data ***/ + final int dtype; + switch (destDepth) { + case 8: + dtype = TYPE_INDEX_8; + break; + case 4: + destStride <<= 1; + dtype = TYPE_INDEX_4; + break; + case 2: + destStride <<= 2; + dtype = TYPE_INDEX_2; + break; + case 1: + destStride <<= 3; + dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX); + final int dprxi = (flipX) ? -1 : 1; + final int dpryi = (flipY) ? -destStride : destStride; + + /*** Prepare special processing data ***/ + int apr; + if ((op & BLIT_ALPHA) != 0) { + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: + case ALPHA_CHANNEL_SEPARATE: + if (alphaData == null) alphaMode = 0x10000; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_PACKED: + if (alphaData == null) alphaMode = 0x10000; + alphaStride <<= 3; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_INDEX: + case ALPHA_MASK_RGB: + if (alphaData == null) alphaMode = 0x10000; + apr = 0; + break; + default: + alphaMode = (alphaMode << 16) / 255; // prescale + case ALPHA_CHANNEL_SOURCE: + apr = 0; + break; + } + } else { + alphaMode = 0x10000; + apr = 0; + } + final boolean ditherEnabled = (op & BLIT_DITHER) != 0; + + /*** Blit ***/ + int dp = dpr; + int sp = spr; + int ap = apr; + int destPaletteSize = 1 << destDepth; + if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length; + byte[] paletteMapping = null; + boolean isExactPaletteMapping = true; + switch (alphaMode) { + case 0x10000: + /*** If the palettes and formats are equivalent use a one-to-one mapping ***/ + if ((stype == dtype) && + (srcReds == destReds) && (srcGreens == destGreens) && (srcBlues == destBlues)) { + paletteMapping = ONE_TO_ONE_MAPPING; + break; + /*** If palettes have not been supplied, supply a suitable mapping ***/ + } else if ((srcReds == null) || (destReds == null)) { + if (srcDepth <= destDepth) { + paletteMapping = ONE_TO_ONE_MAPPING; + } else { + paletteMapping = new byte[1 << srcDepth]; + int mask = (0xff << destDepth) >>> 8; + for (int i = 0; i < paletteMapping.length; ++i) paletteMapping[i] = (byte)(i & mask); + } + break; + } + case ALPHA_MASK_UNPACKED: + case ALPHA_MASK_PACKED: + case ALPHA_MASK_INDEX: + case ALPHA_MASK_RGB: + /*** Generate a palette mapping ***/ + int srcPaletteSize = 1 << srcDepth; + paletteMapping = new byte[srcPaletteSize]; + if ((srcReds != null) && (srcReds.length < srcPaletteSize)) srcPaletteSize = srcReds.length; + for (int i = 0, r, g, b, index; i < srcPaletteSize; ++i) { + r = srcReds[i] & 0xff; + g = srcGreens[i] & 0xff; + b = srcBlues[i] & 0xff; + index = 0; + int minDistance = 0x7fffffff; + for (int j = 0, dr, dg, db, distance; j < destPaletteSize; ++j) { + dr = (destReds[j] & 0xff) - r; + dg = (destGreens[j] & 0xff) - g; + db = (destBlues[j] & 0xff) - b; + distance = dr * dr + dg * dg + db * db; + if (distance < minDistance) { + index = j; + if (distance == 0) break; + minDistance = distance; + } + } + paletteMapping[i] = (byte)index; + if (minDistance != 0) isExactPaletteMapping = false; + } + break; + } + if ((paletteMapping != null) && (isExactPaletteMapping || ! ditherEnabled)) { + if ((stype == dtype) && (alphaMode == 0x10000)) { + /*** Fast blit (copy w/ mapping) ***/ + switch (stype) { + case TYPE_INDEX_8: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = paletteMapping[srcData[sp] & 0xff]; + sp += (sfx >>> 16); + } + } + break; + case TYPE_INDEX_4: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + final int v; + if ((sp & 1) != 0) v = paletteMapping[srcData[sp >> 1] & 0x0f]; + else v = (srcData[sp >> 1] >>> 4) & 0x0f; + sp += (sfx >>> 16); + if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | v); + else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (v << 4)); + } + } + break; + case TYPE_INDEX_2: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + final int index = paletteMapping[(srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03]; + sp += (sfx >>> 16); + final int shift = 6 - (dp & 3) * 2; + destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift)); + } + } + break; + case TYPE_INDEX_1_MSB: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + final int index = paletteMapping[(srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01]; + sp += (sfx >>> 16); + final int shift = 7 - (dp & 7); + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift)); + } + } + break; + case TYPE_INDEX_1_LSB: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + final int index = paletteMapping[(srcData[sp >> 3] >>> (sp & 7)) & 0x01]; + sp += (sfx >>> 16); + final int shift = dp & 7; + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift)); + } + } + break; + } + } else { + /*** Convert between indexed modes using mapping and mask ***/ + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + int index; + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_INDEX_8: + index = srcData[sp] & 0xff; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_4: + if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f; + else index = (srcData[sp >> 1] >>> 4) & 0x0f; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_2: + index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_MSB: + index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_LSB: + index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01; + sp += (sfx >>> 16); + break; + default: + return; + } + /*** APPLY MASK ***/ + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: { + final byte mask = alphaData[ap]; + ap += (sfx >> 16); + if (mask == 0) continue; + } break; + case ALPHA_MASK_PACKED: { + final int mask = alphaData[ap >> 3] & (1 << (ap & 7)); + ap += (sfx >> 16); + if (mask == 0) continue; + } break; + case ALPHA_MASK_INDEX: { + int i = 0; + while (i < alphaData.length) { + if (index == (alphaData[i] & 0xff)) break; + } + if (i < alphaData.length) continue; + } break; + case ALPHA_MASK_RGB: { + final byte r = srcReds[index], g = srcGreens[index], b = srcBlues[index]; + int i = 0; + while (i < alphaData.length) { + if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) break; + i += 3; + } + if (i < alphaData.length) continue; + } break; + } + index = paletteMapping[index] & 0xff; + + /*** WRITE NEXT PIXEL ***/ + switch (dtype) { + case TYPE_INDEX_8: + destData[dp] = (byte) index; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | index); + else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (index << 4)); + break; + case TYPE_INDEX_2: { + final int shift = 6 - (dp & 3) * 2; + destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift)); + } break; + case TYPE_INDEX_1_MSB: { + final int shift = 7 - (dp & 7); + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift)); + } break; + case TYPE_INDEX_1_LSB: { + final int shift = dp & 7; + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift)); + } break; + } + } + } + } + return; + } + + /*** Comprehensive blit (apply transformations) ***/ + int alpha = alphaMode; + int index = 0; + int indexq = 0; + int lastindex = 0, lastr = -1, lastg = -1, lastb = -1; + final int[] rerr, gerr, berr; + if (ditherEnabled) { + rerr = new int[destWidth + 2]; + gerr = new int[destWidth + 2]; + berr = new int[destWidth + 2]; + } else { + rerr = null; gerr = null; berr = null; + } + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + ap = apr += (sfy >>> 16) * alphaStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + int lrerr = 0, lgerr = 0, lberr = 0; + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_INDEX_8: + index = srcData[sp] & 0xff; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_4: + if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f; + else index = (srcData[sp >> 1] >>> 4) & 0x0f; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_2: + index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_MSB: + index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_LSB: + index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01; + sp += (sfx >>> 16); + break; + } + + /*** DO SPECIAL PROCESSING IF REQUIRED ***/ + int r = srcReds[index] & 0xff, g = srcGreens[index] & 0xff, b = srcBlues[index] & 0xff; + switch (alphaMode) { + case ALPHA_CHANNEL_SEPARATE: + alpha = ((alphaData[ap] & 0xff) << 16) / 255; + ap += (sfx >> 16); + break; + case ALPHA_MASK_UNPACKED: + alpha = (alphaData[ap] != 0) ? 0x10000 : 0; + ap += (sfx >> 16); + break; + case ALPHA_MASK_PACKED: + alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000; + ap += (sfx >> 16); + break; + case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices + int i = 0; + while (i < alphaData.length) { + if (index == (alphaData[i] & 0xff)) break; + } + if (i < alphaData.length) continue; + } break; + case ALPHA_MASK_RGB: { + int i = 0; + while (i < alphaData.length) { + if ((r == (alphaData[i] & 0xff)) && + (g == (alphaData[i + 1] & 0xff)) && + (b == (alphaData[i + 2] & 0xff))) break; + i += 3; + } + if (i < alphaData.length) continue; + } break; + } + if (alpha != 0x10000) { + if (alpha == 0x0000) continue; + switch (dtype) { + case TYPE_INDEX_8: + indexq = destData[dp] & 0xff; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f; + else indexq = (destData[dp >> 1] >>> 4) & 0x0f; + break; + case TYPE_INDEX_2: + indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03; + break; + case TYPE_INDEX_1_MSB: + indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01; + break; + case TYPE_INDEX_1_LSB: + indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01; + break; + } + // Perform alpha blending + final int rq = destReds[indexq] & 0xff; + final int gq = destGreens[indexq] & 0xff; + final int bq = destBlues[indexq] & 0xff; + r = rq + ((r - rq) * alpha >> 16); + g = gq + ((g - gq) * alpha >> 16); + b = bq + ((b - bq) * alpha >> 16); + } + + /*** MAP COLOR TO THE PALETTE ***/ + if (ditherEnabled) { + // Floyd-Steinberg error diffusion + r += rerr[dx] >> 4; + if (r < 0) r = 0; else if (r > 255) r = 255; + g += gerr[dx] >> 4; + if (g < 0) g = 0; else if (g > 255) g = 255; + b += berr[dx] >> 4; + if (b < 0) b = 0; else if (b > 255) b = 255; + rerr[dx] = lrerr; + gerr[dx] = lgerr; + berr[dx] = lberr; + } + if (r != lastr || g != lastg || b != lastb) { + // moving the variable declarations out seems to make the JDK JIT happier... + for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) { + dr = (destReds[j] & 0xff) - r; + dg = (destGreens[j] & 0xff) - g; + db = (destBlues[j] & 0xff) - b; + distance = dr * dr + dg * dg + db * db; + if (distance < minDistance) { + lastindex = j; + if (distance == 0) break; + minDistance = distance; + } + } + lastr = r; lastg = g; lastb = b; + } + if (ditherEnabled) { + // Floyd-Steinberg error diffusion, cont'd... + final int dxm1 = dx - 1, dxp1 = dx + 1; + int acc; + rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr; + rerr[dx] += acc += lrerr + lrerr; + rerr[dxm1] += acc + lrerr + lrerr; + gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr; + gerr[dx] += acc += lgerr + lgerr; + gerr[dxm1] += acc + lgerr + lgerr; + berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr; + berr[dx] += acc += lberr + lberr; + berr[dxm1] += acc + lberr + lberr; + } + + /*** WRITE NEXT PIXEL ***/ + switch (dtype) { + case TYPE_INDEX_8: + destData[dp] = (byte) lastindex; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex); + else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4)); + break; + case TYPE_INDEX_2: { + final int shift = 6 - (dp & 3) * 2; + destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift)); + } break; + case TYPE_INDEX_1_MSB: { + final int shift = 7 - (dp & 7); + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift)); + } break; + case TYPE_INDEX_1_LSB: { + final int shift = dp & 7; + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift)); + } break; + } + } + } +} + +/** + * Blits an index palette image into a direct palette image. + *+ * Note: The source and destination masks and palettes must + * always be fully specified. + *
+ * + * @param op the blitter operation: a combination of BLIT_xxx flags + * (see BLIT_xxx constants) + * @param srcData the source byte array containing image data + * @param srcDepth the source depth: one of 1, 2, 4, 8 + * @param srcStride the source number of bytes per line + * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if srcDepth is not 1 + * @param srcX the top-left x-coord of the source blit region + * @param srcY the top-left y-coord of the source blit region + * @param srcWidth the width of the source blit region + * @param srcHeight the height of the source blit region + * @param srcReds the source palette red component intensities + * @param srcGreens the source palette green component intensities + * @param srcBlues the source palette blue component intensities + * @param alphaMode the alpha blending or mask mode, may be + * an integer 0-255 for global alpha; ignored if BLIT_ALPHA + * not specified in the blitter operations + * (see ALPHA_MODE_xxx constants) + * @param alphaData the alpha blending or mask data, varies depending + * on the value of alphaMode and sometimes ignored + * @param alphaStride the alpha data number of bytes per line + * @param alphaX the top-left x-coord of the alpha blit region + * @param alphaY the top-left y-coord of the alpha blit region + * @param destData the destination byte array containing image data + * @param destDepth the destination depth: one of 8, 16, 24, 32 + * @param destStride the destination number of bytes per line + * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if destDepth is not 16 or 32 + * @param destX the top-left x-coord of the destination blit region + * @param destY the top-left y-coord of the destination blit region + * @param destWidth the width of the destination blit region + * @param destHeight the height of the destination blit region + * @param destRedMask the destination red channel mask + * @param destGreenMask the destination green channel mask + * @param destBlueMask the destination blue channel mask + * @param flipX if true the resulting image is flipped along the vertical axis + * @param flipY if true the resulting image is flipped along the horizontal axis + */ +static void blit(int op, + byte[] srcData, int srcDepth, int srcStride, int srcOrder, + int srcX, int srcY, int srcWidth, int srcHeight, + byte[] srcReds, byte[] srcGreens, byte[] srcBlues, + int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY, + byte[] destData, int destDepth, int destStride, int destOrder, + int destX, int destY, int destWidth, int destHeight, + int destRedMask, int destGreenMask, int destBlueMask, + boolean flipX, boolean flipY) { + if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return; + + /*** Fast blit (straight copy) ***/ + if (srcX == 0 && srcY == 0 && destX == 0 && destY == 0 && destWidth == srcWidth && destHeight == srcHeight) { + if (destDepth == 24 && srcDepth == 8 && (op & BLIT_ALPHA) == 0 && destRedMask == 0xFF0000 && destGreenMask == 0xFF00 && destBlueMask == 0xFF) { + for (int y = 0, sp = 0, dp = 0, spad = srcStride - srcWidth, dpad = destStride - (destWidth * 3); y < destHeight; y++, sp += spad, dp += dpad) { + for (int x = 0; x < destWidth; x++) { + int index = srcData[sp++] & 0xff; + destData[dp++] = srcReds[index]; + destData[dp++] = srcGreens[index]; + destData[dp++] = srcBlues[index]; + } + } + return; + } + if (destDepth == 32 && destOrder == MSB_FIRST && srcDepth == 8 && (op & BLIT_ALPHA) == 0 && destRedMask == 0xFF0000 && destGreenMask == 0xFF00 && destBlueMask == 0xFF) { + for (int y = 0, sp = 0, dp = 0, spad = srcStride - srcWidth, dpad = destStride - (destWidth * 4); y < destHeight; y++, sp += spad, dp += dpad) { + for (int x = 0; x < destWidth; x++) { + int index = srcData[sp++] & 0xff; + dp++; + destData[dp++] = srcReds[index]; + destData[dp++] = srcGreens[index]; + destData[dp++] = srcBlues[index]; + } + } + return; + } + } + // these should be supplied as params later + final int destAlphaMask = 0; + + /*** Prepare scaling data ***/ + final int dwm1 = destWidth - 1; + final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0; + final int dhm1 = destHeight - 1; + final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0; + + /*** Prepare source-related data ***/ + final int stype; + switch (srcDepth) { + case 8: + stype = TYPE_INDEX_8; + break; + case 4: + srcStride <<= 1; + stype = TYPE_INDEX_4; + break; + case 2: + srcStride <<= 2; + stype = TYPE_INDEX_2; + break; + case 1: + srcStride <<= 3; + stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int spr = srcY * srcStride + srcX; + + /*** Prepare destination-related data ***/ + final int dbpp, dtype; + switch (destDepth) { + case 8: + dbpp = 1; + dtype = TYPE_GENERIC_8; + break; + case 16: + dbpp = 2; + dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB; + break; + case 24: + dbpp = 3; + dtype = TYPE_GENERIC_24; + break; + case 32: + dbpp = 4; + dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid destination type"); + return; + } + int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp; + final int dprxi = (flipX) ? -dbpp : dbpp; + final int dpryi = (flipY) ? -destStride : destStride; + + /*** Prepare special processing data ***/ + int apr; + if ((op & BLIT_ALPHA) != 0) { + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: + case ALPHA_CHANNEL_SEPARATE: + if (alphaData == null) alphaMode = 0x10000; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_PACKED: + if (alphaData == null) alphaMode = 0x10000; + alphaStride <<= 3; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_INDEX: + case ALPHA_MASK_RGB: + if (alphaData == null) alphaMode = 0x10000; + apr = 0; + break; + default: + alphaMode = (alphaMode << 16) / 255; // prescale + case ALPHA_CHANNEL_SOURCE: + apr = 0; + break; + } + } else { + alphaMode = 0x10000; + apr = 0; + } + + /*** Comprehensive blit (apply transformations) ***/ + final int destRedShift = getChannelShift(destRedMask); + final int destRedWidth = getChannelWidth(destRedMask, destRedShift); + final byte[] destReds = ANY_TO_EIGHT[destRedWidth]; + final int destRedPreShift = 8 - destRedWidth; + final int destGreenShift = getChannelShift(destGreenMask); + final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift); + final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth]; + final int destGreenPreShift = 8 - destGreenWidth; + final int destBlueShift = getChannelShift(destBlueMask); + final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift); + final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth]; + final int destBluePreShift = 8 - destBlueWidth; + final int destAlphaShift = getChannelShift(destAlphaMask); + final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift); + final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth]; + final int destAlphaPreShift = 8 - destAlphaWidth; + + int dp = dpr; + int sp = spr; + int ap = apr, alpha = alphaMode; + int r = 0, g = 0, b = 0, a = 0, index = 0; + int rq = 0, gq = 0, bq = 0, aq = 0; + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + ap = apr += (sfy >>> 16) * alphaStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_INDEX_8: + index = srcData[sp] & 0xff; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_4: + if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f; + else index = (srcData[sp >> 1] >>> 4) & 0x0f; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_2: + index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_MSB: + index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_LSB: + index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01; + sp += (sfx >>> 16); + break; + } + + /*** DO SPECIAL PROCESSING IF REQUIRED ***/ + r = srcReds[index] & 0xff; + g = srcGreens[index] & 0xff; + b = srcBlues[index] & 0xff; + switch (alphaMode) { + case ALPHA_CHANNEL_SEPARATE: + alpha = ((alphaData[ap] & 0xff) << 16) / 255; + ap += (sfx >> 16); + break; + case ALPHA_MASK_UNPACKED: + alpha = (alphaData[ap] != 0) ? 0x10000 : 0; + ap += (sfx >> 16); + break; + case ALPHA_MASK_PACKED: + alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000; + ap += (sfx >> 16); + break; + case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices + int i = 0; + while (i < alphaData.length) { + if (index == (alphaData[i] & 0xff)) break; + } + if (i < alphaData.length) continue; + } break; + case ALPHA_MASK_RGB: { + int i = 0; + while (i < alphaData.length) { + if ((r == (alphaData[i] & 0xff)) && + (g == (alphaData[i + 1] & 0xff)) && + (b == (alphaData[i + 2] & 0xff))) break; + i += 3; + } + if (i < alphaData.length) continue; + } break; + } + if (alpha != 0x10000) { + if (alpha == 0x0000) continue; + switch (dtype) { + case TYPE_GENERIC_8: { + final int data = destData[dp] & 0xff; + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_MSB: { + final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_LSB: { + final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_24: { + final int data = (( ((destData[dp] & 0xff) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp + 2] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_MSB: { + final int data = (( (( ((destData[dp] & 0xff) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp + 2] & 0xff)) << 8) | + (destData[dp + 3] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_LSB: { + final int data = (( (( ((destData[dp + 3] & 0xff) << 8) | + (destData[dp + 2] & 0xff)) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + } + // Perform alpha blending + a = aq + ((a - aq) * alpha >> 16); + r = rq + ((r - rq) * alpha >> 16); + g = gq + ((g - gq) * alpha >> 16); + b = bq + ((b - bq) * alpha >> 16); + } + + /*** WRITE NEXT PIXEL ***/ + final int data = + (r >>> destRedPreShift << destRedShift) | + (g >>> destGreenPreShift << destGreenShift) | + (b >>> destBluePreShift << destBlueShift) | + (a >>> destAlphaPreShift << destAlphaShift); + switch (dtype) { + case TYPE_GENERIC_8: { + destData[dp] = (byte) data; + } break; + case TYPE_GENERIC_16_MSB: { + destData[dp] = (byte) (data >>> 8); + destData[dp + 1] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_16_LSB: { + destData[dp] = (byte) (data & 0xff); + destData[dp + 1] = (byte) (data >>> 8); + } break; + case TYPE_GENERIC_24: { + destData[dp] = (byte) (data >>> 16); + destData[dp + 1] = (byte) (data >>> 8); + destData[dp + 2] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_32_MSB: { + destData[dp] = (byte) (data >>> 24); + destData[dp + 1] = (byte) (data >>> 16); + destData[dp + 2] = (byte) (data >>> 8); + destData[dp + 3] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_32_LSB: { + destData[dp] = (byte) (data & 0xff); + destData[dp + 1] = (byte) (data >>> 8); + destData[dp + 2] = (byte) (data >>> 16); + destData[dp + 3] = (byte) (data >>> 24); + } break; + } + } + } +} + +/** + * Blits a direct palette image into an index palette image. + *+ * Note: The source and destination masks and palettes must + * always be fully specified. + *
+ * + * @param op the blitter operation: a combination of BLIT_xxx flags + * (see BLIT_xxx constants) + * @param srcData the source byte array containing image data + * @param srcDepth the source depth: one of 8, 16, 24, 32 + * @param srcStride the source number of bytes per line + * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if srcDepth is not 16 or 32 + * @param srcX the top-left x-coord of the source blit region + * @param srcY the top-left y-coord of the source blit region + * @param srcWidth the width of the source blit region + * @param srcHeight the height of the source blit region + * @param srcRedMask the source red channel mask + * @param srcGreenMask the source green channel mask + * @param srcBlueMask the source blue channel mask + * @param alphaMode the alpha blending or mask mode, may be + * an integer 0-255 for global alpha; ignored if BLIT_ALPHA + * not specified in the blitter operations + * (see ALPHA_MODE_xxx constants) + * @param alphaData the alpha blending or mask data, varies depending + * on the value of alphaMode and sometimes ignored + * @param alphaStride the alpha data number of bytes per line + * @param alphaX the top-left x-coord of the alpha blit region + * @param alphaY the top-left y-coord of the alpha blit region + * @param destData the destination byte array containing image data + * @param destDepth the destination depth: one of 1, 2, 4, 8 + * @param destStride the destination number of bytes per line + * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if destDepth is not 1 + * @param destX the top-left x-coord of the destination blit region + * @param destY the top-left y-coord of the destination blit region + * @param destWidth the width of the destination blit region + * @param destHeight the height of the destination blit region + * @param destReds the destination palette red component intensities + * @param destGreens the destination palette green component intensities + * @param destBlues the destination palette blue component intensities + * @param flipX if true the resulting image is flipped along the vertical axis + * @param flipY if true the resulting image is flipped along the horizontal axis + */ +static void blit(int op, + byte[] srcData, int srcDepth, int srcStride, int srcOrder, + int srcX, int srcY, int srcWidth, int srcHeight, + int srcRedMask, int srcGreenMask, int srcBlueMask, + int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY, + byte[] destData, int destDepth, int destStride, int destOrder, + int destX, int destY, int destWidth, int destHeight, + byte[] destReds, byte[] destGreens, byte[] destBlues, + boolean flipX, boolean flipY) { + if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return; + + // these should be supplied as params later + final int srcAlphaMask = 0; + + /*** Prepare scaling data ***/ + final int dwm1 = destWidth - 1; + final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0; + final int dhm1 = destHeight - 1; + final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0; + + /*** Prepare source-related data ***/ + final int sbpp, stype; + switch (srcDepth) { + case 8: + sbpp = 1; + stype = TYPE_GENERIC_8; + break; + case 16: + sbpp = 2; + stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB; + break; + case 24: + sbpp = 3; + stype = TYPE_GENERIC_24; + break; + case 32: + sbpp = 4; + stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int spr = srcY * srcStride + srcX * sbpp; + + /*** Prepare destination-related data ***/ + final int dtype; + switch (destDepth) { + case 8: + dtype = TYPE_INDEX_8; + break; + case 4: + destStride <<= 1; + dtype = TYPE_INDEX_4; + break; + case 2: + destStride <<= 2; + dtype = TYPE_INDEX_2; + break; + case 1: + destStride <<= 3; + dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX); + final int dprxi = (flipX) ? -1 : 1; + final int dpryi = (flipY) ? -destStride : destStride; + + /*** Prepare special processing data ***/ + int apr; + if ((op & BLIT_ALPHA) != 0) { + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: + case ALPHA_CHANNEL_SEPARATE: + if (alphaData == null) alphaMode = 0x10000; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_PACKED: + if (alphaData == null) alphaMode = 0x10000; + alphaStride <<= 3; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_INDEX: + //throw new IllegalArgumentException("Invalid alpha type"); + return; + case ALPHA_MASK_RGB: + if (alphaData == null) alphaMode = 0x10000; + apr = 0; + break; + default: + alphaMode = (alphaMode << 16) / 255; // prescale + case ALPHA_CHANNEL_SOURCE: + apr = 0; + break; + } + } else { + alphaMode = 0x10000; + apr = 0; + } + final boolean ditherEnabled = (op & BLIT_DITHER) != 0; + + /*** Comprehensive blit (apply transformations) ***/ + final int srcRedShift = getChannelShift(srcRedMask); + final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)]; + final int srcGreenShift = getChannelShift(srcGreenMask); + final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)]; + final int srcBlueShift = getChannelShift(srcBlueMask); + final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)]; + final int srcAlphaShift = getChannelShift(srcAlphaMask); + final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)]; + + int dp = dpr; + int sp = spr; + int ap = apr, alpha = alphaMode; + int r = 0, g = 0, b = 0, a = 0; + int indexq = 0; + int lastindex = 0, lastr = -1, lastg = -1, lastb = -1; + final int[] rerr, gerr, berr; + int destPaletteSize = 1 << destDepth; + if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length; + if (ditherEnabled) { + rerr = new int[destWidth + 2]; + gerr = new int[destWidth + 2]; + berr = new int[destWidth + 2]; + } else { + rerr = null; gerr = null; berr = null; + } + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + ap = apr += (sfy >>> 16) * alphaStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + int lrerr = 0, lgerr = 0, lberr = 0; + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_GENERIC_8: { + final int data = srcData[sp] & 0xff; + sp += (sfx >>> 16); + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_MSB: { + final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff); + sp += (sfx >>> 16) * 2; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_LSB: { + final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff); + sp += (sfx >>> 16) * 2; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_24: { + final int data = (( ((srcData[sp] & 0xff) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp + 2] & 0xff); + sp += (sfx >>> 16) * 3; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_MSB: { + final int data = (( (( ((srcData[sp] & 0xff) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp + 2] & 0xff)) << 8) | + (srcData[sp + 3] & 0xff); + sp += (sfx >>> 16) * 4; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_LSB: { + final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) | + (srcData[sp + 2] & 0xff)) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp] & 0xff); + sp += (sfx >>> 16) * 4; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + } + + /*** DO SPECIAL PROCESSING IF REQUIRED ***/ + switch (alphaMode) { + case ALPHA_CHANNEL_SEPARATE: + alpha = ((alphaData[ap] & 0xff) << 16) / 255; + ap += (sfx >> 16); + break; + case ALPHA_CHANNEL_SOURCE: + alpha = (a << 16) / 255; + break; + case ALPHA_MASK_UNPACKED: + alpha = (alphaData[ap] != 0) ? 0x10000 : 0; + ap += (sfx >> 16); + break; + case ALPHA_MASK_PACKED: + alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000; + ap += (sfx >> 16); + break; + case ALPHA_MASK_RGB: + alpha = 0x10000; + for (int i = 0; i < alphaData.length; i += 3) { + if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) { + alpha = 0x0000; + break; + } + } + break; + } + if (alpha != 0x10000) { + if (alpha == 0x0000) continue; + switch (dtype) { + case TYPE_INDEX_8: + indexq = destData[dp] & 0xff; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f; + else indexq = (destData[dp >> 1] >>> 4) & 0x0f; + break; + case TYPE_INDEX_2: + indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03; + break; + case TYPE_INDEX_1_MSB: + indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01; + break; + case TYPE_INDEX_1_LSB: + indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01; + break; + } + // Perform alpha blending + final int rq = destReds[indexq] & 0xff; + final int gq = destGreens[indexq] & 0xff; + final int bq = destBlues[indexq] & 0xff; + r = rq + ((r - rq) * alpha >> 16); + g = gq + ((g - gq) * alpha >> 16); + b = bq + ((b - bq) * alpha >> 16); + } + + /*** MAP COLOR TO THE PALETTE ***/ + if (ditherEnabled) { + // Floyd-Steinberg error diffusion + r += rerr[dx] >> 4; + if (r < 0) r = 0; else if (r > 255) r = 255; + g += gerr[dx] >> 4; + if (g < 0) g = 0; else if (g > 255) g = 255; + b += berr[dx] >> 4; + if (b < 0) b = 0; else if (b > 255) b = 255; + rerr[dx] = lrerr; + gerr[dx] = lgerr; + berr[dx] = lberr; + } + if (r != lastr || g != lastg || b != lastb) { + // moving the variable declarations out seems to make the JDK JIT happier... + for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) { + dr = (destReds[j] & 0xff) - r; + dg = (destGreens[j] & 0xff) - g; + db = (destBlues[j] & 0xff) - b; + distance = dr * dr + dg * dg + db * db; + if (distance < minDistance) { + lastindex = j; + if (distance == 0) break; + minDistance = distance; + } + } + lastr = r; lastg = g; lastb = b; + } + if (ditherEnabled) { + // Floyd-Steinberg error diffusion, cont'd... + final int dxm1 = dx - 1, dxp1 = dx + 1; + int acc; + rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr; + rerr[dx] += acc += lrerr + lrerr; + rerr[dxm1] += acc + lrerr + lrerr; + gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr; + gerr[dx] += acc += lgerr + lgerr; + gerr[dxm1] += acc + lgerr + lgerr; + berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr; + berr[dx] += acc += lberr + lberr; + berr[dxm1] += acc + lberr + lberr; + } + + /*** WRITE NEXT PIXEL ***/ + switch (dtype) { + case TYPE_INDEX_8: + destData[dp] = (byte) lastindex; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex); + else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4)); + break; + case TYPE_INDEX_2: { + final int shift = 6 - (dp & 3) * 2; + destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift)); + } break; + case TYPE_INDEX_1_MSB: { + final int shift = 7 - (dp & 7); + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift)); + } break; + case TYPE_INDEX_1_LSB: { + final int shift = dp & 7; + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift)); + } break; + } + } + } +} + +/** + * Computes the required channel shift from a mask. + */ +static int getChannelShift(int mask) { + if (mask == 0) return 0; + int i; + for (i = 0; ((mask & 1) == 0) && (i < 32); ++i) { + mask >>>= 1; + } + return i; +} + +/** + * Computes the required channel width (depth) from a mask. + */ +static int getChannelWidth(int mask, int shift) { + if (mask == 0) return 0; + int i; + mask >>>= shift; + for (i = shift; ((mask & 1) != 0) && (i < 32); ++i) { + mask >>>= 1; + } + return i - shift; +} + +/** + * Extracts a field from packed RGB data given a mask for that field. + */ +static byte getChannelField(int data, int mask) { + final int shift = getChannelShift(mask); + return ANY_TO_EIGHT[getChannelWidth(mask, shift)][(data & mask) >>> shift]; +} + +/** + * Creates an ImageData containing one band's worth of a gradient filled + * block. Ifvertical
is true, the band must be tiled
+ * horizontally to fill a region, otherwise it must be tiled vertically.
+ *
+ * @param width the width of the region to be filled
+ * @param height the height of the region to be filled
+ * @param vertical if true sweeps from top to bottom, else
+ * sweeps from left to right
+ * @param fromRGB the color to start with
+ * @param toRGB the color to end with
+ * @param redBits the number of significant red bits, 0 for palette modes
+ * @param greenBits the number of significant green bits, 0 for palette modes
+ * @param blueBits the number of significant blue bits, 0 for palette modes
+ * @return the new ImageData
+ */
+static ImageData createGradientBand(
+ int width, int height, boolean vertical,
+ RGB fromRGB, RGB toRGB,
+ int redBits, int greenBits, int blueBits) {
+ /* Gradients are drawn as tiled bands */
+ final int bandWidth, bandHeight, bitmapDepth;
+ final byte[] bitmapData;
+ final PaletteData paletteData;
+ /* Select an algorithm depending on the depth of the screen */
+ if (redBits != 0 && greenBits != 0 && blueBits != 0) {
+ paletteData = new PaletteData(0x0000ff00, 0x00ff0000, 0xff000000);
+ bitmapDepth = 32;
+ if (redBits >= 8 && greenBits >= 8 && blueBits >= 8) {
+ /* Precise color */
+ final int steps;
+ if (vertical) {
+ bandWidth = 1;
+ bandHeight = height;
+ steps = bandHeight > 1 ? bandHeight - 1 : 1;
+ } else {
+ bandWidth = width;
+ bandHeight = 1;
+ steps = bandWidth > 1 ? bandWidth - 1 : 1;
+ }
+ final int bytesPerLine = bandWidth * 4;
+ bitmapData = new byte[bandHeight * bytesPerLine];
+ buildPreciseGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine);
+ buildPreciseGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine);
+ buildPreciseGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine);
+ } else {
+ /* Dithered color */
+ final int steps;
+ if (vertical) {
+ bandWidth = (width < 8) ? width : 8;
+ bandHeight = height;
+ steps = bandHeight > 1 ? bandHeight - 1 : 1;
+ } else {
+ bandWidth = width;
+ bandHeight = (height < 8) ? height : 8;
+ steps = bandWidth > 1 ? bandWidth - 1 : 1;
+ }
+ final int bytesPerLine = bandWidth * 4;
+ bitmapData = new byte[bandHeight * bytesPerLine];
+ buildDitheredGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine, blueBits);
+ buildDitheredGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine, greenBits);
+ buildDitheredGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine, redBits);
+ }
+ } else {
+ /* Dithered two tone */
+ paletteData = new PaletteData(fromRGB, toRGB);
+ bitmapDepth = 8;
+ final int blendi;
+ if (vertical) {
+ bandWidth = (width < 8) ? width : 8;
+ bandHeight = height;
+ blendi = (bandHeight > 1) ? 0x1040000 / (bandHeight - 1) + 1 : 1;
+ } else {
+ bandWidth = width;
+ bandHeight = (height < 8) ? height : 8;
+ blendi = (bandWidth > 1) ? 0x1040000 / (bandWidth - 1) + 1 : 1;
+ }
+ final int bytesPerLine = (bandWidth + 3) & -4;
+ bitmapData = new byte[bandHeight * bytesPerLine];
+ if (vertical) {
+ for (int dy = 0, blend = 0, dp = 0; dy < bandHeight;
+ ++dy, blend += blendi, dp += bytesPerLine) {
+ for (int dx = 0; dx < bandWidth; ++dx) {
+ bitmapData[dp + dx] = (blend + DITHER_MATRIX[dy & 7][dx]) <
+ 0x1000000 ? (byte)0 : (byte)1;
+ }
+ }
+ } else {
+ for (int dx = 0, blend = 0; dx < bandWidth; ++dx, blend += blendi) {
+ for (int dy = 0, dptr = dx; dy < bandHeight; ++dy, dptr += bytesPerLine) {
+ bitmapData[dptr] = (blend + DITHER_MATRIX[dy][dx & 7]) <
+ 0x1000000 ? (byte)0 : (byte)1;
+ }
+ }
+ }
+ }
+ return new ImageData(bandWidth, bandHeight, bitmapDepth, paletteData, 4, bitmapData);
+}
+
+/*
+ * Fill in gradated values for a color channel
+ */
+static void buildPreciseGradientChannel(int from, int to, int steps,
+ int bandWidth, int bandHeight, boolean vertical,
+ byte[] bitmapData, int dp, int bytesPerLine) {
+ int val = from << 16;
+ final int inc = ((to << 16) - val) / steps + 1;
+ if (vertical) {
+ for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
+ bitmapData[dp] = (byte)(val >>> 16);
+ val += inc;
+ }
+ } else {
+ for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
+ bitmapData[dp] = (byte)(val >>> 16);
+ val += inc;
+ }
+ }
+}
+
+/*
+ * Fill in dithered gradated values for a color channel
+ */
+static void buildDitheredGradientChannel(int from, int to, int steps,
+ int bandWidth, int bandHeight, boolean vertical,
+ byte[] bitmapData, int dp, int bytesPerLine, int bits) {
+ final int mask = 0xff00 >>> bits;
+ int val = from << 16;
+ final int inc = ((to << 16) - val) / steps + 1;
+ if (vertical) {
+ for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
+ for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) {
+ final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits;
+ int temp = val + thresh;
+ if (temp > 0xffffff) bitmapData[dptr] = -1;
+ else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
+ }
+ val += inc;
+ }
+ } else {
+ for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
+ for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) {
+ final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits;
+ int temp = val + thresh;
+ if (temp > 0xffffff) bitmapData[dptr] = -1;
+ else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
+ }
+ val += inc;
+ }
+ }
+}
+
+/**
+ * Renders a gradient onto a GC.
+ * + * This is a GC helper. + *
+ * + * @param gc the GC to render the gradient onto + * @param device the device the GC belongs to + * @param x the top-left x coordinate of the region to be filled + * @param y the top-left y coordinate of the region to be filled + * @param width the width of the region to be filled + * @param height the height of the region to be filled + * @param vertical if true sweeps from top to bottom, else + * sweeps from left to right + * @param fromRGB the color to start with + * @param toRGB the color to end with + * @param redBits the number of significant red bits, 0 for palette modes + * @param greenBits the number of significant green bits, 0 for palette modes + * @param blueBits the number of significant blue bits, 0 for palette modes + */ +static void fillGradientRectangle(GC gc, Device device, + int x, int y, int width, int height, boolean vertical, + RGB fromRGB, RGB toRGB, + int redBits, int greenBits, int blueBits) { + /* Create the bitmap and tile it */ + ImageData band = createGradientBand(width, height, vertical, + fromRGB, toRGB, redBits, greenBits, blueBits); + Image image = new Image(device, band); + if ((band.width == 1) || (band.height == 1)) { + gc.drawImage(image, 0, 0, DPIUtil.autoScaleDown(band.width), DPIUtil.autoScaleDown(band.height), + DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(y), DPIUtil.autoScaleDown(width), + DPIUtil.autoScaleDown(height)); + } else { + if (vertical) { + for (int dx = 0; dx < width; dx += band.width) { + int blitWidth = width - dx; + if (blitWidth > band.width) blitWidth = band.width; + gc.drawImage(image, 0, 0, DPIUtil.autoScaleDown(blitWidth), DPIUtil.autoScaleDown(band.height), + DPIUtil.autoScaleDown(dx + x), DPIUtil.autoScaleDown(y), DPIUtil.autoScaleDown(blitWidth), + DPIUtil.autoScaleDown(band.height)); + } + } else { + for (int dy = 0; dy < height; dy += band.height) { + int blitHeight = height - dy; + if (blitHeight > band.height) blitHeight = band.height; + gc.drawImage(image, 0, 0, DPIUtil.autoScaleDown(band.width), DPIUtil.autoScaleDown(blitHeight), + DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(dy + y), DPIUtil.autoScaleDown(band.width), + DPIUtil.autoScaleDown(blitHeight)); + } + } + } + image.dispose(); +} + +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageDataLoader.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageDataLoader.java new file mode 100644 index 000000000..b1fe23d24 --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageDataLoader.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import java.io.*; + +/** + * Internal class that separates ImageData from ImageLoader + * to allow removal of ImageLoader from the toolkit. + */ +class ImageDataLoader { + + public static ImageData[] load(InputStream stream) { + return new ImageLoader().load(stream); + } + + public static ImageData[] load(String filename) { + return new ImageLoader().load(filename); + } + +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageDataProvider.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageDataProvider.java new file mode 100644 index 000000000..bfa0ec70a --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageDataProvider.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2018 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +/** + * Interface to provide a callback mechanism to get information about images + * when the application is moved from a low DPI monitor to a high DPI monitor. + * This provides API which will be called by SWT during the image rendering. + * + * This interface needs to be implemented by client code to provide the + * image information on demand. + * + * @since 3.104 + */ +public interface ImageDataProvider { + + + /** + * Returns the image data for the given zoom level. + *
+ * If no image is available for a particular zoom level, this method should
+ * return null
. For zoom == 100
, returning
+ * null
is not allowed, and SWT will throw an exception.
+ *
+ * @param zoom
+ * The zoom level in % of the standard resolution (which is 1
+ * physical monitor pixel == 1 SWT logical point). Typically 100,
+ * 150, or 200.
+ * @return the image data, or null
if zoom != 100
+ * and no image is available for the given zoom level.
+ * @since 3.104
+ */
+ ImageData getImageData (int zoom);
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageFileNameProvider.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageFileNameProvider.java
new file mode 100644
index 000000000..2413cda32
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageFileNameProvider.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+/**
+ * Interface to provide a callback mechanism to get information about images
+ * when the application is moved from a low DPI monitor to a high DPI monitor.
+ * This provides API which will be called by SWT during the image rendering.
+ *
+ * This interface needs to be implemented by client code to provide the
+ * image information on demand.
+ *
+ * @since 3.104
+ */
+public interface ImageFileNameProvider {
+
+ /**
+ * Returns the image filePath for the given zoom level.
+ *
+ * If no image is available for a particular zoom level, this method should
+ * return null
. For zoom == 100
, returning
+ * null
is not allowed, and SWT will throw an exception.
+ *
+ * @param zoom
+ * The zoom level in % of the standard resolution (which is 1
+ * physical monitor pixel == 1 SWT logical point). Typically 100,
+ * 150, or 200.
+ * @return the image filePath, or null
if
+ * zoom != 100
and no image is available for the given
+ * zoom level.
+ * @since 3.104
+ */
+ String getImagePath (int zoom);
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageLoader.java
new file mode 100644
index 000000000..bbe5ac8d5
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageLoader.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import java.io.*;
+import java.util.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.image.*;
+
+/**
+ * Instances of this class are used to load images from,
+ * and save images to, a file or stream.
+ *
+ * Currently supported image formats are: + *
ImageLoaders
can be used to:
+ *
+ * NOTE: ImageLoader
is implemented in Java on some platforms, which has
+ * certain performance implications. Performance and memory sensitive applications may
+ * benefit from using one of the constructors provided by Image
, as these
+ * are implemented natively.
+ * When saving jpeg files, the value is from 1 to 100, + * where 1 is very high compression but low quality, and 100 is + * no compression and high quality; default is 75. + *
+ * When saving png files, the value is from 0 to 3, but they do not impact the quality + * because PNG is lossless compression. 0 is uncompressed, 1 is low compression and fast, + * 2 is default compression, and 3 is high compression but slow. + *
+ * + * @since 3.8 + */ + public int compression; + + /* + * the set of ImageLoader event listeners, created on demand + */ + ListimageLoaderListeners
field.
+ */
+void reset() {
+ data = null;
+ logicalScreenWidth = 0;
+ logicalScreenHeight = 0;
+ backgroundPixel = -1;
+ repeatCount = 1;
+ compression = -1;
+}
+
+/**
+ * Loads an array of ImageData
objects from the
+ * specified input stream. Throws an error if either an error
+ * occurs while loading the images, or if the images are not
+ * of a supported type. Returns the loaded image data array.
+ *
+ * @param stream the input stream to load the images from
+ * @return an array of ImageData
objects loaded from the specified input stream
+ *
+ * @exception IllegalArgumentException ImageData
objects from the
+ * file with the specified name. Throws an error if either
+ * an error occurs while loading the images, or if the images are
+ * not of a supported type. Returns the loaded image data array.
+ *
+ * @param filename the name of the file to load the images from
+ * @return an array of ImageData
objects loaded from the specified file
+ *
+ * @exception IllegalArgumentException IMAGE_BMP
IMAGE_BMP_RLE
IMAGE_GIF
IMAGE_ICO
IMAGE_JPEG
IMAGE_PNG
IMAGE_BMP
IMAGE_BMP_RLE
IMAGE_GIF
IMAGE_ICO
IMAGE_JPEG
IMAGE_PNG
+ * An ImageLoaderListener should be added before invoking
+ * one of the receiver's load methods. The listener's
+ * imageDataLoaded
method is called when image
+ * data has been partially loaded, as is supported by interlaced
+ * GIF/PNG or progressive JPEG images.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
true
if the receiver has image loader
+ * listeners, and false
otherwise.
+ *
+ * @return true
if there are ImageLoaderListener
s, and false
otherwise
+ *
+ * @see #addImageLoaderListener(ImageLoaderListener)
+ * @see #removeImageLoaderListener(ImageLoaderListener)
+ */
+public boolean hasListeners() {
+ return imageLoaderListeners != null && imageLoaderListeners.size() > 0;
+}
+
+/**
+ * Notifies all image loader listeners that an image loader event
+ * has occurred. Pass the specified event object to each listener.
+ *
+ * @param event the ImageLoaderEvent
to send to each ImageLoaderListener
+ */
+public void notifyListeners(ImageLoaderEvent event) {
+ if (!hasListeners()) return;
+ int size = imageLoaderListeners.size();
+ for (int i = 0; i < size; i++) {
+ ImageLoaderListener listener = imageLoaderListeners.get(i);
+ listener.imageDataLoaded(event);
+ }
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageLoaderEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageLoaderEvent.java
new file mode 100644
index 000000000..64a9fbe02
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageLoaderEvent.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import java.util.*;
+
+/**
+ * Instances of this class are sent as a result of the incremental
+ * loading of image data.
+ * + * Notes: + *
endOfImage
flag in the event will be set to true
+ * after each individual image is loaded.endOfImage
flag is false, then this is a
+ * partially complete copy of the current ImageData
,
+ * otherwise this is a completely loaded ImageData
+ */
+ public ImageData imageData;
+
+ /**
+ * the zero-based count of image data increments -- this is
+ * equivalent to the number of events that have been generated
+ * while loading a particular image
+ */
+ public int incrementCount;
+
+ /**
+ * If this flag is true, then the current image data has been
+ * completely loaded, otherwise the image data is only partially
+ * loaded, and further ImageLoader events will occur unless an
+ * exception is thrown
+ */
+ public boolean endOfImage;
+
+ static final long serialVersionUID = 3257284738325558065L;
+
+/**
+ * Constructs a new instance of this class given the event source and
+ * the values to store in its fields.
+ *
+ * @param source the ImageLoader that was loading when the event occurred
+ * @param imageData the image data for the event
+ * @param incrementCount the image data increment for the event
+ * @param endOfImage the end of image flag for the event
+ */
+public ImageLoaderEvent(ImageLoader source, ImageData imageData, int incrementCount, boolean endOfImage) {
+ super(source);
+ this.imageData = imageData;
+ this.incrementCount = incrementCount;
+ this.endOfImage = endOfImage;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString () {
+ return "ImageLoaderEvent {source=" + source + " imageData=" + imageData + " incrementCount=" + incrementCount + " endOfImage=" + endOfImage + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageLoaderListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageLoaderListener.java
new file mode 100644
index 000000000..6a38575d0
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/ImageLoaderListener.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.*;
+
+/**
+ * Classes which implement this interface provide methods
+ * that deal with the incremental loading of image data.
+ *
+ * After creating an instance of a class that implements
+ * this interface it can be added to an image loader using the
+ * addImageLoaderListener
method and removed using
+ * the removeImageLoaderListener
method. When
+ * image data is either partially or completely loaded, this
+ * method will be invoked.
+ *
+ * The timing of when this method is called varies depending on + * the format of the image being loaded. + *
+ * + * @param e an event containing information about the image loading operation + */ +void imageDataLoaded(ImageLoaderEvent e); + +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/LineAttributes.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/LineAttributes.java new file mode 100644 index 000000000..43586cb8b --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/LineAttributes.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import org.eclipse.swt.*; + +/** + *LineAttributes
defines a set of line attributes that
+ * can be modified in a GC.
+ *
+ * Application code does not need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no dispose()
method is provided.
+ *
true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof LineAttributes)) return false;
+ LineAttributes p = (LineAttributes)object;
+ if (p.width != width) return false;
+ if (p.cap != cap) return false;
+ if (p.join != join) return false;
+ if (p.style != style) return false;
+ if (p.dashOffset != dashOffset) return false;
+ if (p.miterLimit != miterLimit) return false;
+ if (p.dash != null && dash != null) {
+ if (p.dash.length != dash.length) return false;
+ for (int i = 0; i < dash.length; i++) {
+ if (p.dash[i] != dash[i]) return false;
+ }
+ } else {
+ if (p.dash != null || dash != null) return false;
+ }
+ return true;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+@Override
+public int hashCode () {
+ int hashCode = Float.floatToIntBits(width);
+ hashCode = 31 * hashCode + cap;
+ hashCode = 31 * hashCode + join;
+ hashCode = 31 * hashCode + style;
+ hashCode = 31 * hashCode + Float.floatToIntBits(dashOffset);
+ hashCode = 31 * hashCode + Float.floatToIntBits(miterLimit);
+ if (dash != null) {
+ for (int i = 0; i < dash.length; i++) {
+ hashCode = 31 * hashCode + Float.floatToIntBits(dash[i]);
+ }
+ }
+ return hashCode;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/PaletteData.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/PaletteData.java
new file mode 100644
index 000000000..faabb4e86
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/PaletteData.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel + * Depending on the depth of the image, the PaletteData can take one + * of two forms, indicated by the isDirect field: + *
+ *false
, this palette is an indexed
+ * palette which maps pixel values to RGBs. The actual RGB values
+ * may be retrieved by using the getRGBs() method.
+ * true
, this palette is a direct color
+ * palette. Instead of containing RGB values, it contains red,
+ * green and blue mask and shift information which indicates how
+ * the color components may be extracted from a given pixel.
+ * This means that the RGB value is actually encoded in the pixel value.
+ * + * In this case, the shift data is the number of bits required to shift + * the RGB value to the left in order to align the high bit of the + * corresponding mask with the high bit of the first byte. This number + * may be negative, so care must be taken when shifting. For example, + * with a red mask of 0xFF0000, the red shift would be -16. With a red + * mask of 0x1F, the red shift would be 3. + *
+ *RGB
s for the palette
+ *
+ * @exception IllegalArgumentException RGB
.
+ *
+ * @param rgb the RGB to get the pixel value for
+ * @return the pixel value for the given RGB
+ *
+ * @exception IllegalArgumentException RGB
corresponding to the given pixel value.
+ *
+ * @param pixel the pixel to get the RGB value for
+ * @return the RGB value for the given pixel
+ *
+ * @exception IllegalArgumentException RGB
s for the receiver or null
+ */
+public RGB[] getRGBs() {
+ return colors;
+}
+
+/**
+ * Computes the shift value for a given mask.
+ *
+ * @param mask the mask to compute the shift for
+ * @return the shift amount
+ *
+ * @see PaletteData
+ */
+int shiftForMask(int mask) {
+ for (int i = 31; i >= 0; i--) {
+ if (((mask >> i) & 0x1) != 0) return 7 - i;
+ }
+ return 32;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Path.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Path.java
new file mode 100644
index 000000000..249c409c5
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Path.java
@@ -0,0 +1,688 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent paths through the two-dimensional
+ * coordinate system. Paths do not have to be continuous, and can be
+ * described using lines, rectangles, arcs, cubic or quadratic bezier curves,
+ * glyphs, or other paths.
+ *
+ * Application code must explicitly invoke the Path.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ *
+ * This class requires the operating system's advanced graphics subsystem + * which may not be available on some platforms. + *
+ * + * @see Path, Pattern snippets + * @see SWT Example: GraphicsExample + * @see Sample code and further information + * + * @since 3.1 + */ +public class Path extends Resource { + + /** + * the OS resource for the Path + * (Warning: This field is platform dependent) + *+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public long handle; + + PointF currentPoint = new PointF(), startPoint = new PointF(); + +/** + * Constructs a new empty Path. + *+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ *+ * You must dispose the path when it is no longer required. + *
+ * + * @param device the device on which to allocate the path + * + * @exception IllegalArgumentExceptionpath
. If
+ * flatness
is less than or equal to zero, an unflatten
+ * copy of the path is created. Otherwise, it specifies the maximum
+ * error between the path and its flatten copy. Smaller numbers give
+ * better approximation.
+ * + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ *+ * You must dispose the path when it is no longer required. + *
+ * + * @param device the device on which to allocate the path + * @param path the path to make a copy + * @param flatness the flatness value + * + * @exception IllegalArgumentException+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ *+ * You must dispose the path when it is no longer required. + *
+ * + * @param device the device on which to allocate the path + * @param data the data for the path + * + * @exception IllegalArgumentException
+ * The resulting arc begins at startAngle
and extends
+ * for arcAngle
degrees.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ *
+ * The center of the arc is the center of the rectangle whose origin
+ * is (x
, y
) and whose size is specified by the
+ * width
and height
arguments.
+ *
+ * The resulting arc covers an area width + 1
points wide
+ * by height + 1
points tall.
+ *
true
if the specified point is contained by
+ * the receiver and false otherwise.
+ *
+ * If outline is true
, the point (x, y) checked for containment in
+ * the receiver's outline. If outline is false
, the point is
+ * checked to see if it is contained within the bounds of the (closed) area
+ * covered by the receiver.
+ *
+ * @param x the x coordinate of the point to test for containment
+ * @param y the y coordinate of the point to test for containment
+ * @param gc the GC to use when testing for containment
+ * @param outline controls whether to check the outline or contained area of the path
+ * @return true
if the path contains the point and false
otherwise
+ *
+ * @exception IllegalArgumentException
true
if the Path has been disposed,
+ * and false
otherwise.
+ *
+ * This method gets the dispose state for the Path.
+ * When a Path has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the Path.
+ *
+ * @return true
when the Path is disposed, and false
otherwise
+ */
+@Override
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Sets the current point of the receiver to the point
+ * specified by (x, y). Note that this starts a new
+ * sub path.
+ *
+ * @param x the x coordinate of the new end point
+ * @param y the y coordinate of the new end point
+ *
+ * @exception SWTException
+ * Application code must explicitly invoke the Pattern.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ *
+ * This class requires the operating system's advanced graphics subsystem + * which may not be available on some platforms. + *
+ * + * @see Path, Pattern snippets + * @see SWT Example: GraphicsExample + * @see Sample code and further information + * + * @since 3.1 + */ +public class Pattern extends Resource { + + /** + * the OS resource for the Pattern + * (Warning: This field is platform dependent) + *+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public long handle; + +/** + * Constructs a new Pattern given an image. Drawing with the resulting + * pattern will cause the image to be tiled over the resulting area. + *+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ *+ * You must dispose the pattern when it is no longer required. + *
+ * + * @param device the device on which to allocate the pattern + * @param image the image that the pattern will draw + * + * @exception IllegalArgumentException+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ *+ * You must dispose the pattern when it is no longer required. + *
+ * + * @param device the device on which to allocate the pattern + * @param x1 the x coordinate of the starting corner of the gradient + * @param y1 the y coordinate of the starting corner of the gradient + * @param x2 the x coordinate of the ending corner of the gradient + * @param y2 the y coordinate of the ending corner of the gradient + * @param color1 the starting color of the gradient + * @param color2 the ending color of the gradient + * + * @exception IllegalArgumentException+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ *+ * You must dispose the pattern when it is no longer required. + *
+ * + * @param device the device on which to allocate the pattern + * @param x1 the x coordinate of the starting corner of the gradient + * @param y1 the y coordinate of the starting corner of the gradient + * @param x2 the x coordinate of the ending corner of the gradient + * @param y2 the y coordinate of the ending corner of the gradient + * @param color1 the starting color of the gradient + * @param alpha1 the starting alpha value of the gradient + * @param color2 the ending color of the gradient + * @param alpha2 the ending alpha value of the gradient + * + * @exception IllegalArgumentExceptiontrue
if the Pattern has been disposed,
+ * and false
otherwise.
+ *
+ * This method gets the dispose state for the Pattern.
+ * When a Pattern has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the Pattern.
+ *
+ * @return true
when the Pattern is disposed, and false
otherwise
+ */
+@Override
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+@Override
+public String toString() {
+ if (isDisposed()) return "Pattern {*DISPOSED*}";
+ return "Pattern {" + handle + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Point.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Point.java
new file mode 100644
index 000000000..141c1fed9
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Point.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import java.io.*;
+
+/**
+ * Instances of this class represent places on the (x, y)
+ * coordinate plane.
+ *
+ * The coordinate space for rectangles and points is considered + * to have increasing values downward and to the right from its + * origin making this the normal, computer graphics oriented notion + * of (x, y) coordinates rather than the strict mathematical one. + *
+ *+ * The hashCode() method in this class uses the values of the public + * fields to compute the hash value. When storing instances of the + * class in hashed collections, do not modify these fields after the + * object has been inserted. + *
+ *
+ * Application code does not need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no dispose()
method is provided.
+ *
true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Point)) return false;
+ Point p = (Point)object;
+ return (p.x == this.x) && (p.y == this.y);
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+@Override
+public int hashCode () {
+ return x ^ y;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the point
+ */
+@Override
+public String toString () {
+ return "Point {" + x + ", " + y + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+}
+
+}
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/RGB.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/RGB.java
new file mode 100644
index 000000000..ebcb2d7c0
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/RGB.java
@@ -0,0 +1,238 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2013 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class are descriptions of colors in
+ * terms of the primary additive color model (red, green and
+ * blue). A color may be described in terms of the relative
+ * intensities of these three primary colors. The brightness
+ * of each color is specified by a value in the range 0 to 255,
+ * where 0 indicates no color (blackness) and 255 indicates
+ * maximum intensity.
+ * + * The hashCode() method in this class uses the values of the public + * fields to compute the hash value. When storing instances of the + * class in hashed collections, do not modify these fields after the + * object has been inserted. + *
+ *
+ * Application code does not need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no dispose()
method is provided.
+ *
true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals(Object object) {
+ if (object == this) return true;
+ if (!(object instanceof RGB)) return false;
+ RGB rgb = (RGB)object;
+ return (rgb.red == this.red) && (rgb.green == this.green) && (rgb.blue == this.blue);
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+@Override
+public int hashCode() {
+ return (blue << 16) | (green << 8) | red;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the RGB
+ */
+@Override
+public String toString() {
+ return "RGB {" + red + ", " + green + ", " + blue + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/RGBA.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/RGBA.java
new file mode 100644
index 000000000..24d043127
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/RGBA.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class are descriptions of colors in
+ * terms of the primary additive color model (red, green, blue
+ * and alpha). A color may be described in terms of the relative
+ * intensities of these three primary colors. The brightness
+ * of each color is specified by a value in the range 0 to 255,
+ * where 0 indicates no color (blackness) and 255 indicates
+ * maximum intensity and for alpha 0 indicates transparent and
+ * 255 indicates opaque.
+ * + * The hashCode() method in this class uses the values of the public + * fields to compute the hash value. When storing instances of the + * class in hashed collections, do not modify these fields after the + * object has been inserted. + *
+ *
+ * Application code does not need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no dispose()
method is provided.
+ *
true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals(Object object) {
+ if (object == this) return true;
+ if (!(object instanceof RGBA)) return false;
+ RGBA rgba = (RGBA)object;
+ return (rgba.rgb.red == this.rgb.red) && (rgba.rgb.green == this.rgb.green) && (rgba.rgb.blue == this.rgb.blue)
+ && (rgba.alpha == this.alpha);
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+@Override
+public int hashCode() {
+ return (alpha << 24) | (rgb.blue << 16) | (rgb.green << 8) | rgb.red;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the RGBA
+ */
+@Override
+public String toString() {
+ return "RGBA {" + rgb.red + ", " + rgb.green + ", " + rgb.blue + ", " + alpha + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Rectangle.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Rectangle.java
new file mode 100644
index 000000000..d6645a795
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Rectangle.java
@@ -0,0 +1,353 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class represent rectangular areas in an
+ * (x, y) coordinate system. The top left corner of the rectangle
+ * is specified by its x and y values, and the extent of the
+ * rectangle is specified by its width and height.
+ * + * The coordinate space for rectangles and points is considered + * to have increasing values downward and to the right from its + * origin making this the normal, computer graphics oriented notion + * of (x, y) coordinates rather than the strict mathematical one. + *
+ *+ * The hashCode() method in this class uses the values of the public + * fields to compute the hash value. When storing instances of the + * class in hashed collections, do not modify these fields after the + * object has been inserted. + *
+ *
+ * Application code does not need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no dispose()
method is provided.
+ *
+ * The union of two rectangles is the smallest single rectangle + * that completely covers both of the areas covered by the two + * given rectangles. + *
+ * + * @param rect the rectangle to merge with the receiver + * + * @exception IllegalArgumentExceptiontrue
if the point specified by the
+ * arguments is inside the area specified by the receiver,
+ * and false
otherwise.
+ *
+ * @param x the x coordinate of the point to test for containment
+ * @param y the y coordinate of the point to test for containment
+ * @return true
if the rectangle contains the point and false
otherwise
+ */
+public boolean contains (int x, int y) {
+ return (x >= this.x) && (y >= this.y) && x < (this.x + width) && y < (this.y + height);
+}
+
+/**
+ * Returns true
if the given point is inside the
+ * area specified by the receiver, and false
+ * otherwise.
+ *
+ * @param pt the point to test for containment
+ * @return true
if the rectangle contains the point and false
otherwise
+ *
+ * @exception IllegalArgumentException true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Rectangle)) return false;
+ Rectangle r = (Rectangle)object;
+ return (r.x == this.x) && (r.y == this.y) && (r.width == this.width) && (r.height == this.height);
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+@Override
+public int hashCode () {
+ return x ^ y ^ width ^ height;
+}
+
+/**
+ * Destructively replaces the x, y, width and height values
+ * in the receiver with ones which represent the intersection of the
+ * rectangles specified by the receiver and the given rectangle.
+ *
+ * @param rect the rectangle to intersect with the receiver
+ *
+ * @exception IllegalArgumentException + * The intersection of two rectangles is the rectangle that + * covers the area which is contained within both rectangles. + *
+ * + * @param rect the rectangle to intersect with the receiver + * @return the intersection of the receiver and the argument + * + * @exception IllegalArgumentExceptiontrue
if the rectangle described by the
+ * arguments intersects with the receiver and false
+ * otherwise.
+ * + * Two rectangles intersect if the area of the rectangle + * representing their intersection is not empty. + *
+ * + * @param x the x coordinate of the origin of the rectangle + * @param y the y coordinate of the origin of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * @returntrue
if the rectangle intersects with the receiver, and false
otherwise
+ *
+ * @exception IllegalArgumentException true
if the given rectangle intersects
+ * with the receiver and false
otherwise.
+ * + * Two rectangles intersect if the area of the rectangle + * representing their intersection is not empty. + *
+ * + * @param rect the rectangle to test for intersection + * @returntrue
if the rectangle intersects with the receiver, and false
otherwise
+ *
+ * @exception IllegalArgumentException true
if the receiver does not cover any
+ * area in the (x, y) coordinate plane, and false
if
+ * the receiver does cover some area in the plane.
+ * + * A rectangle is considered to cover area in the + * (x, y) coordinate plane if both its width and height are + * non-zero. + *
+ * + * @returntrue
if the receiver is empty, and false
otherwise
+ */
+public boolean isEmpty () {
+ return (width <= 0) || (height <= 0);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the rectangle
+ */
+@Override
+public String toString () {
+ return "Rectangle {" + x + ", " + y + ", " + width + ", " + height + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+}
+
+/**
+ * Returns a new rectangle which represents the union of
+ * the receiver and the given rectangle.
+ * + * The union of two rectangles is the smallest single rectangle + * that completely covers both of the areas covered by the two + * given rectangles. + *
+ * + * @param rect the rectangle to perform union with + * @return the union of the receiver and the argument + * + * @exception IllegalArgumentException
+ * Application code must explicitly invoke the Region.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ *
+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public long handle; + +/** + * Constructs a new empty region. + *+ * You must dispose the region when it is no longer required. + *
+ * + * @exception SWTError+ * You must dispose the region when it is no longer required. + *
+ * + * @param device the device on which to allocate the region + * + * @exception IllegalArgumentExceptiontrue
if the point specified by the
+ * arguments is inside the area specified by the receiver,
+ * and false
otherwise.
+ *
+ * @param x the x coordinate of the point to test for containment
+ * @param y the y coordinate of the point to test for containment
+ * @return true
if the region contains the point and false
otherwise
+ *
+ * @exception SWTException true
if the given point is inside the
+ * area specified by the receiver, and false
+ * otherwise.
+ *
+ * @param pt the point to test for containment
+ * @return true
if the region contains the point and false
otherwise
+ *
+ * @exception IllegalArgumentException true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode
+ */
+@Override
+public boolean equals (Object object) {
+ if (this == object) return true;
+ if (!(object instanceof Region)) return false;
+ Region rgn = (Region)object;
+ return handle == rgn.handle;
+}
+
+/**
+ * Returns a rectangle which represents the rectangular
+ * union of the collection of polygons the receiver
+ * maintains to describe its area.
+ *
+ * @return a bounding rectangle for the region
+ *
+ * @exception SWTException true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+@Override
+public int hashCode () {
+ return (int)handle;
+}
+
+/**
+ * Intersects the given rectangle to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param rect the rectangle to intersect with the receiver
+ *
+ * @exception IllegalArgumentException true
if the rectangle described by the
+ * arguments intersects with any of the polygons the receiver
+ * maintains to describe its area, and false
otherwise.
+ *
+ * @param x the x coordinate of the origin of the rectangle
+ * @param y the y coordinate of the origin of the rectangle
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @return true
if the rectangle intersects with the receiver, and false
otherwise
+ *
+ * @exception SWTException true
if the given rectangle intersects
+ * with any of the polygons the receiver maintains to describe
+ * its area and false
otherwise.
+ *
+ * @param rect the rectangle to test for intersection
+ * @return true
if the rectangle intersects with the receiver, and false
otherwise
+ *
+ * @exception IllegalArgumentException true
if the region has been disposed,
+ * and false
otherwise.
+ *
+ * This method gets the dispose state for the region.
+ * When a region has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the region.
+ *
+ * @return true
when the region is disposed, and false
otherwise
+ */
+@Override
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Returns true
if the receiver does not cover any
+ * area in the (x, y) coordinate plane, and false
if
+ * the receiver does cover some area in the plane.
+ *
+ * @return true
if the receiver is empty, and false
otherwise
+ *
+ * @exception SWTException
+ * IMPORTANT: This method is not part of the public
+ * API for Region
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ * IMPORTANT: This class is intended to be subclassed only + * within the SWT implementation. However, it has not been marked + * final to allow those outside of the SWT development team to implement + * patched versions of the class in order to get around specific + * limitations in advance of when those limitations can be addressed + * by the team. Any class built using subclassing to access the internals + * of this class will likely fail to compile or run between releases and + * may be strongly platform specific. Subclassing should not be attempted + * without an intimate and detailed understanding of the workings of the + * hierarchy. No support is provided for user-written classes which are + * implemented as subclasses of this class. + *
+ * + * @see #dispose + * @see #isDisposed + * @see Sample code and further information + * + * @since 3.1 + */ +public abstract class Resource { + + /** + * the device where this resource was created + */ + Device device; + +public Resource() { +} + +Resource(Device device) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; +} + +void destroy() { +} + +/** + * Disposes of the operating system resources associated with + * this resource. Applications must dispose of all resources + * which they allocate. + * This method does nothing if the resource is already disposed. + */ +public void dispose() { + if (device == null) return; + if (device.isDisposed()) return; + destroy(); + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * Returns theDevice
where this resource was
+ * created.
+ *
+ * @return Device
the device of the receiver
+ *
+ * @since 3.2
+ */
+public Device getDevice() {
+ Device device = this.device;
+ if (device == null || isDisposed ()) SWT.error (SWT.ERROR_GRAPHIC_DISPOSED);
+ return device;
+}
+
+void init() {
+ if (device.tracking) device.new_Object(this);
+}
+
+/**
+ * Returns true
if the resource has been disposed,
+ * and false
otherwise.
+ *
+ * This method gets the dispose state for the resource.
+ * When a resource has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the resource.
+ *
+ * @return true
when the resource is disposed and false
otherwise
+ */
+public abstract boolean isDisposed();
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/TextLayout.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/TextLayout.java
new file mode 100644
index 000000000..52778ace8
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/TextLayout.java
@@ -0,0 +1,3776 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import java.util.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * TextLayout
is a graphic object that represents
+ * styled text.
+ *
+ * Instances of this class provide support for drawing, cursor + * navigation, hit testing, text wrapping, alignment, tab expansion + * line breaking, etc. These are aspects required for rendering internationalized text. + *
+ * Application code must explicitly invoke the TextLayout#dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ *
+ * You must dispose the text layout when it is no longer required. + *
+ * + * @param device the device on which to allocate the text layout + * + * @exception IllegalArgumentException
+ * The parameter flags
can include one of SWT.DELIMITER_SELECTION
+ * or SWT.FULL_SELECTION
to specify the selection behavior on all lines except
+ * for the last line, and can also include SWT.LAST_LINE_SELECTION
to extend
+ * the specified selection behavior to the last line.
+ *
SWT.CENTER
or
+ * SWT.RIGHT
.
+ *
+ * @return the alignment used to positioned text horizontally
+ *
+ * @exception SWTException trailing
argument indicates whether the offset
+ * corresponds to the leading or trailing edge of the cluster.
+ *
+ * @param offset the character offset
+ * @param trailing the trailing flag
+ * @return the location of the character offset
+ *
+ * @exception SWTException SWT.MOVEMENT_CHAR
,
+ * SWT.MOVEMENT_CLUSTER
, SWT.MOVEMENT_WORD
,
+ * SWT.MOVEMENT_WORD_END
or SWT.MOVEMENT_WORD_START
.
+ *
+ * @param offset the start offset
+ * @param movement the movement type
+ * @return the next offset
+ *
+ * @exception IllegalArgumentException 1
1
SWT.MOVEMENT_CHAR
,
+ * SWT.MOVEMENT_CLUSTER
or SWT.MOVEMENT_WORD
,
+ * SWT.MOVEMENT_WORD_END
or SWT.MOVEMENT_WORD_START
.
+ *
+ * @param offset the start offset
+ * @param movement the movement type
+ * @return the previous offset
+ *
+ * @exception IllegalArgumentException TextStyle
.
+ *
+ * @return the ranges, an array of offsets representing the start and end of each
+ * text style.
+ *
+ * @exception SWTException null
if not set
+ *
+ * @exception IllegalArgumentException true
if the text layout has been disposed,
+ * and false
otherwise.
+ * + * This method gets the dispose state for the text layout. + * When a text layout has been disposed, it is an error to + * invoke any other method (except {@link #dispose()}) using the text layout. + *
+ * + * @returntrue
when the text layout is disposed and false
otherwise
+ */
+@Override
+public boolean isDisposed () {
+ return device == null;
+}
+
+/*
+ * Itemize the receiver text
+ */
+StyleItem[] itemize () {
+ segmentsText = getSegmentsText();
+ int length = segmentsText.length();
+ SCRIPT_CONTROL scriptControl = new SCRIPT_CONTROL();
+ SCRIPT_STATE scriptState = new SCRIPT_STATE();
+ final int MAX_ITEM = length + 1;
+
+ if ((resolveTextDirection() & SWT.RIGHT_TO_LEFT) != 0) {
+ scriptState.uBidiLevel = 1;
+ scriptState.fArabicNumContext = true;
+ }
+
+ /*
+ * In the version of Usp10.h that SWT is compiled the fReserved field is declared
+ * as a bitfield size 8. In newer versions of the Uniscribe, the first bit of fReserved
+ * was used to implement the fMergeNeutralItems feature which can be used to increase
+ * performance by reducing the number of SCRIPT_ITEM returned by ScriptItemize.
+ *
+ * Note: This code is wrong on a big endian machine.
+ *
+ * Note: This code is intentionally commented because it causes bug#377472.
+ */
+// scriptControl.fReserved = 0x1;
+
+ OS.ScriptApplyDigitSubstitution(null, scriptControl, scriptState);
+
+ long hHeap = OS.GetProcessHeap();
+ long pItems = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof);
+ if (pItems == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int[] pcItems = new int[1];
+ char[] chars = new char[length];
+ segmentsText.getChars(0, length, chars, 0);
+ OS.ScriptItemize(chars, length, MAX_ITEM, scriptControl, scriptState, pItems, pcItems);
+// if (hr == E_OUTOFMEMORY) //TODO handle it
+
+ StyleItem[] runs = merge(pItems, pcItems[0]);
+ OS.HeapFree(hHeap, 0, pItems);
+ return runs;
+}
+
+/*
+ * Merge styles ranges and script items
+ */
+StyleItem[] merge (long items, int itemCount) {
+ if (styles.length > stylesCount) {
+ StyleItem[] newStyles = new StyleItem[stylesCount];
+ System.arraycopy(styles, 0, newStyles, 0, stylesCount);
+ styles = newStyles;
+ }
+ int count = 0, start = 0, end = segmentsText.length(), itemIndex = 0, styleIndex = 0;
+ StyleItem[] runs = new StyleItem[itemCount + stylesCount];
+ SCRIPT_ITEM scriptItem = new SCRIPT_ITEM();
+ int itemLimit = -1;
+ int nextItemIndex = 0;
+ boolean linkBefore = false;
+ boolean merge = itemCount > TOO_MANY_RUNS;
+ SCRIPT_PROPERTIES sp = new SCRIPT_PROPERTIES();
+ while (start < end) {
+ StyleItem item = new StyleItem();
+ item.start = start;
+ item.style = styles[styleIndex].style;
+ runs[count++] = item;
+ OS.MoveMemory(scriptItem, items + itemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ item.analysis = scriptItem.a;
+ scriptItem.a = new SCRIPT_ANALYSIS();
+ if (linkBefore) {
+ item.analysis.fLinkBefore = true;
+ linkBefore = false;
+ }
+ char ch = segmentsText.charAt(start);
+ switch (ch) {
+ case '\r':
+ case '\n':
+ item.lineBreak = true;
+ break;
+ case '\t':
+ item.tab = true;
+ break;
+ }
+ if (itemLimit == -1) {
+ nextItemIndex = itemIndex + 1;
+ OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ itemLimit = scriptItem.iCharPos;
+ if (nextItemIndex < itemCount && ch == '\r' && segmentsText.charAt(itemLimit) == '\n') {
+ nextItemIndex = itemIndex + 2;
+ OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ itemLimit = scriptItem.iCharPos;
+ }
+ if (nextItemIndex < itemCount && merge) {
+ if (!item.lineBreak) {
+ OS.MoveMemory(sp, device.scripts[item.analysis.eScript], SCRIPT_PROPERTIES.sizeof);
+ if (!sp.fComplex || item.tab) {
+ for (int i = 0; i < MERGE_MAX; i++) {
+ if (nextItemIndex == itemCount) break;
+ char c = segmentsText.charAt(itemLimit);
+ if (c == '\n' || c == '\r') break;
+ if (c == '\t' != item.tab) break;
+ OS.MoveMemory(sp, device.scripts[scriptItem.a.eScript], SCRIPT_PROPERTIES.sizeof);
+ if (!item.tab && sp.fComplex) break;
+ nextItemIndex++;
+ OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ itemLimit = scriptItem.iCharPos;
+ }
+ }
+ }
+ }
+ }
+
+ int styleLimit = translateOffset(styles[styleIndex + 1].start);
+ if (styleLimit <= itemLimit) {
+ styleIndex++;
+ start = styleLimit;
+ if (start < itemLimit && 0 < start && start < end) {
+ char pChar = segmentsText.charAt(start - 1);
+ char tChar = segmentsText.charAt(start);
+ if (Character.isLetter(pChar) && Character.isLetter(tChar)) {
+ item.analysis.fLinkAfter = true;
+ linkBefore = true;
+ }
+ }
+ }
+ if (itemLimit <= styleLimit) {
+ itemIndex = nextItemIndex;
+ start = itemLimit;
+ itemLimit = -1;
+ }
+ item.length = start - item.start;
+ }
+ StyleItem item = new StyleItem();
+ item.start = end;
+ OS.MoveMemory(scriptItem, items + itemCount * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ item.analysis = scriptItem.a;
+ runs[count++] = item;
+ if (runs.length != count) {
+ StyleItem[] result = new StyleItem[count];
+ System.arraycopy(runs, 0, result, 0, count);
+ return result;
+ }
+ return runs;
+}
+
+/*
+ * Resolves text direction. If the nominal direction is LTR or RTL, no
+ * resolution is needed; if the nominal direction is "auto", have BidiUtil
+ * resolve it according to the first strong bidi character.
+ */
+int resolveTextDirection () {
+ return textDirection == SWT.AUTO_TEXT_DIRECTION ? BidiUtil.resolveTextDirection (text) : textDirection;
+}
+
+/*
+ * Reorder the run
+ */
+StyleItem[] reorder (StyleItem[] runs, boolean terminate) {
+ int length = runs.length;
+ if (length <= 1) return runs;
+ byte[] bidiLevels = new byte[length];
+ for (int i=0; iSWT.RIGHT
or SWT.CENTER
.
+ *
+ * The default alignment is SWT.LEFT
. Note that the receiver's
+ * width must be set in order to use SWT.RIGHT
or SWT.CENTER
+ * alignment.
+ *
-1
which means that the
+ * ascent is calculated from the line fonts.
+ *
+ * @param ascent the new ascent
+ *
+ * @exception IllegalArgumentException -1
-1
which means that the
+ * descent is calculated from the line fonts.
+ *
+ * @param descent the new descent
+ *
+ * @exception IllegalArgumentException -1
SWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
+ *
+ * @param orientation new orientation style
+ *
+ * @exception SWTException
+ * Each text segment is determined by two consecutive offsets in the
+ * segments
arrays. The first element of the array should
+ * always be zero and the last one should always be equals to length of
+ * the text.
+ *
+ * When segments characters are set, the segments are the offsets where + * the characters are inserted in the text. + *
+ * + * @param segments the text segments offset + * + * @exception SWTException
TextLayout
.
+ *
+ * @param segmentsChars the segments characters
+ *
+ * @exception SWTException + * Note: Setting the text also clears all the styles. This method + * returns without doing anything if the new text is the same as + * the current text. + *
+ * + * @param text the new text + * + * @exception IllegalArgumentExceptionSWT.LEFT_TO_RIGHT
, SWT.RIGHT_TO_LEFT
+ * or SWT.AUTO_TEXT_DIRECTION
.
+ *
+ * + * Warning: This API is currently only implemented on Windows. + * It doesn't set the base text direction on GTK and Cocoa. + *
+ * + * @param textDirection the new text direction + * + * @exception SWTException-1
which means wrapping is disabled.
+ *
+ * @param width the new width
+ *
+ * @exception IllegalArgumentException 0
or less than -1
0
TextStyle
defines a set of styles that can be applied
+ * to a range of text.
+ * + * The hashCode() method in this class uses the values of the public + * fields to compute the hash value. When storing instances of the + * class in hashed collections, do not modify these fields after the + * object has been inserted. + *
+ *
+ * Application code does not need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no dispose()
method is provided.
+ *
SWT.UNDERLINE_SINGLE
.
+ *
+ *
+ * @since 3.1
+ */
+ public boolean underline;
+
+ /**
+ * the underline color of the style
+ *
+ * @since 3.4
+ */
+ public Color underlineColor;
+
+ /**
+ * the underline style. This style is ignored when
+ * underline
is false.
+ *
+ * This value should be one of SWT.UNDERLINE_SINGLE
,
+ * SWT.UNDERLINE_DOUBLE
, SWT.UNDERLINE_ERROR
,
+ * SWT.UNDERLINE_SQUIGGLE
, or SWT.UNDERLINE_LINK
.
+ *
SWT.NONE
.
+ *
+ * This value should be one of SWT.BORDER_SOLID
,
+ * SWT.BORDER_DASH
,SWT.BORDER_DOT
or
+ * SWT.NONE
.
+ *
GlyphMetrics
.
+ *
+ *
+ * @since 3.5
+ */
+ public Object data;
+
+
+/**
+ * Create an empty text style.
+ *
+ * @since 3.4
+ */
+public TextStyle () {
+}
+
+/**
+ * Create a new text style with the specified font, foreground
+ * and background.
+ *
+ * @param font the font of the style, null
if none
+ * @param foreground the foreground color of the style, null
if none
+ * @param background the background color of the style, null
if none
+ */
+public TextStyle (Font font, Color foreground, Color background) {
+ if (font != null && font.isDisposed()) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ if (foreground != null && foreground.isDisposed()) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ if (background != null && background.isDisposed()) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ this.font = font;
+ this.foreground = foreground;
+ this.background = background;
+}
+
+
+/**
+ * Create a new text style from an existing text style.
+ *
+ * @param style the style to copy
+ *
+ * @since 3.4
+ */
+public TextStyle (TextStyle style) {
+ if (style == null) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ font = style.font;
+ foreground = style.foreground;
+ background = style.background;
+ underline = style.underline;
+ underlineColor = style.underlineColor;
+ underlineStyle = style.underlineStyle;
+ strikeout = style.strikeout;
+ strikeoutColor = style.strikeoutColor;
+ borderStyle = style.borderStyle;
+ borderColor = style.borderColor;
+ metrics = style.metrics;
+ rise = style.rise;
+ data = style.data;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the same object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals(Object object) {
+ if (object == this) return true;
+ if (object == null) return false;
+ if (!(object instanceof TextStyle)) return false;
+ TextStyle style = (TextStyle)object;
+ if (foreground != null) {
+ if (!foreground.equals(style.foreground)) return false;
+ } else if (style.foreground != null) return false;
+ if (background != null) {
+ if (!background.equals(style.background)) return false;
+ } else if (style.background != null) return false;
+ if (font != null) {
+ if (!font.equals(style.font)) return false;
+ } else if (style.font != null) return false;
+ if (metrics != null) {
+ if (!metrics.equals(style.metrics)) return false;
+ } else if (style.metrics != null) return false;
+ if (underline != style.underline) return false;
+ if (underlineStyle != style.underlineStyle) return false;
+ if (borderStyle != style.borderStyle) return false;
+ if (strikeout != style.strikeout) return false;
+ if (rise != style.rise) return false;
+ if (underlineColor != null) {
+ if (!underlineColor.equals(style.underlineColor)) return false;
+ } else if (style.underlineColor != null) return false;
+ if (strikeoutColor != null) {
+ if (!strikeoutColor.equals(style.strikeoutColor)) return false;
+ } else if (style.strikeoutColor != null) return false;
+ if (underlineStyle != style.underlineStyle) return false;
+ if (borderColor != null) {
+ if (!borderColor.equals(style.borderColor)) return false;
+ } else if (style.borderColor != null) return false;
+ if (data != null) {
+ if (!data.equals(style.data)) return false;
+ } else if (style.data != null) return false;
+ return true;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+@Override
+public int hashCode() {
+ int hash = 0;
+ if (foreground != null) hash ^= foreground.hashCode();
+ if (background != null) hash ^= background.hashCode();
+ if (font != null) hash ^= font.hashCode();
+ if (metrics != null) hash ^= metrics.hashCode();
+ if (underline) hash ^= (hash << 1);
+ if (strikeout) hash ^= (hash << 2);
+ hash ^= rise;
+ if (underlineColor != null) hash ^= underlineColor.hashCode();
+ if (strikeoutColor != null) hash ^= strikeoutColor.hashCode();
+ if (borderColor != null) hash ^= borderColor.hashCode();
+ hash ^= underlineStyle;
+ return hash;
+}
+
+boolean isAdherentBorder(TextStyle style) {
+ if (this == style) return true;
+ if (style == null) return false;
+ if (borderStyle != style.borderStyle) return false;
+ if (borderColor != null) {
+ if (!borderColor.equals(style.borderColor)) return false;
+ } else {
+ if (style.borderColor != null) return false;
+ if (foreground != null) {
+ if (!foreground.equals(style.foreground)) return false;
+ } else if (style.foreground != null) return false;
+ }
+ return true;
+}
+
+boolean isAdherentUnderline(TextStyle style) {
+ if (this == style) return true;
+ if (style == null) return false;
+ if (underline != style.underline) return false;
+ if (underlineStyle != style.underlineStyle) return false;
+ if (underlineColor != null) {
+ if (!underlineColor.equals(style.underlineColor)) return false;
+ } else {
+ if (style.underlineColor != null) return false;
+ if (foreground != null) {
+ if (!foreground.equals(style.foreground)) return false;
+ } else if (style.foreground != null) return false;
+ }
+ return true;
+}
+
+boolean isAdherentStrikeout(TextStyle style) {
+ if (this == style) return true;
+ if (style == null) return false;
+ if (strikeout != style.strikeout) return false;
+ if (strikeoutColor != null) {
+ if (!strikeoutColor.equals(style.strikeoutColor)) return false;
+ } else {
+ if (style.strikeoutColor != null) return false;
+ if (foreground != null) {
+ if (!foreground.equals(style.foreground)) return false;
+ } else if (style.foreground != null) return false;
+ }
+ return true;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the TextStyle
+ */
+@Override
+public String toString () {
+ StringBuilder buffer = new StringBuilder("TextStyle {"); //$NON-NLS-1$
+ int startLength = buffer.length();
+ if (font != null) {
+ if (buffer.length() > startLength) buffer.append(", "); //$NON-NLS-1$
+ buffer.append("font="); //$NON-NLS-1$
+ buffer.append(font);
+ }
+ if (foreground != null) {
+ if (buffer.length() > startLength) buffer.append(", "); //$NON-NLS-1$
+ buffer.append("foreground="); //$NON-NLS-1$
+ buffer.append(foreground);
+ }
+ if (background != null) {
+ if (buffer.length() > startLength) buffer.append(", "); //$NON-NLS-1$
+ buffer.append("background="); //$NON-NLS-1$
+ buffer.append(background);
+ }
+ if (underline) {
+ if (buffer.length() > startLength) buffer.append(", "); //$NON-NLS-1$
+ buffer.append("underline="); //$NON-NLS-1$
+ switch (underlineStyle) {
+ case SWT.UNDERLINE_SINGLE: buffer.append("single"); break; //$NON-NLS-1$
+ case SWT.UNDERLINE_DOUBLE: buffer.append("double"); break; //$NON-NLS-1$
+ case SWT.UNDERLINE_SQUIGGLE: buffer.append("squiggle"); break; //$NON-NLS-1$
+ case SWT.UNDERLINE_ERROR: buffer.append("error"); break; //$NON-NLS-1$
+ case SWT.UNDERLINE_LINK: buffer.append("link"); break; //$NON-NLS-1$
+ }
+ if (underlineColor != null) {
+ buffer.append(", underlineColor="); //$NON-NLS-1$
+ buffer.append(underlineColor);
+ }
+ }
+ if (strikeout) {
+ if (buffer.length() > startLength) buffer.append(", "); //$NON-NLS-1$
+ buffer.append("striked out"); //$NON-NLS-1$
+ if (strikeoutColor != null) {
+ buffer.append(", strikeoutColor="); //$NON-NLS-1$
+ buffer.append(strikeoutColor);
+ }
+ }
+ if (borderStyle != SWT.NONE) {
+ if (buffer.length() > startLength) buffer.append(", "); //$NON-NLS-1$
+ buffer.append("border="); //$NON-NLS-1$
+ switch (borderStyle) {
+ case SWT.BORDER_SOLID: buffer.append("solid"); break; //$NON-NLS-1$
+ case SWT.BORDER_DOT: buffer.append("dot"); break; //$NON-NLS-1$
+ case SWT.BORDER_DASH: buffer.append("dash"); break; //$NON-NLS-1$
+ }
+ if (borderColor != null) {
+ buffer.append(", borderColor="); //$NON-NLS-1$
+ buffer.append(borderColor);
+ }
+ }
+ if (rise != 0) {
+ if (buffer.length() > startLength) buffer.append(", "); //$NON-NLS-1$
+ buffer.append("rise="); //$NON-NLS-1$
+ buffer.append(rise);
+ }
+ if (metrics != null) {
+ if (buffer.length() > startLength) buffer.append(", "); //$NON-NLS-1$
+ buffer.append("metrics="); //$NON-NLS-1$
+ buffer.append(metrics);
+ }
+ buffer.append("}"); //$NON-NLS-1$
+ return buffer.toString();
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Transform.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Transform.java
new file mode 100644
index 000000000..6e666ba73
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/graphics/Transform.java
@@ -0,0 +1,396 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.gdip.*;
+
+/**
+ * Instances of this class represent transformation matrices for
+ * points expressed as (x, y) pairs of floating point numbers.
+ *
+ * Application code must explicitly invoke the Transform.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ *
+ * This class requires the operating system's advanced graphics subsystem + * which may not be available on some platforms. + *
+ * + * @see SWT Example: GraphicsExample + * @see Sample code and further information + * + * @since 3.1 + */ +public class Transform extends Resource { + + /** + * the OS resource for the Transform + * (Warning: This field is platform dependent) + *+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public long handle; + +/** + * Constructs a new identity Transform. + *+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ *+ * You must dispose the transform when it is no longer required. + *
+ * + * @param device the device on which to allocate the Transform + * + * @exception IllegalArgumentException+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ *+ * You must dispose the transform when it is no longer required. + *
+ * + * @param device the device on which to allocate the Transform + * @param elements an array of floats that describe the transformation matrix + * + * @exception IllegalArgumentException+ * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + *
+ *+ * You must dispose the transform when it is no longer required. + *
+ * + * @param device the device on which to allocate the Transform + * @param m11 the first element of the first row of the matrix + * @param m12 the second element of the first row of the matrix + * @param m21 the first element of the second row of the matrix + * @param m22 the second element of the second row of the matrix + * @param dx the third element of the first row of the matrix + * @param dy the third element of the second row of the matrix + * + * @exception IllegalArgumentExceptiontrue
if the Transform has been disposed,
+ * and false
otherwise.
+ *
+ * This method gets the dispose state for the Transform.
+ * When a Transform has been disposed, it is an error to
+ * invoke any other method (except {@link #dispose()}) using the Transform.
+ *
+ * @return true
when the Transform is disposed, and false
otherwise
+ */
+@Override
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Returns true
if the Transform represents the identity matrix
+ * and false otherwise.
+ *
+ * @return true
if the receiver is an identity Transform, and false
otherwise
+ */
+public boolean isIdentity() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return Gdip.Matrix_IsIdentity(handle);
+}
+
+/**
+ * Modifies the receiver such that the matrix it represents becomes the
+ * the result of multiplying the matrix it previously represented by the
+ * argument.
+ *
+ * @param matrix the matrix to multiply the receiver by
+ *
+ * @exception SWTException
GC
s)
+where most of the primitive drawing operations are implemented, and
+images including both the code for displaying them and the public API for
+loading/saving them.
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/BidiUtil.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/BidiUtil.java
new file mode 100644
index 000000000..4cb9407df
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/BidiUtil.java
@@ -0,0 +1,688 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.internal;
+
+
+import java.util.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+/*
+ * Wraps Win32 API used to bidi enable widgets. Up to 3.104 was used by
+ * StyledText widget exclusively. 3.105 release introduced the method
+ * #resolveTextDirection, which is used by other widgets as well.
+ */
+public class BidiUtil {
+
+ // Keyboard language ids
+ public static final int KEYBOARD_NON_BIDI = 0;
+ public static final int KEYBOARD_BIDI = 1;
+
+ // bidi flag
+ static int isBidiPlatform = -1;
+
+ // getRenderInfo flag values
+ public static final int CLASSIN = 1;
+ public static final int LINKBEFORE = 2;
+ public static final int LINKAFTER = 4;
+
+ // variables used for providing a listener mechanism for keyboard language
+ // switching
+ static Map+ * + * @param hwnd the handle of the Control that is listening for keyboard language + * changes + * @param runnable the code that should be executed when a keyboard language change + * occurs + */ +public static void addLanguageListener (long hwnd, Runnable runnable) { + languageMap.put(new LONG(hwnd), runnable); + subclass(hwnd); +} +public static void addLanguageListener (Control control, Runnable runnable) { + addLanguageListener(control.handle, runnable); +} +/** + * Proc used for OS.EnumSystemLanguageGroups call during isBidiPlatform test. + */ +static long EnumSystemLanguageGroupsProc(long lpLangGrpId, long lpLangGrpIdString, long lpLangGrpName, long options, long lParam) { + if ((int)lpLangGrpId == OS.LGRPID_HEBREW) { + isBidiPlatform = 1; + return 0; + } + if ((int)lpLangGrpId == OS.LGRPID_ARABIC) { + isBidiPlatform = 1; + return 0; + } + return 1; +} +/** + * Wraps the ExtTextOut function. + *
+ * + * @param gc the gc to use for rendering + * @param renderBuffer the glyphs to render as an array of characters + * @param renderDx the width of each glyph in renderBuffer + * @param x x position to start rendering + * @param y y position to start rendering + */ +public static void drawGlyphs(GC gc, char[] renderBuffer, int[] renderDx, int x, int y) { + int length = renderDx.length; + if (OS.GetLayout (gc.handle) != 0) { + reverse(renderDx); + renderDx[length-1]--; //fixes bug 40006 + reverse(renderBuffer); + } + // render transparently to avoid overlapping segments. fixes bug 40006 + int oldBkMode = OS.SetBkMode(gc.handle, OS.TRANSPARENT); + OS.ExtTextOut(gc.handle, x, y, ETO_GLYPH_INDEX , null, renderBuffer, renderBuffer.length, renderDx); + OS.SetBkMode(gc.handle, oldBkMode); +} +/** + * Return ordering and rendering information for the given text. Wraps the GetFontLanguageInfo + * and GetCharacterPlacement functions. + *
+ *
+ * @param gc the GC to use for measuring of this line, input parameter
+ * @param text text that bidi data should be calculated for, input parameter
+ * @param order an array of integers representing the visual position of each character in
+ * the text array, output parameter
+ * @param classBuffer an array of integers representing the type (e.g., ARABIC, HEBREW,
+ * LOCALNUMBER) of each character in the text array, input/output parameter
+ * @param dx an array of integers representing the pixel width of each glyph in the returned
+ * glyph buffer, output parameter
+ * @param flags an integer representing rendering flag information, input parameter
+ * @param offsets text segments that should be measured and reordered separately, input
+ * parameter. See org.eclipse.swt.custom.BidiSegmentEvent for details.
+ * @return buffer with the glyphs that should be rendered for the given text
+ */
+public static char[] getRenderInfo(GC gc, String text, int[] order, byte[] classBuffer, int[] dx, int flags, int [] offsets) {
+ int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle);
+ long hHeap = OS.GetProcessHeap();
+ boolean isRightOriented = OS.GetLayout(gc.handle) != 0;
+ char [] textBuffer = text.toCharArray();
+ int byteCount = textBuffer.length;
+ boolean linkBefore = (flags & LINKBEFORE) == LINKBEFORE;
+ boolean linkAfter = (flags & LINKAFTER) == LINKAFTER;
+
+ GCP_RESULTS result = new GCP_RESULTS();
+ result.lStructSize = GCP_RESULTS.sizeof;
+ result.nGlyphs = byteCount;
+ long lpOrder = result.lpOrder = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4);
+ long lpDx = result.lpDx = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4);
+ long lpClass = result.lpClass = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ long lpGlyphs = result.lpGlyphs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 2);
+
+ // set required dwFlags
+ int dwFlags = 0;
+ int glyphFlags = 0;
+ // Always reorder. We assume that if we are calling this function we're
+ // on a platform that supports bidi. Fixes 20690.
+ dwFlags |= GCP_REORDER;
+ if ((fontLanguageInfo & GCP_LIGATE) == GCP_LIGATE) {
+ dwFlags |= GCP_LIGATE;
+ glyphFlags |= 0;
+ }
+ if ((fontLanguageInfo & GCP_GLYPHSHAPE) == GCP_GLYPHSHAPE) {
+ dwFlags |= GCP_GLYPHSHAPE;
+ if (linkBefore) {
+ glyphFlags |= GCPGLYPH_LINKBEFORE;
+ }
+ if (linkAfter) {
+ glyphFlags |= GCPGLYPH_LINKAFTER;
+ }
+ }
+ byte[] lpGlyphs2;
+ if (linkBefore || linkAfter) {
+ lpGlyphs2 = new byte[2];
+ lpGlyphs2[0]=(byte)glyphFlags;
+ lpGlyphs2[1]=(byte)(glyphFlags >> 8);
+ }
+ else {
+ lpGlyphs2 = new byte[] {(byte) glyphFlags};
+ }
+ OS.MoveMemory(result.lpGlyphs, lpGlyphs2, lpGlyphs2.length);
+
+ if ((flags & CLASSIN) == CLASSIN) {
+ // set classification values for the substring
+ dwFlags |= GCP_CLASSIN;
+ OS.MoveMemory(result.lpClass, classBuffer, classBuffer.length);
+ }
+
+ char[] glyphBuffer = new char[result.nGlyphs];
+ int glyphCount = 0;
+ for (int i=0; i
+ *
+ * @return an integer representing the active keyboard language (KEYBOARD_BIDI,
+ * KEYBOARD_NON_BIDI)
+ */
+public static int getKeyboardLanguage() {
+ long layout = OS.GetKeyboardLayout(0);
+ return isBidiLang(layout) ? KEYBOARD_BIDI : KEYBOARD_NON_BIDI;
+}
+/**
+ * Return the languages that are installed for the keyboard.
+ *
+ *
+ * @return integer array with an entry for each installed language
+ */
+static long[] getKeyboardLanguageList() {
+ int maxSize = 10;
+ long[] tempList = new long[maxSize];
+ int size = OS.GetKeyboardLayoutList(maxSize, tempList);
+ long[] list = new long[size];
+ System.arraycopy(tempList, 0, list, 0, size);
+ return list;
+}
+static boolean isBidiLang(long lang) {
+ int id = OS.PRIMARYLANGID(OS.LOWORD(lang));
+ return id == LANG_ARABIC || id == LANG_HEBREW || id == LANG_FARSI;
+}
+/**
+ * Return whether or not the platform supports a bidi language. Determine this
+ * by looking at the languages that are installed.
+ *
+ *
+ * @return true if bidi is supported, false otherwise. Always
+ * false on Windows CE.
+ */
+public static boolean isBidiPlatform() {
+ if (isBidiPlatform != -1) return isBidiPlatform == 1; // already set
+
+ isBidiPlatform = 0;
+
+ // The following test is a workaround for bug report 27629. On WinXP,
+ // both bidi and complex script (e.g., Thai) languages must be installed
+ // at the same time. Since the bidi platform calls do not support
+ // double byte characters, there is no way to run Eclipse using the
+ // complex script languages on XP, so constrain this test to answer true
+ // only if a bidi input language is defined. Doing so will allow complex
+ // script languages to work (e.g., one can install bidi and complex script
+ // languages, but only install the Thai keyboard).
+ if (!isKeyboardBidi()) return false;
+
+ Callback callback = null;
+ try {
+ callback = new Callback (Class.forName (CLASS_NAME), "EnumSystemLanguageGroupsProc", 5); //$NON-NLS-1$
+ long lpEnumSystemLanguageGroupsProc = callback.getAddress ();
+ if (lpEnumSystemLanguageGroupsProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ OS.EnumSystemLanguageGroups(lpEnumSystemLanguageGroupsProc, OS.LGRPID_INSTALLED, 0);
+ callback.dispose ();
+ } catch (ClassNotFoundException e) {
+ //callback can only be null at this point
+ }
+ if (isBidiPlatform == 1) return true;
+ // need to look at system code page for NT & 98 platforms since EnumSystemLanguageGroups is
+ // not supported for these platforms
+ String codePage = String.valueOf(OS.GetACP());
+ if (CD_PG_ARABIC.equals(codePage) || CD_PG_HEBREW.equals(codePage)) {
+ isBidiPlatform = 1;
+ }
+ return isBidiPlatform == 1;
+}
+/**
+ * Return whether or not the keyboard supports input of a bidi language. Determine this
+ * by looking at the languages that are installed for the keyboard.
+ *
+ *
+ * @return true if bidi is supported, false otherwise.
+ */
+public static boolean isKeyboardBidi() {
+ long[] list = getKeyboardLanguageList();
+ for (int i=0; i
+ *
+ * @param text
+ * Text base direction should be resolved for.
+ * @return SWT#LEFT_RIGHT or SWT#RIGHT_TO_LEFT if the text contains strong
+ * characters and thus the direction can be resolved, SWT#NONE
+ * otherwise.
+ * @since 3.105
+ */
+public static int resolveTextDirection (String text) {
+ if (text == null) return SWT.NONE;
+ int length = text.length();
+ if (length == 0) return SWT.NONE;
+ char[] rtlProbe = {' ', ' ', '1'};
+ /*
+ * "Wide" version of win32 API can also run even on non-Unicode Windows,
+ * hence need for OS.IsUnicode check here.
+ */
+ char[] ltrProbe = {'\u202b', 'a', ' '};
+ char[] numberProbe = {'\u05d0', ' ', ' '};
+ GCP_RESULTS result = new GCP_RESULTS();
+ result.lStructSize = GCP_RESULTS.sizeof;
+ int nGlyphs = result.nGlyphs = ltrProbe.length;
+ long hHeap = OS.GetProcessHeap();
+ long lpOrder = result.lpOrder = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, nGlyphs * 4);
+ long hdc = OS.GetDC(0);
+ int[] order = new int[1];
+ int textDirection = SWT.NONE;
+ for (int i = 0; i < length; i++) {
+ char ch = text.charAt(i);
+ rtlProbe[0] = ch;
+ OS.GetCharacterPlacement(hdc, rtlProbe, rtlProbe.length, 0, result, OS.GCP_REORDER);
+ OS.MoveMemory(order, result.lpOrder, 4);
+ if (order[0] == 2) {
+ textDirection = SWT.RIGHT_TO_LEFT;
+ break;
+ }
+ ltrProbe[2] = ch;
+ OS.GetCharacterPlacement(hdc, ltrProbe, ltrProbe.length, 0, result, OS.GCP_REORDER);
+ OS.MoveMemory(order, result.lpOrder + 4, 4);
+ if (order[0] == 1) {
+ numberProbe[2] = ch;
+ OS.GetCharacterPlacement(hdc, numberProbe, numberProbe.length, 0, result, OS.GCP_REORDER);
+ OS.MoveMemory(order, result.lpOrder, 4);
+ if (order[0] == 0) {
+ textDirection = SWT.LEFT_TO_RIGHT;
+ break;
+ }
+ }
+ }
+ OS.ReleaseDC (0, hdc);
+ OS.HeapFree(hHeap, 0, lpOrder);
+ return textDirection;
+
+}
+/**
+ * Switch the keyboard language to the specified language type. We do
+ * not distinguish between multiple bidi or multiple non-bidi languages, so
+ * set the keyboard to the first language of the given type.
+ *
+ *
+ * @param language integer representing language. One of
+ * KEYBOARD_BIDI, KEYBOARD_NON_BIDI.
+ */
+public static void setKeyboardLanguage(int language) {
+ if (language == getKeyboardLanguage()) return;
+ boolean bidi = language == KEYBOARD_BIDI;
+ long[] list = getKeyboardLanguageList();
+ for (int i=0; i Note, do not use this if the method arguments have a double, as arguments will be
+ * shifted/corrupted. See Bug 510538. Instead use the following constructor: Note, do not use this if the method arguments have a double, as arguments will be
+ * shifted/corrupted. See Bug 510538. Instead use the following constructor: Note, do not use this if the method arguments have a double, as arguments will be
+ * shifted/corrupted. See Bug 510538. Instead use the following constructor: Register the java method to be a C callback.
+ * I.e, C will be able to make a call to this java method directly (through callback.c) The other constructors hard-code int/long into the method signature: Note:
+ * The following types are supported: For example if you want to link the following method:
+ * Note: This should not be called by application code.
+ *
+ * Note: This should not be called by application code.
+ *
+ * Note: This should not be called by application code.
+ *
+ * WARNING: This operation is extremely dangerous,
+ * and should never be performed by application code.
+ *
+ * It is part of our effort to provide support for both J2SE
+ * and J2ME platforms.
+ *
+ * IMPORTANT: some of the methods have been modified from their
+ * J2SE parents. Refer to the description of each method for
+ * specific changes.
+ *
+ * IMPORTANT: the j2me version has an additional restriction on
+ * the arguments. p must be within the range 0 - 32767 (inclusive).
+ * q must be within the range 1 - 32767 (inclusive).
+ *
+ * The new process inherits the environment of the caller.
+ *
+ *
+ * @param prog array containing the program to execute and its arguments
+ * @param envp
+ * array of strings, each element of which has environment
+ * variable settings in the format name=value
+ * @param workingDir
+ * the working directory of the new process, or null if the new
+ * process should inherit the working directory of the caller
+ *
+ * @exception IOException
+ * if the program cannot be executed
+ * @exception SecurityException
+ * if the current SecurityManager disallows program execution
+ *
+ * @since 3.6
+ */
+public static void exec(String[] prog, String[] envp, String workingDir) throws java.io.IOException{
+ Runtime.getRuntime().exec(prog, null, workingDir != null ? new File(workingDir) : null);
+}
+
+private static ResourceBundle msgs = null;
+
+/**
+ * Returns the NLS'ed message for the given argument. This is only being
+ * called from SWT.
+ *
+ * @param key the key to look up
+ * @return the message for the given key
+ *
+ * @see SWT#getMessage(String)
+ */
+public static String getMessage(String key) {
+ String answer = key;
+
+ if (key == null) {
+ SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (msgs == null) {
+ try {
+ msgs = ResourceBundle.getBundle("org.eclipse.swt.internal.SWTMessages"); //$NON-NLS-1$
+ } catch (MissingResourceException ex) {
+ answer = key + " (no resource bundle)"; //$NON-NLS-1$
+ }
+ }
+ if (msgs != null) {
+ try {
+ answer = msgs.getString(key);
+ } catch (MissingResourceException ex2) {}
+ }
+ return answer;
+}
+
+public static String getMessage(String key, Object[] args) {
+ String answer = key;
+
+ if (key == null || args == null) {
+ SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (msgs == null) {
+ try {
+ msgs = ResourceBundle.getBundle("org.eclipse.swt.internal.SWTMessages"); //$NON-NLS-1$
+ } catch (MissingResourceException ex) {
+ answer = key + " (no resource bundle)"; //$NON-NLS-1$
+ }
+ }
+ if (msgs != null) {
+ try {
+ MessageFormat formatter = new MessageFormat("");
+ formatter.applyPattern(msgs.getString(key));
+ answer = formatter.format(args);
+ } catch (MissingResourceException ex2) {}
+ }
+ return answer;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/DPIUtil.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/DPIUtil.java
new file mode 100644
index 000000000..cbfa1c5cc
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/DPIUtil.java
@@ -0,0 +1,499 @@
+/*******************************************************************************
+ * Copyright (c) 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.internal;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * This class hold common constants and utility functions w.r.t. to SWT high DPI
+ * functionality.
+ *
+ * The {@code autoScaleUp(..)} methods convert from API coordinates (in
+ * SWT points) to internal high DPI coordinates (in pixels) that interface with
+ * native widgets.
+ *
+ * The {@code autoScaleDown(..)} convert from high DPI pixels to API coordinates
+ * (in SWT points).
+ *
+ * It is part of our effort to provide support for both J2SE
+ * and J2ME platforms. Under this scheme, classes need to
+ * implement SWTEventListener instead of java.util.EventListener.
+ *
+ * Note: java.util.EventListener is not part of CDC and CLDC.
+ *
+ * Answer the number of bytes actually read or -1 if no bytes were read and
+ * end of stream was encountered. This implementation reads bytes from
+ * the pushback buffer first, then the target stream if more bytes are required
+ * to satisfy
+ * The bytes are pushed so that they would be read back b[0], b[1], etc.
+ * If the push back buffer cannot handle the bytes copied from
+Applications should not need to reference the classes in this package
+directly.
+
+Referencing any of the classes in this package directly guarantees
+that the code is platform specific. Applications should not need to
+reference the classes in this package directly.
+
+Applications should not need to reference the classes in this package
+directly.
+
+ * Note that unicode characters which can not be found in the platform
+ * encoding will be converted to an arbitrary platform specific character.
+ *
+Referencing any of the classes in this package directly guarantees
+that the code is platform specific. Applications should not need to
+reference the classes in this package directly.
+
+ * Initially, the controls will all be as tall as the tallest control,
+ * and as wide as the widest.
+ * Example code: first a
+ *
+ * A
+ * specifies that the side to which the
+ * Control sides can also be attached to another control.
+ * For example:
+ * For top and bottom attachments, TOP, BOTTOM and CENTER are used. For left
+ * and right attachments, LEFT, RIGHT and CENTER are used. If any other case
+ * occurs, the default will be used instead.
+ *
+ * To set a
+ *
+ * The following example code creates a
+ * To use a
+ * Each side of a child control can be attached to a position in the parent
+ * composite, or to other controls within the
+ * If a side is not given an attachment, it is defined as not being attached
+ * to anything, causing the child to remain at its preferred size. If a child
+ * is given no attachment on either the left or the right or top or bottom, it is
+ * automatically attached to the left and top of the composite respectively.
+ * The following code positions
+ * IMPORTANT: Do not define circular attachments. For example, do not attach
+ * the right edge of
+ * There are two ways to create a
+ * NOTE: Do not reuse grabExcessHorizontalSpace specifies whether the width of the cell
+ * changes depending on the size of the parent Composite. If
+ * grabExcessHorizontalSpace is The default value is false. grabExcessVerticalSpace specifies whether the height of the cell
+ * changes depending on the size of the parent Composite. If
+ * grabExcessVerticalSpace is The default value is false.
+ *
+ * The following code creates a shell managed by a
+ * The
+ * The following code uses a
+ *
+ * The following example code creates a Definitions for these constants can be found in MSDN.
+ *
+ */
+public class OLE extends SWT {
+
+ public static final int S_FALSE = 1; // Used for functions that semantically return a Boolean FALSE result to indicate that the function succeeded.
+ public static final int S_OK = 0; // Function succeeded.
+ public static final int E_FAIL = -2147467259; // Unspecified failure.
+ public static final int E_INVALIDARG = -2147024809; // Invalid argument
+ public static final int E_NOINTERFACE = -2147467262; // QueryInterface did not recognize the requested interface.
+ public static final int E_NOTIMPL = -2147467263; // Not implemented
+
+ public static final String IID_IUNKNOWN = "{00000000-0000-0000-C000-000000000046}"; //$NON-NLS-1$
+ public static final String IID_IDISPATCH = "{00020400-0000-0000-C000-000000000046}"; //$NON-NLS-1$
+
+ // Verbs that can be invoked on this client
+ public static final int OLEIVERB_DISCARDUNDOSTATE = -6; // close the OLE object and discard the undo state
+ public static final int OLEIVERB_HIDE = -3; // hide the OLE object
+ public static final int OLEIVERB_INPLACEACTIVATE = -5; // open the OLE for editing in-place
+ public static final int OLEIVERB_OPEN = -2; // open the OLE object for editing in a separate window
+ public static final int OLEIVERB_PRIMARY = 0; // opens the OLE object for editing
+ public static final int OLEIVERB_PROPERTIES = -7; // request the OLE object properties dialog
+ public static final int OLEIVERB_SHOW = -1; // show the OLE object
+ public static final int OLEIVERB_UIACTIVATE = -4; // activate the UI for the OLE object
+
+ public static final int PROPERTY_CHANGING = 0;
+ public static final int PROPERTY_CHANGED = 1;
+
+ /**
+ * Error code for OleError - No specific error information available
+ */
+ public static final int HRESULT_UNSPECIFIED = 0;
+ /**
+ * Error code for OleError - Failed to create file
+ */
+ public static final int ERROR_CANNOT_CREATE_FILE = 1000;
+ /**
+ * Error code for OleError - Failed to create Ole Client
+ */
+ public static final int ERROR_CANNOT_CREATE_OBJECT = 1001;
+ /**
+ * Error code for OleError - File does not exist, is not accessible to user or does not have the correct format
+ */
+ public static final int ERROR_CANNOT_OPEN_FILE = 1002;
+ /**
+ * Error code for OleError - Failed to find requested interface on OLE Object
+ */
+ public static final int ERROR_INTERFACE_NOT_FOUND = 1003;
+ /**
+ * Error code for OleError - Class ID not found in registry
+ */
+ public static final int ERROR_INVALID_CLASSID = 1004;
+ /**
+ * Error code for OleError - Failed to get the class factory for the specified classID
+ */
+ public static final int ERROR_CANNOT_ACCESS_CLASSFACTORY = 1005;
+ /**
+ * Error code for OleError - Failed to create Licensed instance
+ */
+ public static final int ERROR_CANNOT_CREATE_LICENSED_OBJECT = 1006;
+ /**
+ * Error code for OleError - Out of Memory
+ */
+ public static final int ERROR_OUT_OF_MEMORY = 1007;
+ /**
+ * Error code for OleError - Failed to change Variant type
+ */
+ public static final int ERROR_CANNOT_CHANGE_VARIANT_TYPE = 1010;
+ /**
+ * Error code for OleError - Invalid address received for Ole Interface
+ */
+ public static final int ERROR_INVALID_INTERFACE_ADDRESS = 1011;
+ /**
+ * Error code for OleError - Unable to find Application
+ */
+ public static final int ERROR_APPLICATION_NOT_FOUND = 1013;
+ /**
+ * Error code for OleError - Action can not be performed
+ */
+ public static final int ERROR_ACTION_NOT_PERFORMED = 1014;
+
+ public static final int OLECMDF_SUPPORTED = 1;
+ public static final int OLECMDF_ENABLED = 2;
+ public static final int OLECMDF_LATCHED = 4;
+ public static final int OLECMDF_NINCHED = 8;
+
+ public static final int OLECMDTEXTF_NONE = 0;
+ public static final int OLECMDTEXTF_NAME = 1;
+ public static final int OLECMDTEXTF_STATUS = 2;
+
+ public static final int OLECMDEXECOPT_DODEFAULT = 0;
+ public static final int OLECMDEXECOPT_PROMPTUSER = 1;
+ public static final int OLECMDEXECOPT_DONTPROMPTUSER = 2;
+ public static final int OLECMDEXECOPT_SHOWHELP = 3;
+
+ public static final int OLECMDID_OPEN = 1;
+ public static final int OLECMDID_NEW = 2;
+ public static final int OLECMDID_SAVE = 3;
+ public static final int OLECMDID_SAVEAS = 4;
+ public static final int OLECMDID_SAVECOPYAS = 5;
+ public static final int OLECMDID_PRINT = 6;
+ public static final int OLECMDID_PRINTPREVIEW = 7;
+ public static final int OLECMDID_PAGESETUP = 8;
+ public static final int OLECMDID_SPELL = 9;
+ public static final int OLECMDID_PROPERTIES = 10;
+ public static final int OLECMDID_CUT = 11;
+ public static final int OLECMDID_COPY = 12;
+ public static final int OLECMDID_PASTE = 13;
+ public static final int OLECMDID_PASTESPECIAL = 14;
+ public static final int OLECMDID_UNDO = 15;
+ public static final int OLECMDID_REDO = 16;
+ public static final int OLECMDID_SELECTALL = 17;
+ public static final int OLECMDID_CLEARSELECTION = 18;
+ public static final int OLECMDID_ZOOM = 19;
+ public static final int OLECMDID_GETZOOMRANGE = 20;
+ public static final int OLECMDID_UPDATECOMMANDS = 21;
+ public static final int OLECMDID_REFRESH = 22;
+ public static final int OLECMDID_STOP = 23;
+ public static final int OLECMDID_HIDETOOLBARS = 24;
+ public static final int OLECMDID_SETPROGRESSMAX = 25;
+ public static final int OLECMDID_SETPROGRESSPOS = 26;
+ public static final int OLECMDID_SETPROGRESSTEXT = 27;
+ public static final int OLECMDID_SETTITLE = 28;
+ public static final int OLECMDID_SETDOWNLOADSTATE = 29;
+ public static final int OLECMDID_STOPDOWNLOAD = 30;
+
+ /* Ole Property Description flags */
+ public static int VARFLAG_FREADONLY = 0x1;
+ public static int VARFLAG_FSOURCE = 0x2;
+ public static int VARFLAG_FBINDABLE = 0x4;
+ public static int VARFLAG_FREQUESTEDIT = 0x8;
+ public static int VARFLAG_FDISPLAYBIND = 0x10;
+ public static int VARFLAG_FDEFAULTBIND = 0x20;
+ public static int VARFLAG_FHIDDEN = 0x40;
+ public static int VARFLAG_FRESTRICTED = 0x80;
+ public static int VARFLAG_FDEFAULTCOLLELEM = 0x100;
+ public static int VARFLAG_FUIDEFAULT = 0x200;
+ public static int VARFLAG_FNONBROWSABLE = 0x400;
+ public static int VARFLAG_FREPLACEABLE = 0x800;
+ public static int VARFLAG_FIMMEDIATEBIND = 0x1000;
+
+ /* Ole Property Description kind */
+ public static int VAR_PERINSTANCE = 0;
+ public static int VAR_STATIC = 1;
+ public static int VAR_CONST = 2;
+ public static int VAR_DISPATCH = 3;
+
+ /* Ole Parameter Description flags */
+ public static short IDLFLAG_NONE = 0;
+ public static short IDLFLAG_FIN = 1;
+ public static short IDLFLAG_FOUT = 2;
+ public static short IDLFLAG_FLCID = 4;
+ public static short IDLFLAG_FRETVAL = 8;
+
+ /* Ole Description types */
+ public static final short VT_BOOL = 11; // Boolean; True=-1, False=0.
+ public static final short VT_BSTR = 8; // Binary String.
+ public static final short VT_BYREF = 16384; // By reference - must be combined with one of the other VT values
+ public static final short VT_CY = 6; // Currency.
+ public static final short VT_DATE = 7; // Date.
+ public static final short VT_DISPATCH = 9; // IDispatch
+ public static final short VT_EMPTY = 0; // Not specified.
+ public static final short VT_ERROR = 10; // Scodes.
+ public static final short VT_I2 = 2; // 2-byte signed int.
+ public static final short VT_I4 = 3; // 4-byte signed int.
+ public static final short VT_NULL = 1; // Null.
+ public static final short VT_R4 = 4; // 4-byte real.
+ public static final short VT_R8 = 5; // 8-byte real.
+ public static final short VT_UI1 = 17; // Unsigned char.
+ public static final short VT_UI4 = 19; // Unsigned int.
+ public static final short VT_UNKNOWN = 13; // IUnknown FAR*.
+ public static final short VT_VARIANT = 12; // VARIANT FAR*.
+ public static final short VT_PTR = 26;
+ public static final short VT_USERDEFINED = 29;
+ public static final short VT_HRESULT = 25;
+ public static final short VT_DECIMAL = 14;
+ public static final short VT_I1 = 16;
+ public static final short VT_UI2 = 18;
+ public static final short VT_I8 = 20;
+ public static final short VT_UI8 = 21;
+ public static final short VT_INT = 22;
+ public static final short VT_UINT = 23;
+ public static final short VT_VOID = 24;
+ public static final short VT_SAFEARRAY = 27;
+ public static final short VT_CARRAY = 28;
+ public static final short VT_LPSTR = 30;
+ public static final short VT_LPWSTR = 31;
+ public static final short VT_RECORD = 36;
+ public static final short VT_FILETIME = 64;
+ public static final short VT_BLOB = 65;
+ public static final short VT_STREAM = 66;
+ public static final short VT_STORAGE = 67;
+ public static final short VT_STREAMED_OBJECT = 68;
+ public static final short VT_STORED_OBJECT = 69;
+ public static final short VT_BLOB_OBJECT = 70;
+ public static final short VT_CF = 71;
+ public static final short VT_CLSID = 72;
+ public static final short VT_VERSIONED_STREAM = 73;
+ public static final short VT_BSTR_BLOB = 0xfff;
+ public static final short VT_VECTOR = 0x1000;
+ public static final short VT_ARRAY = 0x2000;
+
+ /* Ole Function Description Invoke Kind values */
+ public static final int INVOKE_FUNC = 1;
+ public static final int INVOKE_PROPERTYGET = 2;
+ public static final int INVOKE_PROPERTYPUT = 4;
+ public static final int INVOKE_PROPERTYPUTREF = 8;
+
+ /* Ole Function Description function kind */
+ public static final int FUNC_VIRTUAL = 0;
+ public static final int FUNC_PUREVIRTUAL = 1;
+ public static final int FUNC_NONVIRTUAL = 2;
+ public static final int FUNC_STATIC = 3;
+ public static final int FUNC_DISPATCH = 4;
+
+ /* Ole Function Description function flags */
+ public static final short FUNCFLAG_FRESTRICTED = 1;
+ public static final short FUNCFLAG_FSOURCE = 0x2;
+ public static final short FUNCFLAG_FBINDABLE = 0x4;
+ public static final short FUNCFLAG_FREQUESTEDIT = 0x8;
+ public static final short FUNCFLAG_FDISPLAYBIND = 0x10;
+ public static final short FUNCFLAG_FDEFAULTBIND = 0x20;
+ public static final short FUNCFLAG_FHIDDEN = 0x40;
+ public static final short FUNCFLAG_FUSESGETLASTERROR = 0x80;
+ public static final short FUNCFLAG_FDEFAULTCOLLELEM = 0x100;
+ public static final short FUNCFLAG_FUIDEFAULT = 0x200;
+ public static final short FUNCFLAG_FNONBROWSABLE = 0x400;
+ public static final short FUNCFLAG_FREPLACEABLE = 0x800;
+ public static final short FUNCFLAG_FIMMEDIATEBIND = 0x1000;
+
+ /* Ole Function Description calling convention */
+ public static final int CC_FASTCALL = 0;
+ public static final int CC_CDECL = 1;
+ public static final int CC_MSCPASCAL = 2;
+ public static final int CC_PASCAL = 2;
+ public static final int CC_MACPASCAL = 3;
+ public static final int CC_STDCALL = 4;
+ public static final int CC_FPFASTCALL = 5;
+ public static final int CC_SYSCALL = 6;
+ public static final int CC_MPWCDECL = 7;
+ public static final int CC_MPWPASCAL = 8;
+ public static final int CC_MAX = 9;
+
+ static final String ERROR_NOT_IMPLEMENTED_MSG = "Required functionality not currently supported.";//$NON-NLS-1$
+ static final String ERROR_CANNOT_CREATE_FILE_MSG = "Failed to create file.";//$NON-NLS-1$
+ static final String ERROR_CANNOT_CREATE_OBJECT_MSG = "Failed to create Ole Client.";//$NON-NLS-1$
+ static final String ERROR_CANNOT_OPEN_FILE_MSG = "File does not exist, is not accessible to user or does not have the correct format.";//$NON-NLS-1$
+ static final String ERROR_INTERFACE_NOT_FOUND_MSG = "Failed to find requested interface on OLE Object.";//$NON-NLS-1$
+ static final String ERROR_INVALID_CLASSID_MSG = "Class ID not found in registry";//$NON-NLS-1$
+ static final String ERROR_CANNOT_ACCESS_CLASSFACTORY_MSG = "Failed to get the class factory for the specified classID";//$NON-NLS-1$
+ static final String ERROR_CANNOT_CREATE_LICENSED_OBJECT_MSG = "Failed to create Licensed instance";//$NON-NLS-1$
+ static final String ERROR_OUT_OF_MEMORY_MSG = "Out of Memory";//$NON-NLS-1$
+ static final String ERROR_CANNOT_CHANGE_VARIANT_TYPE_MSG = "Failed to change Variant type";//$NON-NLS-1$
+ static final String ERROR_INVALID_INTERFACE_ADDRESS_MSG = "Invalid address received for Ole Interface.";//$NON-NLS-1$
+ static final String ERROR_APPLICATION_NOT_FOUND_MSG = "Unable to find Application.";//$NON-NLS-1$
+ static final String ERROR_ACTION_NOT_PERFORMED_MSG = "Action can not be performed.";//$NON-NLS-1$
+
+
+public static void error (int code) {
+ error (code, 0);
+}
+public static void error (int code, int hresult) {
+
+ switch (code) {
+ /* Illegal Arguments (non-fatal) */
+ case ERROR_INVALID_INTERFACE_ADDRESS :{
+ throw new IllegalArgumentException (ERROR_INVALID_INTERFACE_ADDRESS_MSG);
+ }
+
+ /* SWT Errors (non-fatal) */
+ case ERROR_CANNOT_CREATE_FILE : {
+ String msg = ERROR_CANNOT_CREATE_FILE_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);
+ }
+ case ERROR_CANNOT_CREATE_OBJECT : {
+ String msg = ERROR_CANNOT_CREATE_OBJECT_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);//$NON-NLS-1$
+ }
+ case ERROR_CANNOT_OPEN_FILE : {
+ String msg = ERROR_CANNOT_OPEN_FILE_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);
+ }
+ case ERROR_INTERFACE_NOT_FOUND : {
+ String msg = ERROR_INTERFACE_NOT_FOUND_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);
+ }
+ case ERROR_INVALID_CLASSID : {
+ String msg = ERROR_INVALID_CLASSID_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);
+ }
+ case ERROR_CANNOT_ACCESS_CLASSFACTORY : {
+ String msg = ERROR_CANNOT_ACCESS_CLASSFACTORY_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);
+ }
+ case ERROR_CANNOT_CREATE_LICENSED_OBJECT : {
+ String msg = ERROR_CANNOT_CREATE_LICENSED_OBJECT_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);
+ }
+ case ERROR_CANNOT_CHANGE_VARIANT_TYPE : {
+ String msg = ERROR_CANNOT_CHANGE_VARIANT_TYPE_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);
+ }
+ case ERROR_APPLICATION_NOT_FOUND : {
+ String msg = ERROR_APPLICATION_NOT_FOUND_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);
+ }
+ case ERROR_ACTION_NOT_PERFORMED : {
+ String msg = ERROR_ACTION_NOT_PERFORMED_MSG;
+ if (hresult != 0) msg += " result = "+hresult;//$NON-NLS-1$
+ throw new SWTException (code, msg);
+ }
+
+ /* OS Failure/Limit (fatal, may occur only on some platforms) */
+ case ERROR_OUT_OF_MEMORY : {
+ String msg = ERROR_ACTION_NOT_PERFORMED_MSG;
+ if (hresult != 0) msg += " result = "+hresult; //$NON-NLS-1$
+ throw new SWTError (code, msg);
+ }
+ }
+
+ /* Unknown/Undefined Error */
+ SWT.error(code);
+}
+
+/*
+ * Finds the OLE program id that is associated with an extension.
+ * The extension may or may not begin with a '.'. On platforms
+ * that do not support OLE, an empty string is returned.
+ *
+ * @param extension the program extension
+ * @return a string that is the OLE program id or an empty string
+ *
+ * @exception IllegalArgumentException The OLE Document or ActiveX Control must support the IDispatch interface in order to provide
+ * OleAutomation support. The additional functionality provided by the OLE Object is specified in
+ * its IDL file. The additional methods can either be to get property values ( Here is a sample IDL fragment:
+ *
+ * An example of how to interact with this extended functionality is shown below:
+ *
+ *
+ * This method releases the IDispatch interface on the OLE Document or ActiveX Control.
+ * Do not use the OleAutomation object after it has been disposed.
+ */
+public void dispose() {
+
+ if (objIDispatch != null){
+ objIDispatch.Release();
+ }
+ objIDispatch = null;
+
+ if (objITypeInfo != null){
+ objITypeInfo.Release();
+ }
+ objITypeInfo = null;
+
+ if (objIUnknown != null){
+ objIUnknown.Release();
+ OS.OleUninitialize();
+ }
+ objIUnknown = null;
+}
+long getAddress() {
+ return objIDispatch.getAddress();
+}
+GUID getClassID(String clientName) {
+ // create a GUID struct to hold the result
+ GUID guid = new GUID();
+
+ // create a null terminated array of char
+ char[] buffer = null;
+ if (clientName != null) {
+ int count = clientName.length();
+ buffer = new char[count + 1];
+ clientName.getChars(0, count, buffer, 0);
+ }
+ if (COM.CLSIDFromProgID(buffer, guid) != COM.S_OK){
+ int result = COM.CLSIDFromString(buffer, guid);
+ if (result != COM.S_OK) return null;
+ }
+ return guid;
+}
+/**
+ * Returns the fully qualified name of the Help file for the given member ID.
+ *
+ * @param dispId the member ID whose Help file is being retrieved.
+ * @return a string representing the fully qualified name of a Help
+ * file or null.
+ */
+public String getHelpFile(int dispId) {
+ if (objITypeInfo == null) return null;
+ String[] file = new String[1];
+ int rc = objITypeInfo.GetDocumentation(dispId, null, null, null, file );
+ if (rc == OLE.S_OK) return file[0];
+ return null;
+}
+/**
+ * Returns the documentation string for the given member ID.
+ *
+ * @param dispId the member ID in which the documentation is being retrieved.
+ * @return the documentation string if it exists; otherwise return null.
+ */
+public String getDocumentation(int dispId) {
+ if (objITypeInfo == null) return null;
+ String[] doc = new String[1];
+ int rc = objITypeInfo.GetDocumentation(dispId, null, doc, null, null );
+ if (rc == OLE.S_OK) return doc[0];
+ return null;
+}
+/**
+ * Returns the property description of a variable at the given index.
+ *
+ * @param index the index of a variable whose property is being retrieved.
+ * @return an OlePropertyDescription for a variable at the given index.
+ */
+public OlePropertyDescription getPropertyDescription(int index) {
+ if (objITypeInfo == null) return null;
+ long[] ppVarDesc = new long[1];
+ int rc = objITypeInfo.GetVarDesc(index, ppVarDesc);
+ if (rc != OLE.S_OK) return null;
+ VARDESC vardesc = new VARDESC();
+ COM.MoveMemory(vardesc, ppVarDesc[0], VARDESC.sizeof);
+
+ OlePropertyDescription data = new OlePropertyDescription();
+ data.id = vardesc.memid;
+ data.name = getName(vardesc.memid);
+ data.type = vardesc.elemdescVar_tdesc_vt;
+ if (data.type == OLE.VT_PTR) {
+ short[] vt = new short[1];
+ OS.MoveMemory(vt, vardesc.elemdescVar_tdesc_union + C.PTR_SIZEOF, 2);
+ data.type = vt[0];
+ }
+ data.flags = vardesc.wVarFlags;
+ data.kind = vardesc.varkind;
+ data.description = getDocumentation(vardesc.memid);
+ data.helpFile = getHelpFile(vardesc.memid);
+
+ objITypeInfo.ReleaseVarDesc(ppVarDesc[0]);
+ return data;
+}
+/**
+ * Returns the description of a function at the given index.
+ *
+ * @param index the index of a function whose property is being retrieved.
+ * @return an OleFunctionDescription for a function at the given index.
+ */
+public OleFunctionDescription getFunctionDescription(int index) {
+ if (objITypeInfo == null) return null;
+ long[] ppFuncDesc = new long[1];
+ int rc = objITypeInfo.GetFuncDesc(index, ppFuncDesc);
+ if (rc != OLE.S_OK) return null;
+ FUNCDESC funcdesc = new FUNCDESC();
+ COM.MoveMemory(funcdesc, ppFuncDesc[0], FUNCDESC.sizeof);
+
+ OleFunctionDescription data = new OleFunctionDescription();
+
+ data.id = funcdesc.memid;
+ data.optionalArgCount = funcdesc.cParamsOpt;
+ data.invokeKind = funcdesc.invkind;
+ data.funcKind = funcdesc.funckind;
+ data.flags = funcdesc.wFuncFlags;
+ data.callingConvention = funcdesc.callconv;
+ data.documentation = getDocumentation(funcdesc.memid);
+ data.helpFile = getHelpFile(funcdesc.memid);
+
+ String[] names = getNames(funcdesc.memid, funcdesc.cParams + 1);
+ if (names.length > 0) {
+ data.name = names[0];
+ }
+ data.args = new OleParameterDescription[funcdesc.cParams];
+ for (int i = 0; i < data.args.length; i++) {
+ data.args[i] = new OleParameterDescription();
+ if (names.length > i + 1) {
+ data.args[i].name = names[i + 1];
+ }
+ //TODO 0- use structures
+ short[] vt = new short[1];
+ OS.MoveMemory(vt, funcdesc.lprgelemdescParam + i * COM.ELEMDESC_sizeof() + C.PTR_SIZEOF, 2);
+ if (vt[0] == OLE.VT_PTR) {
+ long [] pTypedesc = new long [1];
+ OS.MoveMemory(pTypedesc, funcdesc.lprgelemdescParam + i * COM.ELEMDESC_sizeof(), C.PTR_SIZEOF);
+ short[] vt2 = new short[1];
+ OS.MoveMemory(vt2, pTypedesc[0] + C.PTR_SIZEOF, 2);
+ vt[0] = (short)(vt2[0] | COM.VT_BYREF);
+ }
+ data.args[i].type = vt[0];
+ short[] wParamFlags = new short[1];
+ OS.MoveMemory(wParamFlags, funcdesc.lprgelemdescParam + i * COM.ELEMDESC_sizeof() + COM.TYPEDESC_sizeof () + C.PTR_SIZEOF, 2);
+ data.args[i].flags = wParamFlags[0];
+ }
+
+ data.returnType = funcdesc.elemdescFunc_tdesc_vt;
+ if (data.returnType == OLE.VT_PTR) {
+ short[] vt = new short[1];
+ OS.MoveMemory(vt, funcdesc.elemdescFunc_tdesc_union + C.PTR_SIZEOF, 2);
+ data.returnType = vt[0];
+ }
+
+ objITypeInfo.ReleaseFuncDesc(ppFuncDesc[0]);
+ return data;
+}
+/**
+ * Returns the type info of the current object referenced by the automation.
+ * The type info contains information about the object such as the function descriptions,
+ * the member descriptions and attributes of the type.
+ *
+ * @return the type info of the receiver
+ */
+public TYPEATTR getTypeInfoAttributes() {
+ if (objITypeInfo == null) return null;
+ long [] ppTypeAttr = new long [1];
+ int rc = objITypeInfo.GetTypeAttr(ppTypeAttr);
+ if (rc != OLE.S_OK) return null;
+ TYPEATTR typeattr = new TYPEATTR();
+ COM.MoveMemory(typeattr, ppTypeAttr[0], TYPEATTR.sizeof);
+ objITypeInfo.ReleaseTypeAttr(ppTypeAttr[0]);
+ return typeattr;
+}
+/**
+ * Returns the name of the given member ID.
+ *
+ * @param dispId the member ID in which the name is being retrieved.
+ * @return the name if it exists; otherwise return null.
+ */
+public String getName(int dispId) {
+ if (objITypeInfo == null) return null;
+ String[] name = new String[1];
+ int rc = objITypeInfo.GetDocumentation(dispId, name, null, null, null );
+ if (rc == OLE.S_OK) return name[0];
+ return null;
+}
+/**
+ * Returns the name of a function and parameter names for the specified function ID.
+ *
+ * @param dispId the function ID in which the name and parameters are being retrieved.
+ * @param maxSize the maximum number of names to retrieve.
+ * @return an array of name containing the function name and the parameter names
+ */
+public String[] getNames(int dispId, int maxSize) {
+ if (objITypeInfo == null) return new String[0];
+ String[] names = new String[maxSize];
+ int[] count = new int[1];
+ int rc = objITypeInfo.GetNames(dispId, names, maxSize, count);
+ if (rc == OLE.S_OK) {
+ String[] newNames = new String[count[0]];
+ System.arraycopy(names, 0, newNames, 0, count[0]);
+ return newNames;
+ }
+ return new String[0];
+}
+/**
+ * Returns the positive integer values (IDs) that are associated with the specified names by the
+ * IDispatch implementor. If you are trying to get the names of the parameters in a method, the first
+ * String in the names array must be the name of the method followed by the names of the parameters.
+ *
+ * @param names an array of names for which you require the identifiers
+ *
+ * @return positive integer values that are associated with the specified names in the same
+ * order as the names where provided; or null if the names are unknown
+ */
+public int[] getIDsOfNames(String[] names) {
+
+ int[] rgdispid = new int[names.length];
+ int result = objIDispatch.GetIDsOfNames(new GUID(), names, names.length, COM.LOCALE_USER_DEFAULT, rgdispid);
+ if (result != COM.S_OK) return null;
+
+ return rgdispid;
+}
+/**
+ * Returns a description of the last error encountered.
+ *
+ * @return a description of the last error encountered
+ */
+public String getLastError() {
+
+ return exceptionDescription;
+
+}
+/**
+ * Returns the value of the property specified by the dispIdMember.
+ *
+ * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ *
+ * @return the value of the property specified by the dispIdMember or null
+ */
+public Variant getProperty(int dispIdMember) {
+ Variant pVarResult = new Variant();
+ int result = invoke(dispIdMember, COM.DISPATCH_PROPERTYGET, null, null, pVarResult);
+ return (result == OLE.S_OK) ? pVarResult : null;
+}
+/**
+ * Returns the value of the property specified by the dispIdMember.
+ *
+ * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ *
+ * @param rgvarg an array of arguments for the method. All arguments are considered to be
+ * read only unless the Variant is a By Reference Variant type.
+ *
+ * @return the value of the property specified by the dispIdMember or null
+ *
+ * @since 2.0
+ */
+public Variant getProperty(int dispIdMember, Variant[] rgvarg) {
+ Variant pVarResult = new Variant();
+ int result = invoke(dispIdMember, COM.DISPATCH_PROPERTYGET, rgvarg, null, pVarResult);
+ return (result == OLE.S_OK) ? pVarResult : null;
+
+}
+/**
+ * Returns the value of the property specified by the dispIdMember.
+ *
+ * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ *
+ * @param rgvarg an array of arguments for the method. All arguments are considered to be
+ * read only unless the Variant is a By Reference Variant type.
+ *
+ * @param rgdispidNamedArgs an array of identifiers for the arguments specified in rgvarg; the
+ * parameter IDs must be in the same order as their corresponding values;
+ * all arguments must have an identifier - identifiers can be obtained using
+ * OleAutomation.getIDsOfNames
+ *
+ * @return the value of the property specified by the dispIdMember or null
+ *
+ * @since 2.0
+ */
+public Variant getProperty(int dispIdMember, Variant[] rgvarg, int[] rgdispidNamedArgs) {
+ Variant pVarResult = new Variant();
+ int result = invoke(dispIdMember, COM.DISPATCH_PROPERTYGET, rgvarg, rgdispidNamedArgs, pVarResult);
+ return (result == OLE.S_OK) ? pVarResult : null;
+}
+@Override
+public boolean equals(Object object) {
+ if (object == this) return true;
+ if (object instanceof OleAutomation) {
+ if (objIDispatch == null) return false;
+ OleAutomation oleAutomation = ((OleAutomation) object);
+ if (oleAutomation.objIDispatch == null) return false;
+ long address1 = objIDispatch.getAddress();
+ long address2 = oleAutomation.objIDispatch.getAddress();
+ return address1 == address2;
+ }
+ return false;
+}
+/**
+ * Invokes a method on the OLE Object; the method has no parameters.
+ *
+ * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ *
+ * @return the result of the method or null if the method failed to give result information
+ */
+public Variant invoke(int dispIdMember) {
+ Variant pVarResult = new Variant();
+ int result = invoke(dispIdMember, COM.DISPATCH_METHOD, null, null, pVarResult);
+ return (result == COM.S_OK) ? pVarResult : null;
+}
+/**
+ * Invokes a method on the OLE Object; the method has no optional parameters.
+ *
+ * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ *
+ * @param rgvarg an array of arguments for the method. All arguments are considered to be
+ * read only unless the Variant is a By Reference Variant type.
+ *
+ * @return the result of the method or null if the method failed to give result information
+ */
+public Variant invoke(int dispIdMember, Variant[] rgvarg) {
+ Variant pVarResult = new Variant();
+ int result = invoke(dispIdMember, COM.DISPATCH_METHOD, rgvarg, null, pVarResult);
+ return (result == COM.S_OK) ? pVarResult : null;
+}
+/**
+ * Invokes a method on the OLE Object; the method has optional parameters. It is not
+ * necessary to specify all the optional parameters, only include the parameters for which
+ * you are providing values.
+ *
+ * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ *
+ * @param rgvarg an array of arguments for the method. All arguments are considered to be
+ * read only unless the Variant is a By Reference Variant type.
+ *
+ * @param rgdispidNamedArgs an array of identifiers for the arguments specified in rgvarg; the
+ * parameter IDs must be in the same order as their corresponding values;
+ * all arguments must have an identifier - identifiers can be obtained using
+ * OleAutomation.getIDsOfNames
+ *
+ * @return the result of the method or null if the method failed to give result information
+ */
+public Variant invoke(int dispIdMember, Variant[] rgvarg, int[] rgdispidNamedArgs) {
+ Variant pVarResult = new Variant();
+ int result = invoke(dispIdMember, COM.DISPATCH_METHOD, rgvarg, rgdispidNamedArgs, pVarResult);
+ return (result == COM.S_OK) ? pVarResult : null;
+}
+private int invoke(int dispIdMember, int wFlags, Variant[] rgvarg, int[] rgdispidNamedArgs, Variant pVarResult) {
+
+ // get the IDispatch interface for the control
+ if (objIDispatch == null) return COM.E_FAIL;
+
+ // create a DISPPARAMS structure for the input parameters
+ DISPPARAMS pDispParams = new DISPPARAMS();
+ // store arguments in rgvarg
+ if (rgvarg != null && rgvarg.length > 0) {
+ pDispParams.cArgs = rgvarg.length;
+ pDispParams.rgvarg = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, VARIANT.sizeof * rgvarg.length);
+ int offset = 0;
+ for (int i = rgvarg.length - 1; i >= 0 ; i--) {
+ rgvarg[i].getData(pDispParams.rgvarg + offset);
+ offset += VARIANT.sizeof;
+ }
+ }
+
+ // if arguments have ids, store the ids in rgdispidNamedArgs
+ if (rgdispidNamedArgs != null && rgdispidNamedArgs.length > 0) {
+ pDispParams.cNamedArgs = rgdispidNamedArgs.length;
+ pDispParams.rgdispidNamedArgs = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, 4 * rgdispidNamedArgs.length);
+ int offset = 0;
+ for (int i = rgdispidNamedArgs.length; i > 0; i--) {
+ OS.MoveMemory(pDispParams.rgdispidNamedArgs + offset, new int[] {rgdispidNamedArgs[i-1]}, 4);
+ offset += 4;
+ }
+ }
+
+ // invoke the method
+ EXCEPINFO excepInfo = new EXCEPINFO();
+ int[] pArgErr = new int[1];
+ long pVarResultAddress = 0;
+ if (pVarResult != null) pVarResultAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
+ int result = objIDispatch.Invoke(dispIdMember, new GUID(), COM.LOCALE_USER_DEFAULT, wFlags, pDispParams, pVarResultAddress, excepInfo, pArgErr);
+
+ if (pVarResultAddress != 0){
+ pVarResult.setData(pVarResultAddress);
+ COM.VariantClear(pVarResultAddress);
+ OS.GlobalFree(pVarResultAddress);
+ }
+
+ // free the Dispparams resources
+ if (pDispParams.rgdispidNamedArgs != 0){
+ OS.GlobalFree(pDispParams.rgdispidNamedArgs);
+ }
+ if (pDispParams.rgvarg != 0) {
+ int offset = 0;
+ for (int i = 0, length = rgvarg.length; i < length; i++){
+ COM.VariantClear(pDispParams.rgvarg + offset);
+ offset += VARIANT.sizeof;
+ }
+ OS.GlobalFree(pDispParams.rgvarg);
+ }
+
+ // save error string and cleanup EXCEPINFO
+ manageExcepinfo(result, excepInfo);
+
+ return result;
+}
+/**
+ * Invokes a method on the OLE Object; the method has no parameters. In the early days of OLE,
+ * the IDispatch interface was not well defined and some applications (mainly Word) did not support
+ * a return value. For these applications, call this method instead of calling
+ * The OleClientSite provides the following capabilities:
+ * This object implements the OLE Interfaces IUnknown, IOleClientSite, IAdviseSink,
+ * IOleInPlaceSite
+ *
+ * Note that although this class is a subclass of
+ * IMPORTANT: This method is not part of the public
+ * API for In addition to the behaviour provided by OleClientSite, this object provides the following:
+ * This object implements the OLE Interfaces IOleControlSite, IDispatch, and IPropertyNotifySink.
+ *
+ * Note that although this class is a subclass of
+ * IMPORTANT: This method is not part of the public
+ * API for
+* This method notifies all listeners that an event
+* has occurred.
+*
+* @param eventType the desired SWT event
+* @param event the event data
+*
+* @exception IllegalArgumentException OleFrame allows the container to do the following: When an OLE Document is in-place active, the Document provides its own menus but the application
+ * is given the opportunity to merge some of its menus into the menubar. The application
+ * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
+ * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
+ * menu locations. Note that an application can insert more than one menu into a single location.
+ *
+ * @return the application menu items that will appear in the Container location when an OLE Document
+ * is in-place activated.
+ *
+ */
+public MenuItem[] getContainerMenus(){
+ return containerMenuItems;
+}
+/**
+ *
+ * Returns the application menu items that will appear in the File location when an OLE Document
+ * is in-place activated.
+ *
+ * When an OLE Document is in-place active, the Document provides its own menus but the application
+ * is given the opportunity to merge some of its menus into the menubar. The application
+ * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
+ * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
+ * menu locations. Note that an application can insert more than one menu into a single location.
+ *
+ * @return the application menu items that will appear in the File location when an OLE Document
+ * is in-place activated.
+ *
+ */
+public MenuItem[] getFileMenus(){
+ return fileMenuItems;
+}
+long getIOleInPlaceFrame() {
+ return iOleInPlaceFrame.getAddress();
+}
+private long getMenuItemID(long hMenu, int index) {
+ long id = 0;
+ MENUITEMINFO lpmii = new MENUITEMINFO();
+ lpmii.cbSize = MENUITEMINFO.sizeof;
+ lpmii.fMask = OS.MIIM_STATE | OS.MIIM_SUBMENU | OS.MIIM_ID;
+ OS.GetMenuItemInfo(hMenu, index, true, lpmii);
+ if ((lpmii.fState & OS.MF_POPUP) == OS.MF_POPUP) {
+ id = lpmii.hSubMenu;
+ } else {
+ id = lpmii.wID;
+ }
+ return id;
+}
+private int GetWindow(long phwnd) {
+ if (phwnd != 0) {
+ OS.MoveMemory(phwnd, new long[] {handle}, C.PTR_SIZEOF);
+ }
+ return COM.S_OK;
+}
+/**
+ *
+ * Returns the application menu items that will appear in the Window location when an OLE Document
+ * is in-place activated.
+ *
+ * When an OLE Document is in-place active, the Document provides its own menus but the application
+ * is given the opportunity to merge some of its menus into the menubar. The application
+ * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
+ * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
+ * menu locations. Note that an application can insert more than one menu into a single location.
+ *
+ * @return the application menu items that will appear in the Window location when an OLE Document
+ * is in-place activated.
+ *
+ */
+public MenuItem[] getWindowMenus(){
+ return windowMenuItems;
+}
+private int InsertMenus(long hmenuShared, long lpMenuWidths) {
+ // locate menu bar
+ Menu menubar = getShell().getMenuBar();
+ if (menubar == null || menubar.isDisposed()) {
+ OS.MoveMemory(lpMenuWidths, new int[] {0}, 4);
+ return COM.S_OK;
+ }
+ long hMenu = menubar.handle;
+
+ // Create a holder for menu information. This will be passed down to
+ // the OS and the OS will fill in the requested information for each menu.
+ MENUITEMINFO lpmii = new MENUITEMINFO();
+ long hHeap = OS.GetProcessHeap();
+ int cch = 128;
+ int byteCount = cch * TCHAR.sizeof;
+ long pszText = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ lpmii.cbSize = MENUITEMINFO.sizeof;
+ lpmii.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_SUBMENU | OS.MIIM_DATA;
+ lpmii.dwTypeData = pszText;
+ lpmii.cch = cch;
+
+ // Loop over all "File-like" menus in the menubar and get information about the
+ // item from the OS.
+ int fileMenuCount = 0;
+ int newindex = 0;
+ if (this.fileMenuItems != null) {
+ for (int i = 0; i < this.fileMenuItems.length; i++) {
+ MenuItem item = this.fileMenuItems[i];
+ if (item != null) {
+ int index = item.getParent().indexOf(item);
+ lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the
+ // exact number of characters in name. Reset it to our max size
+ // before each call.
+ if (OS.GetMenuItemInfo(hMenu, index, true, lpmii)) {
+ if (OS.InsertMenuItem(hmenuShared, newindex, true, lpmii)) {
+ // keep track of the number of items
+ fileMenuCount++;
+ newindex++;
+ }
+ }
+ }
+ }
+ }
+
+ // copy the menu item count information to the pointer
+ OS.MoveMemory(lpMenuWidths, new int[] {fileMenuCount}, 4);
+
+ // Loop over all "Container-like" menus in the menubar and get information about the
+ // item from the OS.
+ int containerMenuCount = 0;
+ if (this.containerMenuItems != null) {
+ for (int i = 0; i < this.containerMenuItems.length; i++) {
+ MenuItem item = this.containerMenuItems[i];
+ if (item != null) {
+ int index = item.getParent().indexOf(item);
+ lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the
+ // exact number of characters in name. Reset it to a large number
+ // before each call.
+ if (OS.GetMenuItemInfo(hMenu, index, true, lpmii)) {
+ if (OS.InsertMenuItem(hmenuShared, newindex, true, lpmii)) {
+ // keep track of the number of items
+ containerMenuCount++;
+ newindex++;
+ }
+ }
+ }
+ }
+ }
+
+ // copy the menu item count information to the pointer
+ OS.MoveMemory(lpMenuWidths + 8, new int[] {containerMenuCount}, 4);
+
+ // Loop over all "Window-like" menus in the menubar and get information about the
+ // item from the OS.
+ int windowMenuCount = 0;
+ if (this.windowMenuItems != null) {
+ for (int i = 0; i < this.windowMenuItems.length; i++) {
+ MenuItem item = this.windowMenuItems[i];
+ if (item != null) {
+ int index = item.getParent().indexOf(item);
+ lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the
+ // exact number of characters in name. Reset it to a large number
+ // before each call.
+ if (OS.GetMenuItemInfo(hMenu, index, true, lpmii)) {
+ if (OS.InsertMenuItem(hmenuShared, newindex, true, lpmii)) {
+ // keep track of the number of items
+ windowMenuCount++;
+ newindex++;
+ }
+ }
+ }
+ }
+ }
+
+ // copy the menu item count information to the pointer
+ OS.MoveMemory(lpMenuWidths + 16, new int[] {windowMenuCount}, 4);
+
+ // free resources used in querying the OS
+ if (pszText != 0)
+ OS.HeapFree(hHeap, 0, pszText);
+ return COM.S_OK;
+}
+void onActivate(Event e) {
+ if (objIOleInPlaceActiveObject != null) {
+ objIOleInPlaceActiveObject.OnFrameWindowActivate(true);
+ }
+}
+void onDeactivate(Event e) {
+ if (objIOleInPlaceActiveObject != null) {
+ objIOleInPlaceActiveObject.OnFrameWindowActivate(false);
+ }
+}
+private void onDispose(Event e) {
+
+ releaseObjectInterfaces();
+ currentdoc = null;
+
+ this.Release();
+ removeListener(SWT.Activate, listener);
+ removeListener(SWT.Deactivate, listener);
+ removeListener(SWT.Dispose, listener);
+ removeListener(SWT.Resize, listener);
+ removeListener(SWT.Move, listener);
+}
+void onFocusIn(Event e) {
+ if (lastActivatedMenuHandle != newMenuHandle)
+ currentdoc.doVerb(OLE.OLEIVERB_SHOW);
+ if (OS.GetMenu(shellHandle) != newMenuHandle)
+ OS.SetMenu(shellHandle, newMenuHandle);
+}
+void onFocusOut(Event e) {
+ Control control = getDisplay().getFocusControl();
+ if (OS.GetMenu(shellHandle) != oldMenuHandle && control != null && control.handle != shellHandle)
+ OS.SetMenu(shellHandle, oldMenuHandle);
+}
+private void onResize(Event e) {
+ if (objIOleInPlaceActiveObject != null) {
+ RECT lpRect = new RECT();
+ OS.GetClientRect(handle, lpRect);
+ objIOleInPlaceActiveObject.ResizeBorder(lpRect, iOleInPlaceFrame.getAddress(), true);
+ }
+}
+private int QueryInterface(long riid, long ppvObject) {
+// implements IUnknown, IOleInPlaceFrame, IOleContainer, IOleInPlaceUIWindow
+ if (riid == 0 || ppvObject == 0)
+ return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+ if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIOleInPlaceFrame) ) {
+ OS.MoveMemory(ppvObject, new long [] {iOleInPlaceFrame.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+
+ OS.MoveMemory(ppvObject, new long [] {0}, C.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+/**
+ * Decrement the count of references to this instance
+ *
+ * @return the current reference count
+ */
+int Release() {
+ refCount--;
+ if (refCount == 0){
+ disposeCOMInterfaces();
+ if (COM.FreeUnusedLibraries) {
+ COM.CoFreeUnusedLibraries();
+ }
+ }
+ return refCount;
+}
+private void releaseObjectInterfaces() {
+ if (objIOleInPlaceActiveObject != null) {
+ objIOleInPlaceActiveObject.Release();
+ }
+ objIOleInPlaceActiveObject = null;
+}
+private int RemoveMenus(long hmenuShared) {
+
+ Menu menubar = getShell().getMenuBar();
+ if (menubar == null || menubar.isDisposed()) return COM.S_FALSE;
+
+ long hMenu = menubar.handle;
+
+ List When an OLE Document is in-place active, the Document provides its own menus but the application
+ * is given the opportunity to merge some of its menus into the menubar. The application
+ * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
+ * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
+ * menu locations. Note that an application can insert more than one menu into a single location.
+ *
+ * This method must be called before in place activation of the OLE Document. After the Document
+ * is activated, the menu bar will not be modified until a subsequent activation.
+ *
+ * @param containerMenus an array of top level MenuItems to be inserted into the Container location of
+ * the menubar
+ */
+public void setContainerMenus(MenuItem[] containerMenus){
+ containerMenuItems = containerMenus;
+}
+OleClientSite getCurrentDocument() {
+ return currentdoc;
+}
+void setCurrentDocument(OleClientSite doc) {
+ currentdoc = doc;
+
+ if (currentdoc != null && objIOleInPlaceActiveObject != null) {
+ RECT lpRect = new RECT();
+ OS.GetClientRect(handle, lpRect);
+ objIOleInPlaceActiveObject.ResizeBorder(lpRect, iOleInPlaceFrame.getAddress(), true);
+ }
+}
+/**
+ *
+ * Specify the menu items that should appear in the File location when an OLE Document
+ * is in-place activated.
+ *
+ * When an OLE Document is in-place active, the Document provides its own menus but the application
+ * is given the opportunity to merge some of its menus into the menubar. The application
+ * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
+ * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
+ * menu locations. Note that an application can insert more than one menu into a single location.
+ *
+ * This method must be called before in place activation of the OLE Document. After the Document
+ * is activated, the menu bar will not be modified until a subsequent activation.
+ *
+ * @param fileMenus an array of top level MenuItems to be inserted into the File location of
+ * the menubar
+ */
+public void setFileMenus(MenuItem[] fileMenus){
+ fileMenuItems = fileMenus;
+}
+private int SetMenu(long hmenuShared, long holemenu, long hwndActiveObject) {
+ long inPlaceActiveObject = 0;
+ if (objIOleInPlaceActiveObject != null)
+ inPlaceActiveObject = objIOleInPlaceActiveObject.getAddress();
+
+ Menu menubar = getShell().getMenuBar();
+ if (menubar == null || menubar.isDisposed()){
+ return COM.OleSetMenuDescriptor(0, getShell().handle, hwndActiveObject, iOleInPlaceFrame.getAddress(), inPlaceActiveObject);
+ }
+
+ long handle = menubar.getShell().handle;
+
+ if (hmenuShared == 0 && holemenu == 0) {
+ // re-instate the original menu - this occurs on deactivation
+ hmenuShared = menubar.handle;
+ }
+ if (hmenuShared == 0) return COM.E_FAIL;
+
+ shellHandle = handle;
+ oldMenuHandle = menubar.handle;
+ newMenuHandle = hmenuShared;
+ lastActivatedMenuHandle = newMenuHandle;
+
+ return COM.OleSetMenuDescriptor(holemenu, handle, hwndActiveObject, iOleInPlaceFrame.getAddress(), inPlaceActiveObject);
+}
+/**
+ *
+ * Set the menu items that should appear in the Window location when an OLE Document
+ * is in-place activated.
+ *
+ * When an OLE Document is in-place active, the Document provides its own menus but the application
+ * is given the opportunity to merge some of its menus into the menubar. The application
+ * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
+ * (far right just before Help). The OLE Document retains control of the Edit, Object and Help
+ * menu locations. Note that an application can insert more than one menu into a single location.
+ *
+ * This method must be called before in place activation of the OLE Document. After the Document
+ * is activated, the menu bar will not be modified until a subsequent activation.
+ *
+ * @param windowMenus an array of top level MenuItems to be inserted into the Window location of
+ * the menubar
+ */
+public void setWindowMenus(MenuItem[] windowMenus){
+ windowMenuItems = windowMenus;
+}
+private boolean translateOleAccelerator(MSG msg) {
+ if (objIOleInPlaceActiveObject == null) return false;
+ int result = objIOleInPlaceActiveObject.TranslateAccelerator(msg);
+ return (result != COM.S_FALSE && result != COM.E_NOTIMPL);
+}
+private int TranslateAccelerator(long lpmsg, int wID){
+ Menu menubar = getShell().getMenuBar();
+ if (menubar == null || menubar.isDisposed() || !menubar.isEnabled()) return COM.S_FALSE;
+ if (wID < 0) return COM.S_FALSE;
+
+ Shell shell = menubar.getShell();
+ long hwnd = shell.handle;
+ long hAccel = OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0);
+ if (hAccel == 0) return COM.S_FALSE;
+
+ MSG msg = new MSG();
+ OS.MoveMemory(msg, lpmsg, MSG.sizeof);
+ int result = OS.TranslateAccelerator(hwnd, hAccel, msg);
+ return result == 0 ? COM.S_FALSE : COM.S_OK;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleFunctionDescription.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleFunctionDescription.java
new file mode 100644
index 000000000..5f9678c45
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleFunctionDescription.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+
+public class OleFunctionDescription {
+
+ public int id;
+ public String name;
+ public OleParameterDescription[] args;
+ public int optionalArgCount;
+ public short returnType;
+ public int invokeKind;
+ public int funcKind;
+ public short flags;
+ public int callingConvention;
+ public String documentation;
+ public String helpFile;
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleListener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleListener.java
new file mode 100644
index 000000000..455af5a79
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleListener.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+
+/**
+ * Implementers of
+ * After creating an instance of a class that implements this
+ * interface it can be added to an
+* This method notifies all listeners that an event
+* has occurred.
+*
+* @param eventType the desired SWT event
+* @param event the event data
+*
+* @exception IllegalArgumentException It is used within the OleAutomation object for getting a property, setting a property or invoking
+ * a method on an OLE Control or OLE Document.
+ *
+ */
+public final class Variant {
+ /**
+ * The size in bytes of a native VARIANT struct.
+ */
+ public static final int sizeof = VARIANT.sizeof;
+
+ private short type; // OLE.VT_* type
+ private boolean booleanData;
+ private byte byteData;
+ private short shortData;
+ private char charData;
+ private int intData;
+ private long longData;
+ private float floatData;
+ private double doubleData;
+ private String stringData;
+ private long byRefPtr;
+ private IDispatch dispatchData;
+ private IUnknown unknownData;
+
+ /**
+ * A shared Variant instance with type VT_NULL.
+ *
+ * @since 3.7
+ */
+ public static final Variant NULL;
+ static {
+ NULL = new Variant ();
+ NULL.type = COM.VT_NULL;
+ }
+
+/**
+ * Invokes platform specific functionality to copy a variant
+ * into operating system memory.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * IMPORTANT: This method is not part of the public
+ * API for When creating a VT_BYREF Variant, you must give the full Variant type
+ * including VT_BYREF such as
+ *
+ * The caller is expected to have appropriately invoked unknown.AddRef() before creating
+ * this Variant.
+ *
+ * @since 2.0
+ *
+ * @param idispatch the IDispatch object that this Variant represents
+ *
+ */
+public Variant(IDispatch idispatch) {
+ type = COM.VT_DISPATCH;
+ dispatchData = idispatch;
+}
+/**
+ * Create a Variant object which represents an IUnknown interface as a VT_UNKNOWN.
+ *
+ * The caller is expected to have appropriately invoked unknown.AddRef() before creating
+ * this Variant.
+ *
+ * @param unknown the IUnknown object that this Variant represents
+ *
+ */
+public Variant(IUnknown unknown) {
+ type = COM.VT_UNKNOWN;
+ unknownData = unknown;
+}
+/**
+ * Create a Variant object which represents a Java long as a VT_I8.
+ *
+ * @param val the Java long value that this Variant represents
+ *
+ * @since 3.2
+ */
+ public Variant(long val) {
+ type = COM.VT_I8;
+ longData = val;
+}
+/**
+ * Create a Variant object which represents a Java String as a VT_BSTR.
+ *
+ * @param string the Java String value that this Variant represents
+ *
+ */
+public Variant(String string) {
+ type = COM.VT_BSTR;
+ stringData = string;
+}
+/**
+ * Create a Variant object which represents a Java short as a VT_I2.
+ *
+ * @param val the Java short value that this Variant represents
+ *
+ */
+public Variant(short val) {
+ type = COM.VT_I2;
+ shortData = val;
+}
+/**
+ * Create a Variant object which represents a Java boolean as a VT_BOOL.
+ *
+ * @param val the Java boolean value that this Variant represents
+ *
+ */
+public Variant(boolean val) {
+ type = COM.VT_BOOL;
+ booleanData = val;
+}
+
+/**
+ * Calling dispose will release resources associated with this Variant.
+ * If the resource is an IDispatch or IUnknown interface, Release will be called.
+ * If the resource is a ByRef pointer, nothing is released.
+ *
+ * @since 2.1
+ */
+public void dispose() {
+ if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
+ return;
+ }
+
+ switch (type) {
+ case COM.VT_DISPATCH :
+ dispatchData.Release();
+ break;
+ case COM.VT_UNKNOWN :
+ unknownData.Release();
+ break;
+ }
+
+}
+/**
+ * Returns the OleAutomation object represented by this Variant.
+ *
+ * If this Variant does not contain an OleAutomation object, an attempt is made to
+ * coerce the Variant type into an OleAutomation object. If this fails, an error is
+ * thrown. Note that OleAutomation objects must be disposed when no longer
+ * needed.
+ *
+ * @return the OleAutomation object represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain an IDispatch object, an attempt is made to
+ * coerce the Variant type into an IDIspatch object. If this fails, an error is
+ * thrown.
+ *
+ * @since 2.0
+ *
+ * @return the IDispatch object represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain a Java boolean, an attempt is made to
+ * coerce the Variant type into a Java boolean. If this fails, an error is thrown.
+ *
+ * @return the Java boolean represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain a reference to data, zero is returned.
+ *
+ * @return a pointer to the referenced data represented by this Variant or 0
+ *
+ */
+public long getByRef() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if ((type & COM.VT_BYREF)== COM.VT_BYREF) {
+ return byRefPtr;
+ }
+
+ return 0;
+}
+/**
+ * Returns the Java byte represented by this Variant.
+ *
+ * If this Variant does not contain a Java byte, an attempt is made to
+ * coerce the Variant type into a Java byte. If this fails, an error is thrown.
+ *
+ * @return the Java byte represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain a Java char, an attempt is made to
+ * coerce the Variant type into a Java char. If this fails, an error is thrown.
+ *
+ * @return the Java char represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain a Java double, an attempt is made to
+ * coerce the Variant type into a Java double. If this fails, an error is thrown.
+ *
+ * @return the Java double represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain a Java float, an attempt is made to
+ * coerce the Variant type into a Java float. If this fails, an error is thrown.
+ *
+ * @return the Java float represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain a Java int, an attempt is made to
+ * coerce the Variant type into a Java int. If this fails, an error is thrown.
+ *
+ * @return the Java int represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain a Java long, an attempt is made to
+ * coerce the Variant type into a Java long. If this fails, an error is thrown.
+ *
+ * @return the Java long represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain a Java short, an attempt is made to
+ * coerce the Variant type into a Java short. If this fails, an error is thrown.
+ *
+ * @return the Java short represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain a Java String, an attempt is made to
+ * coerce the Variant type into a Java String. If this fails, an error is thrown.
+ *
+ * @return the Java String represented by this Variant
+ *
+ * @exception SWTException If this Variant does not contain an IUnknown object, an attempt is made to
+ * coerce the Variant type into an IUnknown object. If this fails, an error is
+ * thrown.
+ *
+ * @return the IUnknown object represented by this Variant
+ *
+ * @exception SWTException
+Referencing any of the classes in this package directly guarantees
+that the code is platform specific.
+
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Setting the printer data to null is equivalent to
+ * resetting all data fields to their default values.
+ *
+ * This value can be from 1 to the maximum number of pages for the platform.
+ * Note that it is only valid if the scope is
+ * This value can be from 1 to the maximum number of pages for the platform.
+ * Note that it is only valid if the scope is
+ * This value can be from 1 to the maximum number of pages for the platform.
+ * Note that it is only valid if the scope is
+ * This value can be from 1 to the maximum number of pages for the platform.
+ * Note that it is only valid if the scope is
+ * A
+ * Application code must explicitly invoke the
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ *
+ * Note: You must dispose the printer when it is no longer required.
+ *
+ * Note: You must dispose the printer when it is no longer required.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * This must be the first method called to initiate a print job,
+ * followed by any number of startPage/endPage calls, followed by
+ * endJob. Calling startPage, endPage, or endJob before startJob
+ * will result in undefined behavior.
+ *
+ * After calling startJob, this method may be called any number of times
+ * along with a matching endPage.
+ *
+ * For a printer, this is the size of the physical page, in pixels.
+ *
+ * For a printer, this is the size of the printable area
+ * of the page, in pixels.
+ *
+ * Most printers have a minimum margin on each edge of the paper where the
+ * printer device is unable to print. This margin is known as the "trim."
+ * This method can be used to calculate the printer's minimum margins
+ * by passing in a client area of 0, 0, 0, 0 and then using the resulting
+ * x and y coordinates (which will be <= 0) to determine the minimum margins
+ * for the top and left edges of the paper, and the resulting width and height
+ * (offset by the resulting x and y) to determine the minimum margins for the
+ * bottom and right edges of the paper, as follows:
+ *
+ * Application code does not need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no
+ * The default value is
+ * This is also known as simplex printing.
+ *
+ * For portrait orientation, the long edge is vertical.
+ * For landscape orientation, the long edge is horizontal.
+ *
+ * This is also known as duplex printing.
+ *
+ * For portrait orientation, the short edge is horizontal.
+ * For landscape orientation, the short edge is vertical.
+ *
+ * This is also known as duplex tumble printing.
+ *
+ * Note: Only one of the styles ARROW, CHECK, PUSH, RADIO, and TOGGLE
+ * may be specified.
+ *
+ * Note: Only one of the styles LEFT, RIGHT, and CENTER may be specified.
+ *
+ * Note: Only one of the styles UP, DOWN, LEFT, and RIGHT may be specified
+ * when the ARROW style is specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ *
+ * When the
+ * When the receiver is of type
+ * Note: This is custom paint operation and only affects {@link SWT#PUSH} and {@link SWT#TOGGLE} buttons. If the native button
+ * has a 3D look an feel (e.g. Windows 7), this method will cause the button to look FLAT irrespective of the state of the
+ * {@link SWT#FLAT} style.
+ * For {@link SWT#CHECK} and {@link SWT#RADIO} buttons, this method delegates to {@link Control#setBackground(Color)}.
+ *
+ * Note that a Button can display an image and text simultaneously
+ * on Windows (starting with XP), GTK+ and OSX. On other platforms,
+ * a Button that has an image and text set into it will display the
+ * image or text that was set most recently.
+ *
+ * When the receiver is of type
+ * This method sets the button label. The label may include
+ * the mnemonic character but must not contain line delimiters.
+ *
+ * Mnemonics are indicated by an '&' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, a selection
+ * event occurs. On most platforms, the mnemonic appears
+ * underlined but may be emphasized in a platform specific
+ * manner. The mnemonic indicator character '&' can be
+ * escaped by doubling it in the string, causing a single
+ * '&' to be displayed.
+ *
+ * Note that a Button can display an image and text simultaneously
+ * on Windows (starting with XP), GTK+ and OSX. On other platforms,
+ * a Button that has an image and text set into it will display the
+ * image or text that was set most recently.
+ *
+ * Also note, if control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ * This class may be subclassed by custom control implementors
+ * who are building controls that are not constructed
+ * from aggregates of other controls. That is, they are either
+ * painted using SWT graphics calls or are handled by native
+ * methods.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * The caret for the control is automatically hidden
+ * and shown when the control is painted or resized,
+ * when focus is gained or lost and when an the control
+ * is scrolled. To avoid drawing on top of the caret,
+ * the programmer must hide and show the caret when
+ * drawing in the window any other time.
+ *
+ * The caret for the control is automatically hidden
+ * and shown when the control is painted or resized,
+ * when focus is gained or lost and when an the control
+ * is scrolled. To avoid drawing on top of the caret,
+ * the programmer must hide and show the caret when
+ * drawing in the window any other time.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ *
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: Since
+ * Note that although this class is a subclass of
+ * Note: Only one of the styles DROP_DOWN and SIMPLE may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: If control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ * Note: To add an item at the end of the list, use the
+ * result of calling
+ * Also note, if control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ * A
+ * Warning: This API is currently only implemented on Windows.
+ *
+ *
+ * Note: To clear the selected items in the receiver's list,
+ * use
+ * The current selection is copied to the clipboard.
+ *
+ * The current selection is first copied to the
+ * clipboard and then deleted from the widget.
+ *
+ * Note: To clear the selection in the receiver's text field,
+ * use
+ * Indexing is zero based.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ *
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ *
+ * Indexing is zero based. The range of a selection is from
+ * 0..N where N is the number of characters in the widget.
+ *
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept.
+ *
+ *
+ * @param orientation new orientation style
+ *
+ * @exception SWTException
+ * This call is ignored when the receiver is read only and
+ * the given string is not in the receiver's list.
+ *
+ * Note: The text field in a
+ * Also note, if control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ * To reset this value to the default, use
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept.
+ *
+ * Note: The
+ * Note: The
+ * This class may be subclassed by custom control implementors
+ * who are building controls that are constructed from aggregates
+ * of other controls.
+ *
+ * The style value is either one of the style constants defined in
+ * class The
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of children, so modifying the array will
+ * not affect the receiver.
+ *
+ * Use of this method is discouraged since it is the least-efficient
+ * way to trigger a layout. The use of
+ * This is equivalent to calling
+ * Note: Layout is different from painting. If a child is
+ * moved or resized such that an area in the parent is
+ * exposed, then the parent will paint. If no child is
+ * affected, the parent will not paint.
+ *
+ * It is normally more efficient to invoke {@link Control#requestLayout()}
+ * on every control which has changed in the layout than it is to invoke
+ * this method on the layout itself. Clients are encouraged to use
+ * {@link Control#requestLayout()} where possible instead of calling
+ * this method.
+ *
+ * If a child is resized as a result of a call to layout, the
+ * resize event will invoke the layout of the child. The layout
+ * will cascade down through all child widgets in the receiver's widget
+ * tree until a child is encountered that does not resize. Note that
+ * a layout due to a resize will not flush any cached information
+ * (same as
+ * Note: Layout is different from painting. If a child is
+ * moved or resized such that an area in the parent is
+ * exposed, then the parent will paint. If no child is
+ * affected, the parent will not paint.
+ *
+ * It is normally more efficient to invoke {@link Control#requestLayout()}
+ * on every control which has changed in the layout than it is to invoke
+ * this method on the layout itself. Clients are encouraged to use
+ * {@link Control#requestLayout()} where possible instead of calling
+ * this method.
+ *
+ * Note: Layout is different from painting. If a child is
+ * moved or resized such that an area in the parent is
+ * exposed, then the parent will paint. If no child is
+ * affected, the parent will not paint.
+ *
+ * It is normally more efficient to invoke {@link Control#requestLayout()}
+ * on every control which has changed in the layout than it is to invoke
+ * this method on the layout itself. Clients are encouraged to use
+ * {@link Control#requestLayout()} where possible instead of calling
+ * this method.
+ *
+ * Note: Layout is different from painting. If a child is
+ * moved or resized such that an area in the parent is
+ * exposed, then the parent will paint. If no child is
+ * affected, the parent will not paint.
+ *
+ * The parameter
+ * When the
+ * When the
+ * The
+ * Note: Layout is different from painting. If a child is
+ * moved or resized such that an area in the parent is
+ * exposed, then the parent will paint. If no child is
+ * affected, the parent will not paint.
+ *
+ * Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified.
+ *
+ * IMPORTANT: This class is intended to be subclassed only
+ * within the SWT implementation.
+ *
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * NOTE: If
+ * Warning: This API is currently only implemented on Windows and Cocoa.
+ * SWT doesn't send Gesture or Touch events on GTK.
+ *
+ * When a key listener is added to a control, the control
+ * will take part in widget traversal. By default, all
+ * traversal keys (such as the tab key and so on) are
+ * delivered to the control. In order for a control to take
+ * part in traversal, it should listen for traversal events.
+ * Otherwise, the user can traverse into a control but not
+ * out. Note that native controls such as table and tree
+ * implement key traversal in the operating system. It is
+ * not necessary to add traversal listeners for these controls,
+ * unless you want to override the default traversal.
+ *
+ * NOTE: You must also call
+ * Warning: This API is currently only implemented on Windows and Cocoa.
+ * SWT doesn't send Gesture or Touch events on GTK.
+ *
+ * The preferred size of a control is the size that it would
+ * best be displayed at. The width hint and height hint arguments
+ * allow the caller to ask a control questions such as "Given a particular
+ * width, how high does the control need to be to show all of the contents?"
+ * To indicate that the caller does not wish to constrain a particular
+ * dimension, the constant
+ * The preferred size of a control is the size that it would
+ * best be displayed at. The width hint and height hint arguments
+ * allow the caller to ask a control questions such as "Given a particular
+ * width, how high does the control need to be to show all of the contents?"
+ * To indicate that the caller does not wish to constrain a particular
+ * dimension, the constant
+ * If the changed flag is By default, a drag is detected when the gesture
+ * occurs anywhere within the client area of a control.
+ * Some controls, such as tables and trees, override this
+ * behavior. In addition to the operating system specific
+ * drag gesture, they require the mouse to be inside an
+ * item. Custom widget writers can use By default, a drag is detected when the gesture
+ * occurs anywhere within the client area of a control.
+ * Some controls, such as tables and trees, override this
+ * behavior. In addition to the operating system specific
+ * drag gesture, they require the mouse to be inside an
+ * item. Custom widget writers can use
+ * If this is the first time this object is requested,
+ * then the object is created and returned. The object
+ * returned by getAccessible() does not need to be disposed.
+ *
+ * Note: This operation is a hint and may be overridden by the platform.
+ * For example, on some versions of Windows the background of a TabFolder,
+ * is a gradient rather than a solid color.
+ *
+ * When the mouse pointer passes over a control its appearance
+ * is changed to match the control's cursor.
+ *
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * If the changed flag is
+ * The control will not be repositioned synchronously. This method is
+ * fast-running and only marks the control for future participation in
+ * a deferred layout.
+ *
+ * Invoking this method multiple times before the layout occurs is an
+ * inexpensive no-op.
+ *
+ * @since 3.105
+ */
+public void requestLayout () {
+ getShell ().layout (new Control[] {this}, SWT.DEFER);
+}
+
+/**
+ * Causes the entire bounds of the receiver to be marked
+ * as needing to be redrawn. The next time a paint request
+ * is processed, the control will be completely painted,
+ * including the background.
+ *
+ * Schedules a paint request if the invalidated area is visible
+ * or becomes visible later. It is not necessary for the caller
+ * to explicitly call {@link #update()} after calling this method,
+ * but depending on the platform, the automatic repaints may be
+ * delayed considerably.
+ *
+ * Schedules a paint request if the invalidated area is visible
+ * or becomes visible later. It is not necessary for the caller
+ * to explicitly call {@link #update()} after calling this method,
+ * but depending on the platform, the automatic repaints may be
+ * delayed considerably.
+ *
+ * Note: This operation is a hint and may be overridden by the platform.
+ *
+ * Note: This operation is a hint and may be overridden by the platform.
+ * For example, on Windows the background of a Button cannot be changed.
+ *
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause that
+ * value to be set to zero instead.
+ *
+ * Note: On GTK, attempting to set the width or height of the
+ * receiver to a number higher or equal 2^14 will cause them to be
+ * set to (2^14)-1 instead.
+ *
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause that
+ * value to be set to zero instead.
+ *
+ * Note: On GTK, attempting to set the width or height of the
+ * receiver to a number higher or equal 2^14 will cause them to be
+ * set to (2^14)-1 instead.
+ *
+ * When the mouse pointer passes over a control its appearance
+ * is changed to match the control's cursor.
+ *
+ * Note: This operation is a hint and may be overridden by the platform.
+ *
+ * Note: Disposing of a control that has a pop up menu will
+ * dispose of the menu. To avoid this behavior, set the
+ * menu to null before the control is disposed.
+ *
+ *
+ * @param orientation new orientation style
+ *
+ * @exception SWTException
+ * Note: This operation is a hint and may not be supported on some
+ * platforms or for some widgets.
+ *
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause that
+ * value to be set to zero instead.
+ *
+ * Note: On GTK, attempting to set the width or height of the
+ * receiver to a number higher or equal 2^14 will cause them to be
+ * set to (2^14)-1 instead.
+ *
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause them to be
+ * set to zero instead.
+ *
+ * Note: On GTK, attempting to set the width or height of the
+ * receiver to a number higher or equal 2^14 will cause them to be
+ * set to (2^14)-1 instead.
+ *
+ *
+ * Warning: This API is currently only implemented on Windows.
+ * It doesn't set the base text direction on GTK and Cocoa.
+ *
+ * The mnemonic indicator (character '&') is not displayed in a tool tip.
+ * To display a single '&' in the tool tip, the character '&' can be
+ * escaped by doubling it in the string.
+ *
+ * NOTE: This operation is a hint and behavior is platform specific, on Windows
+ * for CJK-style mnemonics of the form " (&C)" at the end of the tooltip text
+ * are not shown in tooltip.
+ *
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ *
+ * NOTE: To properly map a rectangle or a corner of a rectangle on a right-to-left platform, use
+ * {@link Display#map(Control, Control, Rectangle)}.
+ *
+ * NOTE: To properly map a rectangle or a corner of a rectangle on a right-to-left platform, use
+ * {@link Display#map(Control, Control, Rectangle)}.
+ *
+ * NOTE: To properly map a rectangle or a corner of a rectangle on a right-to-left platform, use
+ * {@link Display#map(Control, Control, Rectangle)}.
+ *
+ * NOTE: To properly map a rectangle or a corner of a rectangle on a right-to-left platform, use
+ * {@link Display#map(Control, Control, Rectangle)}.
+ * Valid traversal values are
+ * Valid traversal values are
+ *
+ * Note: This method does not cause a redraw.
+ *
+ * The item children that may be added to instances of this class
+ * must be of type
+ * Note that although this class is a subclass of
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Specifically, the indices of the returned array represent
+ * the current visual order of the items, and the contents
+ * of the array represent the creation order of the items.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * The wrap indices are the indices of all item(s) in the receiver
+ * that will begin on a new row. The indices are given in the order
+ * specified by the item order. The 0th item always begins the first
+ * row, therefore it does not count as a wrap index. If wrap indices
+ * is null or empty, the items will be placed on one line.
+ *
+ * The sizes are specified in an array of points whose x and y
+ * coordinates describe the new widths and heights (respectively)
+ * of the receiver's items in the order specified by the item order.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * The style value is either one of the style constants defined in
+ * class
+ * If
+ * The preferred size of a
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause that
+ * value to be set to zero instead.
+ *
+ * Note: Attempting to set the width or height of the
+ * receiver to a negative number will cause them to be
+ * set to zero instead.
+ *
+ * Note that although this class is a subclass of
+ * Note: Only one of the styles DATE, TIME, or CALENDAR may be specified,
+ * and only one of the styles SHORT, MEDIUM, or LONG may be specified.
+ * The DROP_DOWN style is only valid with the DATE style.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ *
+ * The first day of the month is 1, and the last day depends on the month and year.
+ *
+ * Hours is an integer between 0 and 23.
+ *
+ * Minutes is an integer between 0 and 59.
+ *
+ * The first month of the year is 0, and the last month is 11.
+ *
+ * Seconds is an integer between 0 and 59.
+ *
+ * The first year is 1752 and the last year is 9999.
+ *
+ * This is the recommended way to set the date, because setting the year,
+ * month, and day separately may result in invalid intermediate dates.
+ *
+ * The first day of the month is 1, and the last day depends on the month and year.
+ * If the specified day is not valid for the receiver's month and year, then it is ignored.
+ *
+ * Hours is an integer between 0 and 23.
+ *
+ * Minutes is an integer between 0 and 59.
+ *
+ * The first month of the year is 0, and the last month is 11.
+ * If the specified month is not valid for the receiver's day and year, then it is ignored.
+ *
+ * Seconds is an integer between 0 and 59.
+ *
+ * The first year is 1752 and the last year is 9999.
+ * If the specified year is not valid for the receiver's day and month, then it is ignored.
+ *
+ * IMPORTANT: This class was intended to be abstract and
+ * should never be referenced or instantiated.
+ * Instead, the class
+ * Instances are always displayed in one of the maximized,
+ * minimized or normal states:
+ *
+ * IMPORTANT: This class is intended to be subclassed only
+ * within the SWT implementation.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: This method will return null if called before
+ *
+ * Note: This method will return an empty array if called before
+ *
+ *
+ * @return the maximized state
+ *
+ * @exception SWTException
+ *
+ * @return the minimized state
+ *
+ * @exception SWTException
+ * The default button is the button that is selected when
+ * the receiver is active and the user presses ENTER.
+ *
+ * Note: The result of intermixing calls to
+ * Note: The result of intermixing calls to
+ * Note: If control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ * This class can also be used as the abstract superclass
+ * for user-designed dialogs. Such dialogs usually consist
+ * of a Shell with child widgets. The basic template for a
+ * user-defined dialog typically looks something like this:
+ * Note: The modality styles supported by this class
+ * are treated as HINTs, because not all are supported
+ * by every subclass on every platform. If a modality style is
+ * not supported, it is "upgraded" to a more restrictive modality
+ * style that is supported. For example, if
+ * Note: Only one of the styles APPLICATION_MODAL, PRIMARY_MODAL,
+ * and SYSTEM_MODAL may be specified.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * IMPORTANT: See the comment in
+ * Note that, the value which is returned by this method may
+ * not match the value which was provided to the constructor
+ * when the receiver was created.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note that the path string is platform dependent.
+ * For convenience, either '/' or '\' can be used
+ * as a path separator.
+ *
+ * NOTE: This operation is a hint and is not supported on some platforms. For
+ * example, on Windows (Vista and later), the
+ * Applications which are built with SWT will almost always
+ * require only a single display. In particular, some platforms
+ * which SWT supports will not allow more than one active
+ * display. In other words, some platforms do not support
+ * creating a new display if one already exists that has not been
+ * sent the
+ * In SWT, the thread which creates a
+ * Enforcing these attributes allows SWT to be implemented directly
+ * on the underlying operating system's event model. This has
+ * numerous benefits including smaller footprint, better use of
+ * resources, safer memory management, clearer program logic,
+ * better performance, and fewer overall operating system threads
+ * required. The down side however, is that care must be taken
+ * (only) when constructing multi-threaded applications to use the
+ * inter-thread communication mechanisms which this class provides
+ * when required.
+ *
+ * All SWT API methods which may only be called from the user-interface
+ * thread are distinguished in their documentation by indicating that
+ * they throw the "
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ *
+ * Note: The resulting display is marked as the current
+ * display. If this is the first display which has been
+ * constructed since the application started, it is also
+ * marked as the default display.
+ *
+ * Setting the type of an event to
+ * Note that at the time the runnable is invoked, widgets
+ * that have the receiver as their display may have been
+ * disposed. Therefore, it is necessary to check for this
+ * case inside the runnable before accessing the widget.
+ *
+ * IMPORTANT: See the comment in
+ * This method is called before Class
it is assumed that
+ * the method is a static method on that class.
+ *
+ *
+ * Callback (Object, String, Type, Type [])
Class
+ * it is assumed that the method is a static method on that
+ * class.
+ *
+ *
+ * Callback (Object, String, Type, Type [])
true
if the arguments should be passed in an array and false otherwise
+ */
+public Callback (Object object, String method, int argCount, boolean isArrayBased) {
+ this (object, method, argCount, isArrayBased, 0);
+}
+
+/**
+ * Constructs a new instance of this class given an object
+ * to send the message to, a string naming the method to
+ * invoke, an argument count, a flag indicating whether
+ * or not the arguments will be passed in an array and a value
+ * to return when an exception happens. Note that, if
+ * the object is an instance of Class
+ * it is assumed that the method is a static method on that
+ * class.
+ *
+ *
+ * Callback (Object, String, Type, Type [])
true
if the arguments should be passed in an array and false otherwise
+ * @param errorResult the return value if the java code throws an exception
+ */
+public Callback (Object object, String method, int argCount, boolean isArrayBased, long errorResult) {
+
+ /* Set the callback fields */
+ this.object = object;
+ this.method = method;
+ this.argCount = argCount;
+ this.isStatic = object instanceof Class;
+ this.isArrayBased = isArrayBased;
+ this.errorResult = errorResult;
+
+ /* Inline the common cases */
+ if (isArrayBased) {
+ signature = SIGNATURE_N;
+ } else {
+ switch (argCount) {
+ case 0: signature = SIGNATURE_0; break; //$NON-NLS-1$
+ case 1: signature = SIGNATURE_1; break; //$NON-NLS-1$
+ case 2: signature = SIGNATURE_2; break; //$NON-NLS-1$
+ case 3: signature = SIGNATURE_3; break; //$NON-NLS-1$
+ case 4: signature = SIGNATURE_4; break; //$NON-NLS-1$
+ default:
+ signature = getSignature(argCount);
+ }
+ }
+
+ /* Bind the address */
+ address = bind (this, object, method, signature, argCount, isStatic, isArrayBased, errorResult);
+}
+
+
+/**
+ *
+ * long method (long ...)
+ * Which is suitable for int/long and pointers.
+ * This constructor is used if you need to use a different return/argument type, e.g double. See Bug 510538
+ *
Class
it is assumed that
+ * the method is a static method on that class. long /*int*/
+ *
+ *
+ *
+ *
+ * void myMethod(long /*int*/ arg1, double arg2)
+ * Then you would call this callback like:
+ * Callback (this, "myMethod", void.class, new Type []{long.class, double.class});
+ * void.class, long.class, double.class
+ * @param arguments specify the list of arguments like new Type [] {long.class, double.class }
+ */
+public Callback (Object object, String method, Type returnType, Type [] arguments) {
+ /* Set the callback fields */
+ this.object = object;
+ this.method = method;
+ this.argCount = arguments != null ? arguments.length : 0;
+ this.isStatic = object instanceof Class;
+ this.isArrayBased = false;
+ this.errorResult = 0;
+
+ Function Callback
objects to be invoked. This method is used
+ * to safely shut down SWT when it is run within environments
+ * which can generate spurious events.
+ * Callback
objects to be invoked. This method is used
+ * to safely shut down SWT when it is run within environments
+ * which can generate spurious events.
+ *
+ *
+ */
+public final class Compatibility {
+
+/**
+ * Answers the most negative (i.e. closest to negative infinity)
+ * integer value which is greater than or equal to the number obtained by dividing
+ * the first argument p by the second argument q.
+ *
+ * @param p numerator
+ * @param q denominator (must be different from zero)
+ * @return the ceiling of the rational number p / q.
+ */
+public static int ceil(int p, int q) {
+ return (int)Math.ceil((float)p / q);
+}
+
+/**
+ * Answers the result of rounding to the closest integer the number obtained
+ * by dividing the first argument p by the second argument q.
+ *
+ *
+ */
+public static int pow2(int n) {
+ if (n >= 1 && n <= 30)
+ return 2 << (n - 1);
+ else if (n != 0) {
+ SWT.error(SWT.ERROR_INVALID_RANGE);
+ }
+ return 1;
+}
+
+/**
+ * Execute prog[0] in a separate platform process if the
+ * underlying platform supports this.
+ *
+ *
+ * The current default is "integer200".
+ */
+ private static final String SWT_AUTOSCALE = "swt.autoScale";
+
+ /**
+ * System property that controls the method for scaling images:
+ *
+ *
+ * The current default is to use "nearest", except on
+ * GTK when the deviceZoom is not an integer multiple of 100%.
+ * The smooth strategy currently doesn't work on Win32 and Cocoa, see
+ * bug 493455.
+ */
+ private static final String SWT_AUTOSCALE_METHOD = "swt.autoScale.method";
+ static {
+ autoScaleValue = System.getProperty (SWT_AUTOSCALE);
+
+ String value = System.getProperty (SWT_AUTOSCALE_METHOD);
+ if (value != null) {
+ if (AutoScaleMethod.NEAREST.name().equalsIgnoreCase(value)) {
+ autoScaleMethod = autoScaleMethodSetting = AutoScaleMethod.NEAREST;
+ } else if (AutoScaleMethod.SMOOTH.name().equalsIgnoreCase(value)) {
+ autoScaleMethod = autoScaleMethodSetting = AutoScaleMethod.SMOOTH;
+ }
+ }
+ }
+
+/**
+ * Auto-scale down ImageData
+ */
+public static ImageData autoScaleDown (Device device, final ImageData imageData) {
+ if (deviceZoom == 100 || imageData == null || (device != null && !device.isAutoScalable())) return imageData;
+ float scaleFactor = 1.0f / getScalingFactor ();
+ return autoScaleImageData(device, imageData, scaleFactor);
+}
+
+public static int[] autoScaleDown(int[] pointArray) {
+ if (deviceZoom == 100 || pointArray == null) return pointArray;
+ float scaleFactor = getScalingFactor ();
+ int [] returnArray = new int[pointArray.length];
+ for (int i = 0; i < pointArray.length; i++) {
+ returnArray [i] = Math.round (pointArray [i] / scaleFactor);
+ }
+ return returnArray;
+}
+
+public static int[] autoScaleDown(Drawable drawable, int[] pointArray) {
+ if (drawable != null && !drawable.isAutoScalable ()) return pointArray;
+ return autoScaleDown (pointArray);
+}
+
+/**
+ * Auto-scale up float array dimensions.
+ */
+public static float[] autoScaleDown (float size[]) {
+ if (deviceZoom == 100 || size == null) return size;
+ float scaleFactor = getScalingFactor ();
+ float scaledSize[] = new float[size.length];
+ for (int i = 0; i < scaledSize.length; i++) {
+ scaledSize[i] = size[i] / scaleFactor;
+ }
+ return scaledSize;
+}
+
+/**
+ * Auto-scale up float array dimensions if enabled for Drawable class.
+ */
+public static float[] autoScaleDown (Drawable drawable, float size[]) {
+ if (drawable != null && !drawable.isAutoScalable ()) return size;
+ return autoScaleDown (size);
+}
+
+/**
+ * Auto-scale down int dimensions.
+ */
+public static int autoScaleDown (int size) {
+ if (deviceZoom == 100 || size == SWT.DEFAULT) return size;
+ float scaleFactor = getScalingFactor ();
+ return Math.round (size / scaleFactor);
+}
+/**
+ * Auto-scale down int dimensions if enabled for Drawable class.
+ */
+public static int autoScaleDown (Drawable drawable, int size) {
+ if (drawable != null && !drawable.isAutoScalable ()) return size;
+ return autoScaleDown (size);
+}
+
+/**
+ * Auto-scale down float dimensions.
+ */
+public static float autoScaleDown (float size) {
+ if (deviceZoom == 100 || size == SWT.DEFAULT) return size;
+ float scaleFactor = getScalingFactor ();
+ return (size / scaleFactor);
+}
+
+/**
+ * Auto-scale down float dimensions if enabled for Drawable class.
+ */
+public static float autoScaleDown (Drawable drawable, float size) {
+ if (drawable != null && !drawable.isAutoScalable ()) return size;
+ return autoScaleDown (size);
+}
+
+/**
+ * Returns a new scaled down Point.
+ */
+public static Point autoScaleDown (Point point) {
+ if (deviceZoom == 100 || point == null) return point;
+ float scaleFactor = getScalingFactor ();
+ Point scaledPoint = new Point (0,0);
+ scaledPoint.x = Math.round (point.x / scaleFactor);
+ scaledPoint.y = Math.round (point.y / scaleFactor);
+ return scaledPoint;
+}
+
+/**
+ * Returns a new scaled down Point if enabled for Drawable class.
+ */
+public static Point autoScaleDown (Drawable drawable, Point point) {
+ if (drawable != null && !drawable.isAutoScalable ()) return point;
+ return autoScaleDown (point);
+}
+
+/**
+ * Returns a new scaled down Rectangle.
+ */
+public static Rectangle autoScaleDown (Rectangle rect) {
+ if (deviceZoom == 100 || rect == null) return rect;
+ Rectangle scaledRect = new Rectangle (0,0,0,0);
+ Point scaledTopLeft = DPIUtil.autoScaleDown (new Point (rect.x, rect.y));
+ Point scaledBottomRight = DPIUtil.autoScaleDown (new Point (rect.x + rect.width, rect.y + rect.height));
+
+ scaledRect.x = scaledTopLeft.x;
+ scaledRect.y = scaledTopLeft.y;
+ scaledRect.width = scaledBottomRight.x - scaledTopLeft.x;
+ scaledRect.height = scaledBottomRight.y - scaledTopLeft.y;
+ return scaledRect;
+}
+/**
+ * Returns a new scaled down Rectangle if enabled for Drawable class.
+ */
+public static Rectangle autoScaleDown (Drawable drawable, Rectangle rect) {
+ if (drawable != null && !drawable.isAutoScalable ()) return rect;
+ return autoScaleDown (rect);
+}
+
+/**
+ * Auto-scale image with ImageData
+ */
+public static ImageData autoScaleImageData (Device device, final ImageData imageData, int targetZoom, int currentZoom) {
+ if (imageData == null || targetZoom == currentZoom || (device != null && !device.isAutoScalable())) return imageData;
+ float scaleFactor = (float) targetZoom / (float) currentZoom;
+ return autoScaleImageData(device, imageData, scaleFactor);
+}
+
+private static ImageData autoScaleImageData (Device device, final ImageData imageData, float scaleFactor) {
+ // Guards are already implemented in callers: if (deviceZoom == 100 || imageData == null || scaleFactor == 1.0f) return imageData;
+ int width = imageData.width;
+ int height = imageData.height;
+ int scaledWidth = Math.round ((float) width * scaleFactor);
+ int scaledHeight = Math.round ((float) height * scaleFactor);
+ switch (autoScaleMethod) {
+ case SMOOTH:
+ Image original = new Image (device, (ImageDataProvider) zoom -> imageData);
+
+ /* Create a 24 bit image data with alpha channel */
+ final ImageData resultData = new ImageData (scaledWidth, scaledHeight, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000));
+ resultData.alphaData = new byte [scaledWidth * scaledHeight];
+
+ Image resultImage = new Image (device, (ImageDataProvider) zoom -> resultData);
+ GC gc = new GC (resultImage);
+ gc.setAntialias (SWT.ON);
+ gc.drawImage (original, 0, 0, DPIUtil.autoScaleDown (width), DPIUtil.autoScaleDown (height),
+ /* E.g. destWidth here is effectively DPIUtil.autoScaleDown (scaledWidth), but avoiding rounding errors.
+ * Nevertheless, we still have some rounding errors due to the point-based API GC#drawImage(..).
+ */
+ 0, 0, Math.round (DPIUtil.autoScaleDown ((float) width * scaleFactor)), Math.round (DPIUtil.autoScaleDown ((float) height * scaleFactor)));
+ gc.dispose ();
+ original.dispose ();
+ ImageData result = resultImage.getImageData (DPIUtil.getDeviceZoom ());
+ resultImage.dispose ();
+ return result;
+ case NEAREST:
+ default:
+ return imageData.scaledTo (scaledWidth, scaledHeight);
+ }
+}
+
+/**
+ * Returns a new rectangle as per the scaleFactor.
+ */
+public static Rectangle autoScaleBounds (Rectangle rect, int targetZoom, int currentZoom) {
+ if (deviceZoom == 100 || rect == null || targetZoom == currentZoom) return rect;
+ float scaleFactor = ((float)targetZoom) / (float)currentZoom;
+ Rectangle returnRect = new Rectangle (0,0,0,0);
+ returnRect.x = Math.round (rect.x * scaleFactor);
+ returnRect.y = Math.round (rect.y * scaleFactor);
+ returnRect.width = Math.round (rect.width * scaleFactor);
+ returnRect.height = Math.round (rect.height * scaleFactor);
+ return returnRect;
+}
+
+/**
+ * Auto-scale up ImageData
+ */
+public static ImageData autoScaleUp (Device device, final ImageData imageData) {
+ if (deviceZoom == 100 || imageData == null || (device != null && !device.isAutoScalable())) return imageData;
+ float scaleFactor = deviceZoom / 100f;
+ return autoScaleImageData(device, imageData, scaleFactor);
+}
+
+public static int[] autoScaleUp(int[] pointArray) {
+ if (deviceZoom == 100 || pointArray == null) return pointArray;
+ float scaleFactor = getScalingFactor ();
+ int [] returnArray = new int[pointArray.length];
+ for (int i = 0; i < pointArray.length; i++) {
+ returnArray [i] = Math.round (pointArray [i] * scaleFactor);
+ }
+ return returnArray;
+}
+
+public static int[] autoScaleUp(Drawable drawable, int[] pointArray) {
+ if (drawable != null && !drawable.isAutoScalable ()) return pointArray;
+ return autoScaleUp (pointArray);
+}
+
+/**
+ * Auto-scale up int dimensions.
+ */
+public static int autoScaleUp (int size) {
+ if (deviceZoom == 100 || size == SWT.DEFAULT) return size;
+ float scaleFactor = getScalingFactor ();
+ return Math.round (size * scaleFactor);
+}
+
+/**
+ * Auto-scale up int dimensions using Native DPI
+ */
+public static int autoScaleUpUsingNativeDPI (int size) {
+ if (nativeDeviceZoom == 100 || size == SWT.DEFAULT) return size;
+ float nativeScaleFactor = nativeDeviceZoom / 100f;
+ return Math.round (size * nativeScaleFactor);
+}
+
+/**
+ * Auto-scale up int dimensions if enabled for Drawable class.
+ */
+public static int autoScaleUp (Drawable drawable, int size) {
+ if (drawable != null && !drawable.isAutoScalable ()) return size;
+ return autoScaleUp (size);
+}
+
+public static float autoScaleUp(float size) {
+ if (deviceZoom == 100 || size == SWT.DEFAULT) return size;
+ float scaleFactor = getScalingFactor ();
+ return (size * scaleFactor);
+}
+
+public static float autoScaleUp(Drawable drawable, float size) {
+ if (drawable != null && !drawable.isAutoScalable ()) return size;
+ return autoScaleUp (size);
+}
+
+/**
+ * Returns a new scaled up Point.
+ */
+public static Point autoScaleUp (Point point) {
+ if (deviceZoom == 100 || point == null) return point;
+ float scaleFactor = getScalingFactor ();
+ Point scaledPoint = new Point (0,0);
+ scaledPoint.x = Math.round (point.x * scaleFactor);
+ scaledPoint.y = Math.round (point.y * scaleFactor);
+ return scaledPoint;
+}
+
+/**
+ * Returns a new scaled up Point if enabled for Drawable class.
+ */
+public static Point autoScaleUp (Drawable drawable, Point point) {
+ if (drawable != null && !drawable.isAutoScalable ()) return point;
+ return autoScaleUp (point);
+}
+
+/**
+ * Returns a new scaled up Rectangle.
+ */
+public static Rectangle autoScaleUp (Rectangle rect) {
+ if (deviceZoom == 100 || rect == null) return rect;
+ Rectangle scaledRect = new Rectangle (0,0,0,0);
+ Point scaledTopLeft = DPIUtil.autoScaleUp (new Point (rect.x, rect.y));
+ Point scaledBottomRight = DPIUtil.autoScaleUp (new Point (rect.x + rect.width, rect.y + rect.height));
+
+ scaledRect.x = scaledTopLeft.x;
+ scaledRect.y = scaledTopLeft.y;
+ scaledRect.width = scaledBottomRight.x - scaledTopLeft.x;
+ scaledRect.height = scaledBottomRight.y - scaledTopLeft.y;
+ return scaledRect;
+}
+
+/**
+ * Returns a new scaled up Rectangle if enabled for Drawable class.
+ */
+public static Rectangle autoScaleUp (Drawable drawable, Rectangle rect) {
+ if (drawable != null && !drawable.isAutoScalable ()) return rect;
+ return autoScaleUp (rect);
+}
+
+/**
+ * Returns Scaling factor from the display
+ * @return float scaling factor
+ */
+private static float getScalingFactor () {
+ if (useCairoAutoScale) {
+ return 1;
+ }
+ return deviceZoom / 100f;
+}
+
+/**
+ * Compute the zoom value based on the DPI value.
+ *
+ * @return zoom
+ */
+public static int mapDPIToZoom (int dpi) {
+ double zoom = (double) dpi * 100 / DPI_ZOOM_100;
+ int roundedZoom = (int) Math.round (zoom);
+ return roundedZoom;
+}
+/**
+ * Gets Image data at specified zoom level, if image is missing then
+ * fall-back to 100% image. If provider or fall-back image is not available,
+ * throw error.
+ */
+public static ImageData validateAndGetImageDataAtZoom (ImageDataProvider provider, int zoom, boolean[] found) {
+ if (provider == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ ImageData data = provider.getImageData (zoom);
+ found [0] = (data != null);
+ /* If image is null when (zoom != 100%), fall-back to image at 100% zoom */
+ if (zoom != 100 && !found [0]) data = provider.getImageData (100);
+ if (data == null) SWT.error (SWT.ERROR_INVALID_ARGUMENT, null, ": ImageDataProvider [" + provider + "] returns null ImageData at 100% zoom.");
+ return data;
+}
+
+/**
+ * Gets Image file path at specified zoom level, if image is missing then
+ * fall-back to 100% image. If provider or fall-back image is not available,
+ * throw error.
+ */
+public static String validateAndGetImagePathAtZoom (ImageFileNameProvider provider, int zoom, boolean[] found) {
+ if (provider == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ String filename = provider.getImagePath (zoom);
+ found [0] = (filename != null);
+ /* If image is null when (zoom != 100%), fall-back to image at 100% zoom */
+ if (zoom != 100 && !found [0]) filename = provider.getImagePath (100);
+ if (filename == null) SWT.error (SWT.ERROR_INVALID_ARGUMENT, null, ": ImageFileNameProvider [" + provider + "] returns null filename at 100% zoom.");
+ return filename;
+}
+
+public static int getDeviceZoom() {
+ return deviceZoom;
+}
+
+public static void setDeviceZoom (int nativeDeviceZoom) {
+ DPIUtil.nativeDeviceZoom = nativeDeviceZoom;
+ int deviceZoom = getZoomForAutoscaleProperty (nativeDeviceZoom);
+
+ DPIUtil.deviceZoom = deviceZoom;
+ System.setProperty("org.eclipse.swt.internal.deviceZoom", Integer.toString(deviceZoom));
+ if (deviceZoom != 100 && autoScaleMethodSetting == AutoScaleMethod.AUTO) {
+ if (deviceZoom / 100 * 100 == deviceZoom || !"gtk".equals(SWT.getPlatform())) {
+ autoScaleMethod = AutoScaleMethod.NEAREST;
+ } else {
+ autoScaleMethod = AutoScaleMethod.SMOOTH;
+ }
+ }
+}
+
+public static void setUseCairoAutoScale (boolean cairoAutoScale) {
+ useCairoAutoScale = cairoAutoScale;
+}
+
+public static boolean useCairoAutoScale() {
+ return useCairoAutoScale;
+}
+
+public static int getZoomForAutoscaleProperty (int nativeDeviceZoom) {
+ int zoom = 0;
+ if (autoScaleValue != null) {
+ if ("false".equalsIgnoreCase (autoScaleValue)) {
+ zoom = 100;
+ } else if ("quarter".equalsIgnoreCase (autoScaleValue)) {
+ zoom = (int) (Math.round (nativeDeviceZoom / 25f) * 25);
+ } else if ("exact".equalsIgnoreCase (autoScaleValue)) {
+ zoom = nativeDeviceZoom;
+ } else {
+ try {
+ int zoomValue = Integer.parseInt (autoScaleValue);
+ zoom = Math.max (Math.min (zoomValue, 1600), 25);
+ } catch (NumberFormatException e) {
+ // unsupported value, use default
+ }
+ }
+ }
+ if (zoom == 0) { // || "integer".equalsIgnoreCase (value) || "integer200".equalsIgnoreCase (value)
+ zoom = Math.max ((nativeDeviceZoom + 25) / 100 * 100, 100);
+ if (!"integer".equalsIgnoreCase(autoScaleValue)) {
+ // integer200, or default
+ zoom = Math.min (zoom, 200);
+ }
+ }
+ return zoom;
+}
+
+/**
+ * AutoScale ImageDataProvider.
+ */
+public static final class AutoScaleImageDataProvider implements ImageDataProvider {
+ Device device;
+ ImageData imageData;
+ int currentZoom;
+ public AutoScaleImageDataProvider(Device device, ImageData data, int zoom){
+ this.device = device;
+ this.imageData = data;
+ this.currentZoom = zoom;
+ }
+ @Override
+ public ImageData getImageData(int zoom) {
+ return DPIUtil.autoScaleImageData(device, imageData, zoom, currentZoom);
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/DefaultExceptionHandler.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/DefaultExceptionHandler.java
new file mode 100644
index 000000000..a30a8e84a
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/DefaultExceptionHandler.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Google Inc and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.internal;
+
+import java.util.function.*;
+
+public class DefaultExceptionHandler {
+
+public static final Consumername
is used to load the library. If this fails,
+ * name
is used in another attempt to load the library,
+ * this time ignoring the SWT version encoding scheme.
+ *
+ * @param name the name of the library to load
+ */
+public static void loadLibrary (String name) {
+ loadLibrary (name, true);
+}
+
+/**
+ * Loads the shared library that matches the version of the
+ * Java code which is currently running. SWT shared libraries
+ * follow an encoding scheme where the major, minor and revision
+ * numbers are embedded in the library name and this along with
+ * name
is used to load the library. If this fails,
+ * name
is used in another attempt to load the library,
+ * this time ignoring the SWT version encoding scheme.
+ *
+ * @param name the name of the library to load
+ * @param mapName true if the name should be mapped, false otherwise
+ */
+public static void loadLibrary (String name, boolean mapName) {
+ String prop = System.getProperty ("sun.arch.data.model"); //$NON-NLS-1$
+ if (prop == null) prop = System.getProperty ("com.ibm.vm.bitmode"); //$NON-NLS-1$
+ if (prop != null) {
+ if ("32".equals (prop) && IS_64) { //$NON-NLS-1$
+ throw new UnsatisfiedLinkError ("Cannot load 64-bit SWT libraries on 32-bit JVM"); //$NON-NLS-1$
+ }
+ if ("64".equals (prop) && !IS_64) { //$NON-NLS-1$
+ throw new UnsatisfiedLinkError ("Cannot load 32-bit SWT libraries on 64-bit JVM"); //$NON-NLS-1$
+ }
+ }
+
+ /* Compute the library name and mapped name */
+ String libName1, libName2, mappedName1, mappedName2;
+ if (mapName) {
+ String version = getVersionString ();
+ libName1 = name + "-" + Platform.PLATFORM + "-" + version; //$NON-NLS-1$ //$NON-NLS-2$
+ libName2 = name + "-" + Platform.PLATFORM; //$NON-NLS-1$
+ mappedName1 = mapLibraryName (libName1);
+ mappedName2 = mapLibraryName (libName2);
+ } else {
+ libName1 = libName2 = mappedName1 = mappedName2 = name;
+ }
+
+ StringBuilder message = new StringBuilder();
+
+ /* Try loading library from swt library path */
+ String path = System.getProperty (SWT_LIB_PATH); //$NON-NLS-1$
+ if (path != null) {
+ path = new File (path).getAbsolutePath ();
+ if (load (path + SEPARATOR + mappedName1, message)) return;
+ if (mapName && load (path + SEPARATOR + mappedName2, message)) return;
+ }
+
+ /* Try loading library from java library path */
+ if (load (libName1, message)) return;
+ if (mapName && load (libName2, message)) return;
+
+ /* Try loading library from the tmp directory if swt library path is not specified.
+ * Create the tmp folder if it doesn't exist. Tmp folder looks like this:
+ * ~/.swt/lib/buf
. A value
+ * equal to buf.length indicates no bytes available. A value of
+ * 0 indicates the buffer is full.
+ */
+ protected int pos;
+
+
+ public LEDataInputStream(InputStream input) {
+ this(input, 512);
+ }
+
+ public LEDataInputStream(InputStream input, int bufferSize) {
+ this.in = input;
+ if (bufferSize > 0) {
+ buf = new byte[bufferSize];
+ pos = bufferSize;
+ }
+ else throw new IllegalArgumentException();
+ }
+
+ @Override
+ public void close() throws IOException {
+ buf = null;
+ if (in != null) {
+ in.close();
+ in = null;
+ }
+ }
+
+ /**
+ * Answer how many bytes were read.
+ */
+ public int getPosition() {
+ return position;
+ }
+
+ /**
+ * Answers how many bytes are available for reading without blocking
+ */
+ @Override
+ public int available() throws IOException {
+ if (buf == null) throw new IOException();
+ return (buf.length - pos) + in.available();
+ }
+
+ /**
+ * Answer the next byte of the input stream.
+ */
+ @Override
+ public int read() throws IOException {
+ if (buf == null) throw new IOException();
+ if (pos < buf.length) {
+ position++;
+ return (buf[pos++] & 0xFF);
+ }
+ int c = in.read();
+ if (c != -1) position++;
+ return c;
+ }
+
+ /**
+ * Don't imitate the JDK behaviour of reading a random number
+ * of bytes when you can actually read them all.
+ */
+ @Override
+ public int read(byte b[], int off, int len) throws IOException {
+ int read = 0, count;
+ while (read != len && (count = readData(b, off, len - read)) != -1) {
+ off += count;
+ read += count;
+ }
+ position += read;
+ if (read == 0 && read != len) return -1;
+ return read;
+ }
+
+ /**
+ * Reads at most length
bytes from this LEDataInputStream and
+ * stores them in byte array buffer
starting at offset
.
+ * count
.
+ * buffer
to store the read bytes.
+ * @param length the maximum number of bytes to store in buffer
.
+ *
+ * @return int the number of bytes actually read or -1 if end of stream.
+ *
+ * @exception java.io.IOException if an IOException occurs.
+ */
+ private int readData(byte[] buffer, int offset, int length) throws IOException {
+ if (buf == null) throw new IOException();
+ if (offset < 0 || offset > buffer.length ||
+ length < 0 || (length > buffer.length - offset)) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ int cacheCopied = 0;
+ int newOffset = offset;
+
+ // Are there pushback bytes available?
+ int available = buf.length - pos;
+ if (available > 0) {
+ cacheCopied = (available >= length) ? length : available;
+ System.arraycopy(buf, pos, buffer, newOffset, cacheCopied);
+ newOffset += cacheCopied;
+ pos += cacheCopied;
+ }
+
+ // Have we copied enough?
+ if (cacheCopied == length) return length;
+
+ int inCopied = in.read(buffer, newOffset, length - cacheCopied);
+
+ if (inCopied > 0) return inCopied + cacheCopied;
+ if (cacheCopied == 0) return inCopied;
+ return cacheCopied;
+ }
+
+ /**
+ * Answer an integer comprised of the next
+ * four bytes of the input stream.
+ */
+ public int readInt() throws IOException {
+ byte[] buf = new byte[4];
+ read(buf);
+ return ((buf[3] & 0xFF) << 24) |
+ ((buf[2] & 0xFF) << 16) |
+ ((buf[1] & 0xFF) << 8) |
+ (buf[0] & 0xFF);
+ }
+
+ /**
+ * Answer a short comprised of the next
+ * two bytes of the input stream.
+ */
+ public short readShort() throws IOException {
+ byte[] buf = new byte[2];
+ read(buf);
+ return (short)(((buf[1] & 0xFF) << 8) | (buf[0] & 0xFF));
+ }
+
+ /**
+ * Push back the entire content of the given buffer b
.
+ * b
,
+ * an IOException will be thrown and no byte will be pushed back.
+ *
+Package Specification
+This package contains the classes used by SWT to load and save images
+in the various formats we support, including GIF, JPEG, PNG, BMP, and ICO.
+
+Package Specification
+This package contains the internal classes which implement the Microsoft
+Win32 platform interface to the Object Linking and Embedding mechanism
+that the win32 variant of SWT is capable of using.
+
+Package Specification
+This package provides the Callback
class which is used to
+map the operating system's callback mechanism to Java message sends, and
+the Converter
class which provides translation between Unicode
+and platform specific character sets.
+
+Package Specification
+This package contains the classes which represent the Microsoft
+Win32 platform interface that the win32 variant of SWT is built
+from.
+FillLayout
is the simplest layout class. It lays out
+ * controls in a single row or column, forcing them to be the same size.
+ * FillLayout
does not wrap,
+ * but you can specify margins and spacing. You might use it to
+ * lay out buttons in a task bar or tool bar, or to stack checkboxes
+ * in a Group
. FillLayout
can also be used
+ * when a Composite
only has one child. For example,
+ * if a Shell
has a single Group
child,
+ * FillLayout
will cause the Group
to
+ * completely fill the Shell
(if margins are 0).
+ * FillLayout
is created and
+ * its type field is set, and then the layout is set into the
+ * Composite
. Note that in a FillLayout
,
+ * children are always the same size, and they fill all available space.
+ *
+ * FillLayout fillLayout = new FillLayout();
+ * fillLayout.type = SWT.VERTICAL;
+ * shell.setLayout(fillLayout);
+ *
+ *
+ * @see SWT Example: LayoutExample
+ * @see Sample code and further information
+ */
+public final class FillLayout extends Layout {
+ /**
+ * type specifies how controls will be positioned
+ * within the layout.
+ *
+ * The default value is HORIZONTAL.
+ *
+ * Possible values are:
+ *
+ */
+ public int type = SWT.HORIZONTAL;
+
+ /**
+ * marginWidth specifies the number of points of horizontal margin
+ * that will be placed along the left and right edges of the layout.
+ *
+ * The default value is 0.
+ *
+ * @since 3.0
+ */
+ public int marginWidth = 0;
+
+ /**
+ * marginHeight specifies the number of points of vertical margin
+ * that will be placed along the top and bottom edges of the layout.
+ *
+ * The default value is 0.
+ *
+ * @since 3.0
+ */
+ public int marginHeight = 0;
+
+ /**
+ * spacing specifies the number of points between the edge of one cell
+ * and the edge of its neighbouring cell.
+ *
+ * The default value is 0.
+ *
+ * @since 3.0
+ */
+ public int spacing = 0;
+
+/**
+ * Constructs a new instance of this class.
+ */
+public FillLayout () {
+}
+
+/**
+ * Constructs a new instance of this class given the type.
+ *
+ * @param type the type of fill layout
+ *
+ * @since 2.0
+ */
+public FillLayout (int type) {
+ this.type = type;
+}
+
+@Override
+protected Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache) {
+ Control [] children = composite.getChildren ();
+ int count = children.length;
+ int maxWidth = 0, maxHeight = 0;
+ for (int i=0; iFormAttachments
are set into the top, bottom, left,
+ * and right fields of the FormData
for a control.
+ * For example:
+ *
+ * FormData data = new FormData();
+ * data.top = new FormAttachment(0,5);
+ * data.bottom = new FormAttachment(100,-5);
+ * data.left = new FormAttachment(0,5);
+ * data.right = new FormAttachment(100,-5);
+ * button.setLayoutData(data);
+ *
+ * FormAttachment
defines where to attach the side of
+ * a control by using the equation, y = ax + b. The "a" term represents
+ * a fraction of the parent composite's width (from the left) or height
+ * (from the top). It can be defined using a numerator and denominator,
+ * or just a percentage value. If a percentage is used, the denominator
+ * is set to 100. The "b" term in the equation represents an offset, in
+ * points, from the attachment position. For example:
+ * FormAttachment attach = new FormAttachment (20, -5);
+ *
+ * FormAttachment
+ * object belongs will lie at 20% of the parent composite, minus 5 points.
+ *
+ * FormAttachment attach = new FormAttachment (button, 10);
+ *
+ * specifies that the side to which the FormAttachment
+ * object belongs will lie in the same position as the adjacent side of
+ * the button
control, plus 10 points. The control side can
+ * also be attached to the opposite side of the specified control.
+ * For example:
+ *
+ * FormData data = new FormData ();
+ * data.left = new FormAttachment (button, 0, SWT.LEFT);
+ *
+ * specifies that the left side of the control will lie in the same position
+ * as the left side of the button
control. The control can also
+ * be attached in a position that will center the control on the specified
+ * control. For example:
+ *
+ * data.left = new FormAttachment (button, 0, SWT.CENTER);
+ *
+ * specifies that the left side of the control will be positioned so that it is
+ * centered between the left and right sides of the button
control.
+ * If the alignment is not specified, the default is to attach to the adjacent side.
+ *
+ * @see FormLayout
+ * @see FormData
+ * @see Sample code and further information
+ *
+ * @since 2.0
+ */
+public final class FormAttachment {
+ /**
+ * numerator specifies the numerator of the "a" term in the
+ * equation, y = ax + b, which defines the attachment.
+ */
+ public int numerator;
+
+ /**
+ * denominator specifies the denominator of the "a" term in the
+ * equation, y = ax + b, which defines the attachment.
+ *
+ * The default value is 100.
+ */
+ public int denominator = 100;
+
+ /**
+ * offset specifies the offset, in points, of the control side
+ * from the attachment position.
+ * If the offset is positive, then the control side is offset
+ * to the right of or below the attachment position. If it is
+ * negative, then the control side is offset to the left of or
+ * above the attachment position.
+ *
+ * This is equivalent to the "b" term in the equation y = ax + b.
+ * The default value is 0.
+ */
+ public int offset;
+
+ /**
+ * control specifies the control to which the control side is
+ * attached.
+ */
+ public Control control;
+
+ /**
+ * alignment specifies the alignment of the control side that is
+ * attached to a control.
+ *
Possible values are:
+ *
+ */
+ public int alignment;
+
+/**
+ * Constructs a new instance of this class.
+ * Since no numerator, denominator or offset is specified,
+ * the attachment is treated as a percentage of the form.
+ * The numerator is zero, the denominator is 100 and the
+ * offset is zero.
+ *
+ * @since 3.2
+ */
+public FormAttachment () {
+}
+
+/**
+ * Constructs a new instance of this class given a numerator
+ * Since no denominator or offset is specified, the default
+ * is to treat the numerator as a percentage of the form, with a
+ * denominator of 100. The offset is zero.
+ *
+ * @param numerator the percentage of the position
+ *
+ * @since 3.0
+ */
+public FormAttachment (int numerator) {
+ this (numerator, 100, 0);
+}
+
+/**
+ * Constructs a new instance of this class given a numerator
+ * and an offset. Since no denominator is specified, the default
+ * is to treat the numerator as a percentage of the form, with a
+ * denominator of 100.
+ *
+ * @param numerator the percentage of the position
+ * @param offset the offset of the side from the position
+ */
+public FormAttachment (int numerator, int offset) {
+ this (numerator, 100, offset);
+}
+
+/**
+ * Constructs a new instance of this class given a numerator
+ * and denominator and an offset. The position of the side is
+ * given by the fraction of the form defined by the numerator
+ * and denominator.
+ *
+ * @param numerator the numerator of the position
+ * @param denominator the denominator of the position
+ * @param offset the offset of the side from the position
+ */
+public FormAttachment (int numerator, int denominator, int offset) {
+ if (denominator == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
+ this.numerator = numerator;
+ this.denominator = denominator;
+ this.offset = offset;
+}
+
+/**
+ * Constructs a new instance of this class given a control.
+ * Since no alignment is specified, the default alignment is
+ * to attach the side to the adjacent side of the specified
+ * control. Since no offset is specified, an offset of 0 is
+ * used.
+ *
+ * @param control the control the side is attached to
+ */
+public FormAttachment (Control control) {
+ this (control, 0, SWT.DEFAULT);
+}
+
+/**
+ * Constructs a new instance of this class given a control
+ * and an offset. Since no alignment is specified, the default
+ * alignment is to attach the side to the adjacent side of the
+ * specified control.
+ *
+ * @param control the control the side is attached to
+ * @param offset the offset of the side from the control
+ */
+public FormAttachment (Control control, int offset) {
+ this (control, offset, SWT.DEFAULT);
+}
+
+/**
+ * Constructs a new instance of this class given a control,
+ * an offset and an alignment. The possible alignment values are:
+ *
+ *
+ *
+ * @param control the control the side is attached to
+ * @param offset the offset of the side from the control
+ * @param alignment the alignment of the side to the control it is attached to,
+ * one of TOP, BOTTOM, LEFT, RIGHT, CENTER, or DEFAULT
+ */
+public FormAttachment (Control control, int offset, int alignment) {
+ this.control = control;
+ this.offset = offset;
+ this.alignment = alignment;
+}
+
+FormAttachment divide (int value) {
+ return new FormAttachment (numerator, denominator * value, offset / value);
+}
+
+int gcd (int m, int n) {
+ int temp;
+ m = Math.abs (m);
+ n = Math.abs (n);
+ if (m < n) {
+ temp = m;
+ m = n;
+ n = temp;
+ }
+ while (n != 0){
+ temp = m;
+ m = n;
+ n = temp % n;
+ }
+ return m;
+}
+
+FormAttachment minus (FormAttachment attachment) {
+ FormAttachment solution = new FormAttachment ();
+ solution.numerator = numerator * attachment.denominator - denominator * attachment.numerator;
+ solution.denominator = denominator * attachment.denominator;
+ int gcd = gcd (solution.denominator, solution.numerator);
+ solution.numerator = solution.numerator / gcd;
+ solution.denominator = solution.denominator / gcd;
+ solution.offset = offset - attachment.offset;
+ return solution;
+}
+
+FormAttachment minus (int value) {
+ return new FormAttachment (numerator, denominator, offset - value);
+}
+
+FormAttachment plus (FormAttachment attachment) {
+ FormAttachment solution = new FormAttachment ();
+ solution.numerator = numerator * attachment.denominator + denominator * attachment.numerator;
+ solution.denominator = denominator * attachment.denominator;
+ int gcd = gcd (solution.denominator, solution.numerator);
+ solution.numerator = solution.numerator / gcd;
+ solution.denominator = solution.denominator / gcd;
+ solution.offset = offset + attachment.offset;
+ return solution;
+}
+
+FormAttachment plus (int value) {
+ return new FormAttachment (numerator, denominator, offset + value);
+}
+
+int solveX (int value) {
+ if (denominator == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
+ return ((numerator * value) / denominator) + offset;
+}
+
+int solveY (int value) {
+ if (numerator == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
+ return (value - offset) * denominator / numerator;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the FormAttachment
+ */
+@Override
+public String toString () {
+ String string = control != null ? control.toString () : numerator + "/" + denominator;
+ return "{y = (" + string + (offset >= 0 ? ")x + " + offset: ")x - " + (-offset))+"}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/layout/FormData.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/layout/FormData.java
new file mode 100644
index 000000000..56100f88c
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/layout/FormData.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.layout;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Instances of this class are used to define the attachments
+ * of a control in a FormLayout
.
+ * FormData
object into a control, you use the
+ * setLayoutData ()
method. To define attachments for the
+ * FormData
, set the fields directly, like this:
+ *
+ * FormData data = new FormData();
+ * data.left = new FormAttachment(0,5);
+ * data.right = new FormAttachment(100,-5);
+ * button.setLayoutData(formData);
+ *
+ * FormData
contains the FormAttachments
for
+ * each edge of the control that the FormLayout
uses to
+ * determine the size and position of the control. FormData
+ * objects also allow you to set the width and height of controls within
+ * a FormLayout
.
+ * FormAttachments
+ * to optionally configure the left, top, right and bottom edges of
+ * each child.
+ * FormLayout
and then sets
+ * it into a Shell
:
+ *
+ * Display display = new Display ();
+ * Shell shell = new Shell(display);
+ * FormLayout layout = new FormLayout();
+ * layout.marginWidth = 3;
+ * layout.marginHeight = 3;
+ * shell.setLayout(layout);
+ *
+ * FormLayout
, create a FormData
with
+ * FormAttachment
for each child of Composite
.
+ * The following example code attaches button1
to the top
+ * and left edge of the composite and button2
to the right
+ * edge of button1
and the top and right edges of the
+ * composite:
+ *
+ * FormData data1 = new FormData();
+ * data1.left = new FormAttachment(0, 0);
+ * data1.top = new FormAttachment(0, 0);
+ * button1.setLayoutData(data1);
+ * FormData data2 = new FormData();
+ * data2.left = new FormAttachment(button1);
+ * data2.top = new FormAttachment(0, 0);
+ * data2.right = new FormAttachment(100, 0);
+ * button2.setLayoutData(data2);
+ *
+ * Composite
by
+ * creating instances of FormAttachment
and setting them into
+ * the top, bottom, left, and right fields of the child's FormData
.
+ * button1
and button2
+ * but relies on default attachments:
+ *
+ * FormData data2 = new FormData();
+ * data2.left = new FormAttachment(button1);
+ * data2.right = new FormAttachment(100, 0);
+ * button2.setLayoutData(data2);
+ *
+ * button1
to the left edge of button2
+ * and then attach the left edge of button2
to the right edge of
+ * button1
. This will over constrain the layout, causing undefined
+ * behavior. The algorithm will terminate, but the results are undefined.
+ * GridLayout
. To set a GridData
object into a
+ * control, you use the Control.setLayoutData(Object)
method.
+ * GridData
object with certain
+ * fields set. The first is to set the fields directly, like this:
+ * GridData gridData = new GridData();
+ * gridData.horizontalAlignment = GridData.FILL;
+ * gridData.grabExcessHorizontalSpace = true;
+ * button1.setLayoutData(gridData);
+ *
+ * gridData = new GridData();
+ * gridData.horizontalAlignment = GridData.FILL;
+ * gridData.verticalAlignment = GridData.FILL;
+ * gridData.grabExcessHorizontalSpace = true;
+ * gridData.grabExcessVerticalSpace = true;
+ * gridData.horizontalSpan = 2;
+ * button2.setLayoutData(gridData);
+ *
+ * The second is to take advantage of GridData
convenience constructors, for example:
+ *
+ * button1.setLayoutData(new GridData (SWT.FILL, SWT.CENTER, true, false));
+ * button2.setLayoutData(new GridData (SWT.FILL, SWT.FILL, true, true, 2, 1));
+ *
+ * GridData
objects. Every control in a
+ * Composite
that is managed by a GridLayout
+ * must have a unique GridData
object. If the layout data
+ * for a control in a GridLayout
is null at layout time,
+ * a unique GridData
object is created for it.
+ *
+ *
+ */
+ public int verticalAlignment = CENTER;
+
+ /**
+ * horizontalAlignment specifies how controls will be positioned
+ * horizontally within a cell.
+ *
+ * The default value is BEGINNING.
+ *
+ * Possible values are:
+ *
+ */
+ public int horizontalAlignment = BEGINNING;
+
+ /**
+ * widthHint specifies the preferred width in points. This value
+ * is the wHint passed into Control.computeSize(int, int, boolean)
+ * to determine the preferred size of the control.
+ *
+ * The default value is SWT.DEFAULT.
+ *
+ * @see Control#computeSize(int, int, boolean)
+ */
+ public int widthHint = SWT.DEFAULT;
+
+ /**
+ * heightHint specifies the preferred height in points. This value
+ * is the hHint passed into Control.computeSize(int, int, boolean)
+ * to determine the preferred size of the control.
+ *
+ * The default value is SWT.DEFAULT.
+ *
+ * @see Control#computeSize(int, int, boolean)
+ */
+ public int heightHint = SWT.DEFAULT;
+
+ /**
+ * horizontalIndent specifies the number of points of indentation
+ * that will be placed along the left side of the cell.
+ *
+ * The default value is 0.
+ */
+ public int horizontalIndent = 0;
+
+ /**
+ * verticalIndent specifies the number of points of indentation
+ * that will be placed along the top side of the cell.
+ *
+ * The default value is 0.
+ *
+ * @since 3.1
+ */
+ public int verticalIndent = 0;
+
+ /**
+ * horizontalSpan specifies the number of column cells that the control
+ * will take up.
+ *
+ * The default value is 1.
+ */
+ public int horizontalSpan = 1;
+
+ /**
+ * verticalSpan specifies the number of row cells that the control
+ * will take up.
+ *
+ * The default value is 1.
+ */
+ public int verticalSpan = 1;
+
+ /**
+ * true
, the following rules
+ * apply to the width of the cell:
+ *
+ *
+ * true
, the following rules
+ * apply to the height of the cell:
+ *
+ *
+ * true
,
+ * the size and position of the control will not be managed by the
+ * layout. If this value is false
, the size and
+ * position of the control will be computed and assigned.
+ *
+ * The default value is false
.
+ *
+ * @since 3.1
+ */
+ public boolean exclude = false;
+
+ /**
+ * Value for horizontalAlignment or verticalAlignment.
+ * Position the control at the top or left of the cell.
+ * Not recommended. Use SWT.BEGINNING, SWT.TOP or SWT.LEFT instead.
+ */
+ public static final int BEGINNING = SWT.BEGINNING;
+
+ /**
+ * Value for horizontalAlignment or verticalAlignment.
+ * Position the control in the vertical or horizontal center of the cell
+ * Not recommended. Use SWT.CENTER instead.
+ */
+ public static final int CENTER = 2;
+
+ /**
+ * Value for horizontalAlignment or verticalAlignment.
+ * Position the control at the bottom or right of the cell
+ * Not recommended. Use SWT.END, SWT.BOTTOM or SWT.RIGHT instead.
+ */
+ public static final int END = 3;
+
+ /**
+ * Value for horizontalAlignment or verticalAlignment.
+ * Resize the control to fill the cell horizontally or vertically.
+ * Not recommended. Use SWT.FILL instead.
+ */
+ public static final int FILL = SWT.FILL;
+
+ /**
+ * Style bit for new GridData(int)
.
+ * Position the control at the top of the cell.
+ * Not recommended. Use
+ * new GridData(int, SWT.BEGINNING, boolean, boolean)
+ * instead.
+ */
+ public static final int VERTICAL_ALIGN_BEGINNING = 1 << 1;
+
+ /**
+ * Style bit for new GridData(int)
to position the
+ * control in the vertical center of the cell.
+ * Not recommended. Use
+ * new GridData(int, SWT.CENTER, boolean, boolean)
+ * instead.
+ */
+ public static final int VERTICAL_ALIGN_CENTER = 1 << 2;
+
+ /**
+ * Style bit for new GridData(int)
to position the
+ * control at the bottom of the cell.
+ * Not recommended. Use
+ * new GridData(int, SWT.END, boolean, boolean)
+ * instead.
+ */
+ public static final int VERTICAL_ALIGN_END = 1 << 3;
+
+ /**
+ * Style bit for new GridData(int)
to resize the
+ * control to fill the cell vertically.
+ * Not recommended. Use
+ * new GridData(int, SWT.FILL, boolean, boolean)
+ * instead
+ */
+ public static final int VERTICAL_ALIGN_FILL = 1 << 4;
+
+ /**
+ * Style bit for new GridData(int)
to position the
+ * control at the left of the cell.
+ * Not recommended. Use
+ * new GridData(SWT.BEGINNING, int, boolean, boolean)
+ * instead.
+ */
+ public static final int HORIZONTAL_ALIGN_BEGINNING = 1 << 5;
+
+ /**
+ * Style bit for new GridData(int)
to position the
+ * control in the horizontal center of the cell.
+ * Not recommended. Use
+ * new GridData(SWT.CENTER, int, boolean, boolean)
+ * instead.
+ */
+ public static final int HORIZONTAL_ALIGN_CENTER = 1 << 6;
+
+ /**
+ * Style bit for new GridData(int)
to position the
+ * control at the right of the cell.
+ * Not recommended. Use
+ * new GridData(SWT.END, int, boolean, boolean)
+ * instead.
+ */
+ public static final int HORIZONTAL_ALIGN_END = 1 << 7;
+
+ /**
+ * Style bit for new GridData(int)
to resize the
+ * control to fill the cell horizontally.
+ * Not recommended. Use
+ * new GridData(SWT.FILL, int, boolean, boolean)
+ * instead.
+ */
+ public static final int HORIZONTAL_ALIGN_FILL = 1 << 8;
+
+ /**
+ * Style bit for new GridData(int)
to resize the
+ * control to fit the remaining horizontal space.
+ * Not recommended. Use
+ * new GridData(int, int, true, boolean)
+ * instead.
+ */
+ public static final int GRAB_HORIZONTAL = 1 << 9;
+
+ /**
+ * Style bit for new GridData(int)
to resize the
+ * control to fit the remaining vertical space.
+ * Not recommended. Use
+ * new GridData(int, int, boolean, true)
+ * instead.
+ */
+ public static final int GRAB_VERTICAL = 1 << 10;
+
+ /**
+ * Style bit for new GridData(int)
to resize the
+ * control to fill the cell vertically and to fit the remaining
+ * vertical space.
+ * FILL_VERTICAL = VERTICAL_ALIGN_FILL | GRAB_VERTICAL
+ * Not recommended. Use
+ * new GridData(int, SWT.FILL, boolean, true)
+ * instead.
+ */
+ public static final int FILL_VERTICAL = VERTICAL_ALIGN_FILL | GRAB_VERTICAL;
+
+ /**
+ * Style bit for new GridData(int)
to resize the
+ * control to fill the cell horizontally and to fit the remaining
+ * horizontal space.
+ * FILL_HORIZONTAL = HORIZONTAL_ALIGN_FILL | GRAB_HORIZONTAL
+ * Not recommended. Use
+ * new GridData(SWT.FILL, int, true, boolean)
+ * instead.
+ */
+ public static final int FILL_HORIZONTAL = HORIZONTAL_ALIGN_FILL | GRAB_HORIZONTAL;
+
+ /**
+ * Style bit for new GridData(int)
to resize the
+ * control to fill the cell horizontally and vertically and
+ * to fit the remaining horizontal and vertical space.
+ * FILL_BOTH = FILL_VERTICAL | FILL_HORIZONTAL
+ * Not recommended. Use
+ * new GridData(SWT.FILL, SWT.FILL, true, true)
+ * instead.
+ */
+ public static final int FILL_BOTH = FILL_VERTICAL | FILL_HORIZONTAL;
+
+ int cacheWidth = -1, cacheHeight = -1;
+ int defaultWhint, defaultHhint, defaultWidth = -1, defaultHeight = -1;
+ int currentWhint, currentHhint, currentWidth = -1, currentHeight = -1;
+
+/**
+ * Constructs a new instance of GridData using
+ * default values.
+ */
+public GridData () {
+ super ();
+}
+
+/**
+ * Constructs a new instance based on the GridData style.
+ * This constructor is not recommended.
+ *
+ * @param style the GridData style
+ */
+public GridData (int style) {
+ super ();
+ if ((style & VERTICAL_ALIGN_BEGINNING) != 0) verticalAlignment = BEGINNING;
+ if ((style & VERTICAL_ALIGN_CENTER) != 0) verticalAlignment = CENTER;
+ if ((style & VERTICAL_ALIGN_FILL) != 0) verticalAlignment = FILL;
+ if ((style & VERTICAL_ALIGN_END) != 0) verticalAlignment = END;
+ if ((style & HORIZONTAL_ALIGN_BEGINNING) != 0) horizontalAlignment = BEGINNING;
+ if ((style & HORIZONTAL_ALIGN_CENTER) != 0) horizontalAlignment = CENTER;
+ if ((style & HORIZONTAL_ALIGN_FILL) != 0) horizontalAlignment = FILL;
+ if ((style & HORIZONTAL_ALIGN_END) != 0) horizontalAlignment = END;
+ grabExcessHorizontalSpace = (style & GRAB_HORIZONTAL) != 0;
+ grabExcessVerticalSpace = (style & GRAB_VERTICAL) != 0;
+}
+
+/**
+ * Constructs a new instance of GridData according to the parameters.
+ *
+ * @param horizontalAlignment how control will be positioned horizontally within a cell,
+ * one of: SWT.BEGINNING (or SWT.LEFT), SWT.CENTER, SWT.END (or SWT.RIGHT), or SWT.FILL
+ * @param verticalAlignment how control will be positioned vertically within a cell,
+ * one of: SWT.BEGINNING (or SWT.TOP), SWT.CENTER, SWT.END (or SWT.BOTTOM), or SWT.FILL
+ * @param grabExcessHorizontalSpace whether cell will be made wide enough to fit the remaining horizontal space
+ * @param grabExcessVerticalSpace whether cell will be made high enough to fit the remaining vertical space
+ *
+ * @since 3.0
+ */
+public GridData (int horizontalAlignment, int verticalAlignment, boolean grabExcessHorizontalSpace, boolean grabExcessVerticalSpace) {
+ this (horizontalAlignment, verticalAlignment, grabExcessHorizontalSpace, grabExcessVerticalSpace, 1, 1);
+}
+
+/**
+ * Constructs a new instance of GridData according to the parameters.
+ *
+ * @param horizontalAlignment how control will be positioned horizontally within a cell,
+ * one of: SWT.BEGINNING (or SWT.LEFT), SWT.CENTER, SWT.END (or SWT.RIGHT), or SWT.FILL
+ * @param verticalAlignment how control will be positioned vertically within a cell,
+ * one of: SWT.BEGINNING (or SWT.TOP), SWT.CENTER, SWT.END (or SWT.BOTTOM), or SWT.FILL
+ * @param grabExcessHorizontalSpace whether cell will be made wide enough to fit the remaining horizontal space
+ * @param grabExcessVerticalSpace whether cell will be made high enough to fit the remaining vertical space
+ * @param horizontalSpan the number of column cells that the control will take up
+ * @param verticalSpan the number of row cells that the control will take up
+ *
+ * @since 3.0
+ */
+public GridData (int horizontalAlignment, int verticalAlignment, boolean grabExcessHorizontalSpace, boolean grabExcessVerticalSpace, int horizontalSpan, int verticalSpan) {
+ super ();
+ this.horizontalAlignment = horizontalAlignment;
+ this.verticalAlignment = verticalAlignment;
+ this.grabExcessHorizontalSpace = grabExcessHorizontalSpace;
+ this.grabExcessVerticalSpace = grabExcessVerticalSpace;
+ this.horizontalSpan = horizontalSpan;
+ this.verticalSpan = verticalSpan;
+}
+
+/**
+ * Constructs a new instance of GridData according to the parameters.
+ * A value of SWT.DEFAULT indicates that no minimum width or
+ * no minimum height is specified.
+ *
+ * @param width a minimum width for the column
+ * @param height a minimum height for the row
+ *
+ * @since 3.0
+ */
+public GridData (int width, int height) {
+ super ();
+ this.widthHint = width;
+ this.heightHint = height;
+}
+
+void computeSize (Control control, int wHint, int hHint, boolean flushCache) {
+ if (cacheWidth != -1 && cacheHeight != -1) return;
+ if (wHint == this.widthHint && hHint == this.heightHint) {
+ if (defaultWidth == -1 || defaultHeight == -1 || wHint != defaultWhint || hHint != defaultHhint) {
+ Point size = control.computeSize (wHint, hHint, flushCache);
+ defaultWhint = wHint;
+ defaultHhint = hHint;
+ defaultWidth = size.x;
+ defaultHeight = size.y;
+ }
+ cacheWidth = defaultWidth;
+ cacheHeight = defaultHeight;
+ return;
+ }
+ if (currentWidth == -1 || currentHeight == -1 || wHint != currentWhint || hHint != currentHhint) {
+ Point size = control.computeSize (wHint, hHint, flushCache);
+ currentWhint = wHint;
+ currentHhint = hHint;
+ currentWidth = size.x;
+ currentHeight = size.y;
+ }
+ cacheWidth = currentWidth;
+ cacheHeight = currentHeight;
+}
+
+void flushCache () {
+ cacheWidth = cacheHeight = -1;
+ defaultWidth = defaultHeight = -1;
+ currentWidth = currentHeight = -1;
+}
+
+String getName () {
+ String string = getClass ().getName ();
+ int index = string.lastIndexOf ('.');
+ if (index == -1) return string;
+ return string.substring (index + 1, string.length ());
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the GridData object
+ */
+@Override
+public String toString () {
+ String hAlign = "";
+ switch (horizontalAlignment) {
+ case SWT.FILL: hAlign = "SWT.FILL"; break;
+ case SWT.BEGINNING: hAlign = "SWT.BEGINNING"; break;
+ case SWT.LEFT: hAlign = "SWT.LEFT"; break;
+ case SWT.END: hAlign = "SWT.END"; break;
+ case END: hAlign = "GridData.END"; break;
+ case SWT.RIGHT: hAlign = "SWT.RIGHT"; break;
+ case SWT.CENTER: hAlign = "SWT.CENTER"; break;
+ case CENTER: hAlign = "GridData.CENTER"; break;
+ default: hAlign = "Undefined "+horizontalAlignment; break;
+ }
+ String vAlign = "";
+ switch (verticalAlignment) {
+ case SWT.FILL: vAlign = "SWT.FILL"; break;
+ case SWT.BEGINNING: vAlign = "SWT.BEGINNING"; break;
+ case SWT.TOP: vAlign = "SWT.TOP"; break;
+ case SWT.END: vAlign = "SWT.END"; break;
+ case END: vAlign = "GridData.END"; break;
+ case SWT.BOTTOM: vAlign = "SWT.BOTTOM"; break;
+ case SWT.CENTER: vAlign = "SWT.CENTER"; break;
+ case CENTER: vAlign = "GridData.CENTER"; break;
+ default: vAlign = "Undefined "+verticalAlignment; break;
+ }
+ String string = getName()+" {";
+ string += "horizontalAlignment="+hAlign+" ";
+ if (horizontalIndent != 0) string += "horizontalIndent="+horizontalIndent+" ";
+ if (horizontalSpan != 1) string += "horizontalSpan="+horizontalSpan+" ";
+ if (grabExcessHorizontalSpace) string += "grabExcessHorizontalSpace="+grabExcessHorizontalSpace+" ";
+ if (widthHint != SWT.DEFAULT) string += "widthHint="+widthHint+" ";
+ if (minimumWidth != 0) string += "minimumWidth="+minimumWidth+" ";
+ string += "verticalAlignment="+vAlign+" ";
+ if (verticalIndent != 0) string += "verticalIndent="+verticalIndent+" ";
+ if (verticalSpan != 1) string += "verticalSpan="+verticalSpan+" ";
+ if (grabExcessVerticalSpace) string += "grabExcessVerticalSpace="+grabExcessVerticalSpace+" ";
+ if (heightHint != SWT.DEFAULT) string += "heightHint="+heightHint+" ";
+ if (minimumHeight != 0) string += "minimumHeight="+minimumHeight+" ";
+ if (exclude) string += "exclude="+exclude+" ";
+ string = string.trim();
+ string += "}";
+ return string;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/layout/GridLayout.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/layout/GridLayout.java
new file mode 100644
index 000000000..d0bb2c6f4
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/layout/GridLayout.java
@@ -0,0 +1,754 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.layout;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Instances of this class lay out the control children of a
+ * Composite
in a grid.
+ * GridLayout
has a number of configuration fields, and the
+ * controls it lays out can have an associated layout data object, called
+ * GridData
. The power of GridLayout
lies in the
+ * ability to configure GridData
for each control in the layout.
+ * GridLayout
+ * with 3 columns:
+ * Display display = new Display();
+ * Shell shell = new Shell(display);
+ * GridLayout gridLayout = new GridLayout();
+ * gridLayout.numColumns = 3;
+ * shell.setLayout(gridLayout);
+ *
+ * numColumns
field is the most important field in a
+ * GridLayout
. Widgets are laid out in columns from left
+ * to right, and a new row is created when numColumns
+ 1
+ * controls are added to the Composite
.
+ * RowData
object
+ * into the control.
+ * RowData
object to change the initial
+ * size of a Button
in a Shell
:
+ *
+ * Display display = new Display();
+ * Shell shell = new Shell(display);
+ * shell.setLayout(new RowLayout());
+ * Button button1 = new Button(shell, SWT.PUSH);
+ * button1.setText("Button 1");
+ * button1.setLayoutData(new RowData(50, 40));
+ *
+ *
+ * @see RowLayout
+ * @see Sample code and further information
+ */
+public final class RowData {
+ /**
+ * width specifies the desired width in points. This value
+ * is the wHint passed into Control.computeSize(int, int, boolean)
+ * to determine the preferred size of the control.
+ *
+ * The default value is SWT.DEFAULT.
+ *
+ * @see org.eclipse.swt.widgets.Control#computeSize(int, int, boolean)
+ */
+ public int width = SWT.DEFAULT;
+ /**
+ * height specifies the preferred height in points. This value
+ * is the hHint passed into Control.computeSize(int, int, boolean)
+ * to determine the preferred size of the control.
+ *
+ * The default value is SWT.DEFAULT.
+ *
+ * @see org.eclipse.swt.widgets.Control#computeSize(int, int, boolean)
+ */
+ public int height = SWT.DEFAULT;
+
+ /**
+ * exclude informs the layout to ignore this control when sizing
+ * and positioning controls. If this value is true
,
+ * the size and position of the control will not be managed by the
+ * layout. If this value is false
, the size and
+ * position of the control will be computed and assigned.
+ *
+ * The default value is false
.
+ *
+ * @since 3.1
+ */
+ public boolean exclude = false;
+
+/**
+ * Constructs a new instance of RowData using
+ * default values.
+ */
+public RowData () {
+}
+
+/**
+ * Constructs a new instance of RowData according to the parameters.
+ * A value of SWT.DEFAULT indicates that no minimum width or
+ * no minimum height is specified.
+ *
+ * @param width a minimum width for the control
+ * @param height a minimum height for the control
+ */
+public RowData (int width, int height) {
+ this.width = width;
+ this.height = height;
+}
+
+/**
+ * Constructs a new instance of RowData according to the parameter.
+ * A value of SWT.DEFAULT indicates that no minimum width or
+ * no minimum height is specified.
+ *
+ * @param point a point whose x coordinate specifies a minimum width for the control
+ * and y coordinate specifies a minimum height for the control
+ */
+public RowData (Point point) {
+ this (point.x, point.y);
+}
+
+String getName () {
+ String string = getClass ().getName ();
+ int index = string.lastIndexOf ('.');
+ if (index == -1) return string;
+ return string.substring (index + 1, string.length ());
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the RowData object
+ */
+@Override
+public String toString () {
+ String string = getName ()+" {";
+ if (width != SWT.DEFAULT) string += "width="+width+" ";
+ if (height != SWT.DEFAULT) string += "height="+height+" ";
+ if (exclude) string += "exclude="+exclude+" ";
+ string = string.trim();
+ string += "}";
+ return string;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/layout/RowLayout.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/layout/RowLayout.java
new file mode 100644
index 000000000..cb21fcd13
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/layout/RowLayout.java
@@ -0,0 +1,522 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.layout;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Instances of this class determine the size and position of the
+ * children of a Composite
by placing them either in
+ * horizontal rows or vertical columns within the parent Composite
.
+ * RowLayout
aligns all controls in one row if the
+ * type
is set to horizontal, and one column if it is
+ * set to vertical. It has the ability to wrap, and provides configurable
+ * margins and spacing. RowLayout
has a number of configuration
+ * fields. In addition, the height and width of each control in a
+ * RowLayout
can be specified by setting a RowData
+ * object into the control using setLayoutData ()
.
+ * RowLayout
, sets all
+ * of its fields to non-default values, and then sets it into a
+ * Shell
.
+ * RowLayout rowLayout = new RowLayout();
+ * rowLayout.wrap = false;
+ * rowLayout.pack = false;
+ * rowLayout.justify = true;
+ * rowLayout.type = SWT.VERTICAL;
+ * rowLayout.marginLeft = 5;
+ * rowLayout.marginTop = 5;
+ * rowLayout.marginRight = 5;
+ * rowLayout.marginBottom = 5;
+ * rowLayout.spacing = 0;
+ * shell.setLayout(rowLayout);
+ *
+ * If you are using the default field values, you only need one line of code:
+ *
+ * shell.setLayout(new RowLayout());
+ *
+ *
+ * @see RowData
+ * @see RowLayout snippets
+ * @see SWT Example: LayoutExample
+ * @see Sample code and further information
+ */
+public final class RowLayout extends Layout {
+
+ /**
+ * type specifies whether the layout places controls in rows or
+ * columns.
+ *
+ * The default value is HORIZONTAL.
+ *
+ * Possible values are:
+ *
+ *
+ * @since 2.0
+ */
+ public int type = SWT.HORIZONTAL;
+
+ /**
+ * marginWidth specifies the number of points of horizontal margin
+ * that will be placed along the left and right edges of the layout.
+ *
+ * The default value is 0.
+ *
+ * @since 3.0
+ */
+ public int marginWidth = 0;
+
+ /**
+ * marginHeight specifies the number of points of vertical margin
+ * that will be placed along the top and bottom edges of the layout.
+ *
+ * The default value is 0.
+ *
+ * @since 3.0
+ */
+ public int marginHeight = 0;
+
+ /**
+ * spacing specifies the number of points between the edge of one cell
+ * and the edge of its neighbouring cell.
+ *
+ * The default value is 3.
+ */
+ public int spacing = 3;
+
+ /**
+ * wrap specifies whether a control will be wrapped to the next
+ * row if there is insufficient space on the current row.
+ *
+ * The default value is true.
+ */
+ public boolean wrap = true;
+
+ /**
+ * pack specifies whether all controls in the layout take
+ * their preferred size. If pack is false, all controls will
+ * have the same size which is the size required to accommodate the
+ * largest preferred height and the largest preferred width of all
+ * the controls in the layout.
+ *
+ * The default value is true.
+ */
+ public boolean pack = true;
+
+ /**
+ * fill specifies whether the controls in a row should be
+ * all the same height for horizontal layouts, or the same
+ * width for vertical layouts.
+ *
+ * The default value is false.
+ *
+ * @since 3.0
+ */
+ public boolean fill = false;
+
+ /**
+ * center specifies whether the controls in a row should be
+ * centered vertically in each cell for horizontal layouts,
+ * or centered horizontally in each cell for vertical layouts.
+ *
+ * The default value is false.
+ *
+ * @since 3.4
+ */
+ public boolean center = false;
+
+ /**
+ * justify specifies whether the controls in a row should be
+ * fully justified, with any extra space placed between the controls.
+ *
+ * The default value is false.
+ */
+ public boolean justify = false;
+
+ /**
+ * marginLeft specifies the number of points of horizontal margin
+ * that will be placed along the left edge of the layout.
+ *
+ * The default value is 3.
+ */
+ public int marginLeft = 3;
+
+ /**
+ * marginTop specifies the number of points of vertical margin
+ * that will be placed along the top edge of the layout.
+ *
+ * The default value is 3.
+ */
+ public int marginTop = 3;
+
+ /**
+ * marginRight specifies the number of points of horizontal margin
+ * that will be placed along the right edge of the layout.
+ *
+ * The default value is 3.
+ */
+ public int marginRight = 3;
+
+ /**
+ * marginBottom specifies the number of points of vertical margin
+ * that will be placed along the bottom edge of the layout.
+ *
+ * The default value is 3.
+ */
+ public int marginBottom = 3;
+
+/**
+ * Constructs a new instance of this class with type HORIZONTAL.
+ */
+public RowLayout () {
+}
+
+/**
+ * Constructs a new instance of this class given the type.
+ *
+ * @param type the type of row layout
+ *
+ * @since 2.0
+ */
+public RowLayout (int type) {
+ this.type = type;
+}
+
+@Override
+protected Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache) {
+ Point extent;
+ if (type == SWT.HORIZONTAL) {
+ extent = layoutHorizontal (composite, false, (wHint != SWT.DEFAULT) && wrap, wHint, flushCache);
+ } else {
+ extent = layoutVertical (composite, false, (hHint != SWT.DEFAULT) && wrap, hHint, flushCache);
+ }
+ if (wHint != SWT.DEFAULT) extent.x = wHint;
+ if (hHint != SWT.DEFAULT) extent.y = hHint;
+ return extent;
+}
+
+Point computeSize (Control control, boolean flushCache) {
+ int wHint = SWT.DEFAULT, hHint = SWT.DEFAULT;
+ RowData data = (RowData) control.getLayoutData ();
+ if (data != null) {
+ wHint = data.width;
+ hHint = data.height;
+ }
+ return control.computeSize (wHint, hHint, flushCache);
+}
+
+@Override
+protected boolean flushCache (Control control) {
+ return true;
+}
+
+String getName () {
+ String string = getClass ().getName ();
+ int index = string.lastIndexOf ('.');
+ if (index == -1) return string;
+ return string.substring (index + 1, string.length ());
+}
+
+@Override
+protected void layout (Composite composite, boolean flushCache) {
+ Rectangle clientArea = composite.getClientArea ();
+ if (type == SWT.HORIZONTAL) {
+ layoutHorizontal (composite, true, wrap, clientArea.width, flushCache);
+ } else {
+ layoutVertical (composite, true, wrap, clientArea.height, flushCache);
+ }
+}
+
+Point layoutHorizontal (Composite composite, boolean move, boolean wrap, int width, boolean flushCache) {
+ Control [] children = composite.getChildren ();
+ int count = 0;
+ for (int i=0; i
+Package Specification
+This package contains several standard layout classes which provide
+automated positioning and sizing support for SWT widgets.
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OLE.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OLE.java
new file mode 100644
index 000000000..c10f62abf
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OLE.java
@@ -0,0 +1,442 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+import org.eclipse.swt.*;
+import java.io.File;
+import org.eclipse.swt.internal.ole.win32.COM;
+import org.eclipse.swt.internal.win32.OS;
+import org.eclipse.swt.internal.win32.TCHAR;
+
+
+/**
+ *
+ * OLE contains all the constants used to create an ActiveX Control or an OLE Document.
+ *
+ *
+ *
+ */
+public static String findProgramID (String extension) {
+ if (extension == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (extension.length () == 0) return ""; //$NON-NLS-1$
+
+ if (extension.charAt (0) != '.') extension = "." + extension; //$NON-NLS-1$
+
+ /* Use the character encoding for the default locale */
+ TCHAR extensionKey = new TCHAR(0, extension, true);
+ String result = getKeyValue(extensionKey);
+ if (result != null) {
+ // look for "getProperty
),
+ * to set property values (setProperty
) or to invoke a method (invoke
or
+ * invokeNoReply
). Arguments are passed around in the form of Variant
+ * objects.
+ *
+ *
+ * interface IMyControl : IDispatch
+ * {
+ * [propget, id(0)] HRESULT maxFileCount([retval, out] int *c);
+ * [propput, id(0)] HRESULT maxFileCount([in] int c);
+ * [id(1)] HRESULT AddFile([in] BSTR fileName);
+ * };
+ *
+ *
+ *
+ *
+ * @see OLE and ActiveX snippets
+ * @see SWT Examples: OLEExample, OleWebBrowser
+ */
+public final class OleAutomation {
+ private IUnknown objIUnknown;
+ private IDispatch objIDispatch;
+ private String exceptionDescription;
+ private ITypeInfo objITypeInfo;
+
+OleAutomation(IDispatch idispatch) {
+ if (idispatch == null) OLE.error(OLE.ERROR_INVALID_INTERFACE_ADDRESS);
+ objIDispatch = idispatch;
+ objIDispatch.AddRef();
+
+ long[] ppv = new long[1];
+ /* GetTypeInfo([in] iTInfo, [in] lcid, [out] ppTInfo)
+ * AddRef has already been called on ppTInfo by the callee and must be released by the caller.
+ */
+ int result = objIDispatch.GetTypeInfo(0, COM.LOCALE_USER_DEFAULT, ppv);
+ if (result == OLE.S_OK) {
+ objITypeInfo = new ITypeInfo(ppv[0]);
+ }
+}
+/**
+ * Creates an OleAutomation object for the specified client.
+ *
+ * @param clientSite the site for the OLE Document or ActiveX Control whose additional functionality
+ * you need to access
+ *
+ * @exception IllegalArgumentException
+ * OleAutomation automation = new OleAutomation(myControlSite);
+ *
+ * // Look up the ID of the maxFileCount parameter
+ * int[] rgdispid = automation.getIDsOfNames(new String[]{"maxFileCount"});
+ * int maxFileCountID = rgdispid[0];
+ *
+ * // Set the property maxFileCount to 100:
+ * if (automation.setProperty(maxFileCountID, new Variant(100))) {
+ * System.out.println("Max File Count was successfully set.");
+ * }
+ *
+ * // Get the new value of the maxFileCount parameter:
+ * Variant pVarResult = automation.getProperty(maxFileCountID);
+ * if (pVarResult != null) {
+ * System.out.println("Max File Count is "+pVarResult.getInt());
+ * }
+ *
+ * // Invoke the AddFile method
+ * // Look up the IDs of the AddFile method and its parameter
+ * rgdispid = automation.getIDsOfNames(new String[]{"AddFile", "fileName"});
+ * int dispIdMember = rgdispid[0];
+ * int[] rgdispidNamedArgs = new int[] {rgdispid[1]};
+ *
+ * // Convert arguments to Variant objects
+ * Variant[] rgvarg = new Variant[1];
+ * String fileName = "C:\\testfile";
+ * rgvarg[0] = new Variant(fileName);
+ *
+ * // Call the method
+ * Variant pVarResult = automation.invoke(dispIdMember, rgvarg, rgdispidNamedArgs);
+ *
+ * // Check the return value
+ * if (pVarResult == null || pVarResult.getInt() != OLE.S_OK){
+ * System.out.println("Failed to add file "+fileName);
+ * }
+ *
+ * automation.dispose();
+ *
+ *
+ *
+ */
+public OleAutomation(OleClientSite clientSite) {
+ if (clientSite == null) OLE.error(OLE.ERROR_INVALID_INTERFACE_ADDRESS);
+ objIDispatch = clientSite.getAutomationObject();
+
+ long[] ppv = new long[1];
+ /* GetTypeInfo([in] iTInfo, [in] lcid, [out] ppTInfo)
+ * AddRef has already been called on ppTInfo by the callee and must be released by the caller.
+ */
+ int result = objIDispatch.GetTypeInfo(0, COM.LOCALE_USER_DEFAULT, ppv);
+ if (result == OLE.S_OK) {
+ objITypeInfo = new ITypeInfo(ppv[0]);
+ }
+}
+/**
+ * Creates an OleAutomation object for the specified progID
.
+ *
+ * @param progId the unique program identifier of an OLE Document application;
+ * the value of the ProgID key or the value of the VersionIndependentProgID key specified
+ * in the registry for the desired OLE Document (for example, the VersionIndependentProgID
+ * for Word is Word.Document)
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.6
+ */
+public OleAutomation(String progId) {
+ try {
+ OS.OleInitialize(0);
+ GUID appClsid = getClassID(progId);
+ if (appClsid == null) {
+ OS.OleUninitialize();
+ OLE.error(OLE.ERROR_INVALID_CLASSID);
+ }
+ int flags = COM.CLSCTX_INPROC_SERVER | COM.CLSCTX_LOCAL_SERVER;
+ long[] ppvObject = new long[1];
+ int result = COM.CoCreateInstance(appClsid, 0, flags, COM.IIDIUnknown, ppvObject);
+ if (result != COM.S_OK) {
+ OS.OleUninitialize();
+ OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
+ }
+ objIUnknown = new IUnknown(ppvObject[0]);
+
+ ppvObject[0] = 0;
+ result = objIUnknown.QueryInterface(COM.IIDIDispatch, ppvObject);
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_INTERFACE_NOT_FOUND);
+ objIDispatch = new IDispatch(ppvObject[0]);
+
+ ppvObject[0] = 0;
+ result = objIDispatch.GetTypeInfo(0, COM.LOCALE_USER_DEFAULT, ppvObject);
+ if (result == OLE.S_OK) {
+ objITypeInfo = new ITypeInfo(ppvObject[0]);
+ }
+ } catch (SWTException e) {
+ dispose();
+ throw e;
+ }
+}
+/**
+ * Disposes the automation object.
+ * public void invoke(int dispIdMember)
.
+ *
+ * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ *
+ * @exception org.eclipse.swt.SWTException
+ *
+ */
+public void invokeNoReply(int dispIdMember) {
+ int result = invoke(dispIdMember, COM.DISPATCH_METHOD, null, null, null);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_ACTION_NOT_PERFORMED, result);
+}
+/**
+ * Invokes a method on the OLE Object; the method has no optional parameters. In the early days of OLE,
+ * the IDispatch interface was not well defined and some applications (mainly Word) did not support
+ * a return value. For these applications, call this method instead of calling
+ * public void invoke(int dispIdMember, Variant[] rgvarg)
.
+ *
+ * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ *
+ * @param rgvarg an array of arguments for the method. All arguments are considered to be
+ * read only unless the Variant is a By Reference Variant type.
+ *
+ * @exception org.eclipse.swt.SWTException
+ *
+ */
+public void invokeNoReply(int dispIdMember, Variant[] rgvarg) {
+ int result = invoke(dispIdMember, COM.DISPATCH_METHOD, rgvarg, null, null);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_ACTION_NOT_PERFORMED, result);
+}
+/**
+ * Invokes a method on the OLE Object; the method has optional parameters. It is not
+ * necessary to specify all the optional parameters, only include the parameters for which
+ * you are providing values. In the early days of OLE, the IDispatch interface was not well
+ * defined and some applications (mainly Word) did not support a return value. For these
+ * applications, call this method instead of calling
+ * public void invoke(int dispIdMember, Variant[] rgvarg, int[] rgdispidNamedArgs)
.
+ *
+ * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ *
+ * @param rgvarg an array of arguments for the method. All arguments are considered to be
+ * read only unless the Variant is a By Reference Variant type.
+ *
+ * @param rgdispidNamedArgs an array of identifiers for the arguments specified in rgvarg; the
+ * parameter IDs must be in the same order as their corresponding values;
+ * all arguments must have an identifier - identifiers can be obtained using
+ * OleAutomation.getIDsOfNames
+ *
+ * @exception org.eclipse.swt.SWTException
+ *
+ */
+public void invokeNoReply(int dispIdMember, Variant[] rgvarg, int[] rgdispidNamedArgs) {
+ int result = invoke(dispIdMember, COM.DISPATCH_METHOD, rgvarg, rgdispidNamedArgs, null);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_ACTION_NOT_PERFORMED, result);
+}
+private void manageExcepinfo(int hResult, EXCEPINFO excepInfo) {
+
+ if (hResult == COM.S_OK){
+ exceptionDescription = "No Error"; //$NON-NLS-1$
+ return;
+ }
+
+ // extract exception info
+ if (hResult == COM.DISP_E_EXCEPTION) {
+ if (excepInfo.bstrDescription != 0){
+ int size = COM.SysStringByteLen(excepInfo.bstrDescription);
+ char[] buffer = new char[(size + 1) /2];
+ OS.MoveMemory(buffer, excepInfo.bstrDescription, size);
+ exceptionDescription = new String(buffer);
+ } else {
+ exceptionDescription = "OLE Automation Error Exception "; //$NON-NLS-1$
+ if (excepInfo.wCode != 0){
+ exceptionDescription += "code = "+excepInfo.wCode; //$NON-NLS-1$
+ } else if (excepInfo.scode != 0){
+ exceptionDescription += "code = "+excepInfo.scode; //$NON-NLS-1$
+ }
+ }
+ } else {
+ exceptionDescription = "OLE Automation Error HResult : " + hResult; //$NON-NLS-1$
+ }
+
+ // cleanup EXCEPINFO struct
+ if (excepInfo.bstrDescription != 0)
+ COM.SysFreeString(excepInfo.bstrDescription);
+ if (excepInfo.bstrHelpFile != 0)
+ COM.SysFreeString(excepInfo.bstrHelpFile);
+ if (excepInfo.bstrSource != 0)
+ COM.SysFreeString(excepInfo.bstrSource);
+}
+/**
+ * Sets the property specified by the dispIdMember to a new value.
+ *
+ * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ * @param rgvarg the new value of the property
+ *
+ * @return true if the operation was successful
+ */
+public boolean setProperty(int dispIdMember, Variant rgvarg) {
+ Variant[] rgvarg2 = new Variant[] {rgvarg};
+ int[] rgdispidNamedArgs = new int[] {COM.DISPID_PROPERTYPUT};
+ int dwFlags = COM.DISPATCH_PROPERTYPUT;
+ if ((rgvarg.getType() & COM.VT_BYREF) == COM.VT_BYREF)
+ dwFlags = COM.DISPATCH_PROPERTYPUTREF;
+ Variant pVarResult = new Variant();
+ int result = invoke(dispIdMember, dwFlags, rgvarg2, rgdispidNamedArgs, pVarResult);
+ return (result == COM.S_OK);
+}
+/**
+ * Sets the property specified by the dispIdMember to a new value.
+ *
+ * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
+ * value for the ID can be obtained using OleAutomation.getIDsOfNames
+ * @param rgvarg an array of arguments for the method. All arguments are considered to be
+ * read only unless the Variant is a By Reference Variant type.
+ *
+ * @return true if the operation was successful
+ *
+ * @since 2.0
+ */
+public boolean setProperty(int dispIdMember, Variant[] rgvarg) {
+ int[] rgdispidNamedArgs = new int[] {COM.DISPID_PROPERTYPUT};
+ int dwFlags = COM.DISPATCH_PROPERTYPUT;
+ for (int i = 0; i < rgvarg.length; i++) {
+ if ((rgvarg[i].getType() & COM.VT_BYREF) == COM.VT_BYREF)
+ dwFlags = COM.DISPATCH_PROPERTYPUTREF;
+ }
+ Variant pVarResult = new Variant();
+ int result = invoke(dispIdMember, dwFlags, rgvarg, rgdispidNamedArgs, pVarResult);
+ return (result == COM.S_OK);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleClientSite.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleClientSite.java
new file mode 100644
index 000000000..0cc24ac86
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleClientSite.java
@@ -0,0 +1,1523 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+/**
+ * OleClientSite provides a site to manage an embedded OLE Document within a container.
+ *
+ *
+ *
+ *
+ * Composite
,
+ * it does not make sense to add Control
children to it,
+ * or set a layout on it.
+ *
+ *
+ *
+ * @see OLE and ActiveX snippets
+ * @see SWT Examples: OLEExample, OleWebBrowser
+ */
+public class OleClientSite extends Composite {
+
+ // Interfaces for this Ole Client Container
+ COMObject iOleClientSite;
+ private COMObject iAdviseSink;
+ private COMObject iOleInPlaceSite;
+ private COMObject iOleDocumentSite;
+
+ protected GUID appClsid;
+ private GUID objClsid;
+ private int refCount;
+
+ // References to the associated Frame.
+ protected OleFrame frame;
+
+ // Access to the embedded/linked Ole Object
+ protected IUnknown objIUnknown;
+ protected IOleObject objIOleObject;
+ protected IViewObject2 objIViewObject2;
+ protected IOleInPlaceObject objIOleInPlaceObject;
+ protected IOleCommandTarget objIOleCommandTarget;
+ protected IOleDocumentView objDocumentView;
+
+ // Related storage information
+ protected IStorage tempStorage; // IStorage interface of the receiver
+
+ // Internal state and style information
+ private int aspect; // the display aspect of the embedded object, e.g., DvaspectContent or DvaspectIcon
+ private int type; // Indicates the type of client that can be supported inside this container
+ private boolean isStatic; // Indicates item's display is static, i.e., a bitmap, metafile, etc.
+ boolean isActivated;
+
+ private RECT borderWidths = new RECT();
+ private RECT indent = new RECT();
+ private boolean inUpdate = false;
+ private boolean inInit = true;
+ private boolean inDispose = false;
+
+ private static final String WORDPROGID = "Word.Document"; //$NON-NLS-1$
+
+ private Listener listener;
+
+ static final int STATE_NONE = 0;
+ static final int STATE_RUNNING = 1;
+ static final int STATE_INPLACEACTIVE = 2;
+ static final int STATE_UIACTIVE = 3;
+ static final int STATE_ACTIVE = 4;
+ int state = STATE_NONE;
+
+protected OleClientSite(Composite parent, int style) {
+ /*
+ * NOTE: this constructor should never be used by itself because it does
+ * not create an Ole Object
+ */
+ super(parent, style);
+
+ createCOMInterfaces();
+
+ // install the Ole Frame for this Client Site
+ while (parent != null) {
+ if (parent instanceof OleFrame){
+ frame = (OleFrame)parent;
+ break;
+ }
+ parent = parent.getParent();
+ }
+ if (frame == null) OLE.error(SWT.ERROR_INVALID_ARGUMENT);
+ frame.AddRef();
+
+ aspect = COM.DVASPECT_CONTENT;
+ type = COM.OLEEMBEDDED;
+ isStatic = false;
+
+ listener = new Listener() {
+ private int nestedFocusEvents = 0;
+ @Override
+ public void handleEvent(Event e) {
+ switch (e.type) {
+ case SWT.Resize :
+ case SWT.Move : onResize(e); break;
+ case SWT.Dispose : onDispose(e); break;
+ case SWT.FocusIn:
+ nestedFocusEvents++;
+ boolean hasFocus = isFocusControl();
+ onFocusIn(e);
+ nestedFocusEvents--;
+ /*
+ * Added additional check below to avoid calling OleFrame#onFocusIn() twice,
+ * which other wise lead to Main Menu refresh problem as seen in bug 527268
+ */
+ if (nestedFocusEvents == 0 && hasFocus == isFocusControl())
+ frame.onFocusIn(e);
+ break;
+ case SWT.FocusOut:
+ nestedFocusEvents++;
+ onFocusOut(e);
+ nestedFocusEvents--;
+ if (nestedFocusEvents == 0)
+ frame.onFocusOut(e);
+ break;
+ case SWT.Paint: onPaint(e); break;
+ case SWT.Traverse: onTraverse(e); break;
+ case SWT.KeyDown: /* required for traversal */ break;
+ case SWT.Activate: isActivated = true; break;
+ case SWT.Deactivate: isActivated = false; break;
+ default :
+ OLE.error(SWT.ERROR_NOT_IMPLEMENTED);
+ }
+ }
+ };
+
+ frame.addListener(SWT.Resize, listener);
+ frame.addListener(SWT.Move, listener);
+ addListener(SWT.Dispose, listener);
+ addListener(SWT.FocusIn, listener);
+ addListener(SWT.FocusOut, listener);
+ addListener(SWT.Paint, listener);
+ addListener(SWT.Traverse, listener);
+ addListener(SWT.KeyDown, listener);
+ addListener(SWT.Activate, listener);
+ addListener(SWT.Deactivate, listener);
+}
+/**
+ * Create an OleClientSite child widget using the OLE Document type associated with the
+ * specified file. The OLE Document type is determined either through header information in the file
+ * or through a Registry entry for the file extension. Use style bits to select a particular look
+ * or set of properties.
+ *
+ * @param parent a composite widget; must be an OleFrame
+ * @param style the bitwise OR'ing of widget styles
+ * @param file the file that is to be opened in this OLE Document
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public OleClientSite(Composite parent, int style, File file) {
+ this(parent, style);
+ try {
+
+ if (file == null || file.isDirectory() || !file.exists())
+ OLE.error(SWT.ERROR_INVALID_ARGUMENT);
+
+ // Is there an associated CLSID?
+ GUID fileClsid = new GUID();
+ char[] fileName = (file.getAbsolutePath()+"\0").toCharArray();
+ int result = COM.GetClassFile(fileName, fileClsid);
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_INVALID_CLASSID, result);
+ // associated CLSID may not be installed on this machine
+ String progID = getProgID(fileClsid);
+ if (progID == null) OLE.error(OLE.ERROR_INVALID_CLASSID, result);
+
+ appClsid = fileClsid;
+ OleCreate(appClsid, fileClsid, fileName, file);
+ } catch (SWTException e) {
+ dispose();
+ disposeCOMInterfaces();
+ throw e;
+ }
+}
+/**
+ * Create an OleClientSite child widget to edit a blank document using the specified OLE Document
+ * application. Use style bits to select a particular look or set of properties.
+ *
+ * @param parent a composite widget; must be an OleFrame
+ * @param style the bitwise OR'ing of widget styles
+ * @param progId the unique program identifier of an OLE Document application;
+ * the value of the ProgID key or the value of the VersionIndependentProgID key specified
+ * in the registry for the desired OLE Document (for example, the VersionIndependentProgID
+ * for Word is Word.Document)
+ *
+ * @exception IllegalArgumentException
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public OleClientSite(Composite parent, int style, String progId) {
+ this(parent, style);
+ try {
+ appClsid = getClassID(progId);
+ if (appClsid == null)
+ OLE.error(OLE.ERROR_INVALID_CLASSID);
+
+ // Open a temporary storage object
+ tempStorage = createTempStorage();
+
+ // Create ole object with storage object
+ long[] address = new long[1];
+ /*
+ * Bug in ICA Client 2.7. The creation of the IOleObject fails if the client
+ * site is provided to OleCreate(). The fix is to detect that the program
+ * id is an ICA Client and do not pass a client site to OleCreate().
+ * IOleObject.SetClientSite() is called later on.
+ */
+ long clientSite = isICAClient() ? 0 : iOleClientSite.getAddress();
+ int result = COM.OleCreate(appClsid, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, clientSite, tempStorage.getAddress(), address);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
+
+ objIUnknown = new IUnknown(address[0]);
+
+ // Init sinks
+ addObjectReferences();
+
+ if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING;
+
+ } catch (SWTException e) {
+ dispose();
+ disposeCOMInterfaces();
+ throw e;
+ }
+}
+/**
+ * Create an OleClientSite child widget to edit the specified file using the specified OLE Document
+ * application. Use style bits to select a particular look or set of properties.
+ * OleClientSite
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ * @exception SWTException
+ *
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ */
+public OleClientSite(Composite parent, int style, String progId, File file) {
+ this(parent, style);
+ try {
+ if (file == null || file.isDirectory() || !file.exists()) OLE.error(SWT.ERROR_INVALID_ARGUMENT);
+ appClsid = getClassID(progId);
+ if (appClsid == null) OLE.error(OLE.ERROR_INVALID_CLASSID);
+
+ // Are we opening this file with the preferred OLE object?
+ char[] fileName = (file.getAbsolutePath()+"\0").toCharArray();
+ GUID fileClsid = new GUID();
+ COM.GetClassFile(fileName, fileClsid);
+
+ OleCreate(appClsid, fileClsid, fileName, file);
+ } catch (SWTException e) {
+ dispose();
+ disposeCOMInterfaces();
+ throw e;
+ }
+}
+
+void OleCreate(GUID appClsid, GUID fileClsid, char[] fileName, File file) {
+
+ /* Bug in Windows. In some machines running Windows Vista and
+ * Office 2007, OleCreateFromFile() fails to open files from
+ * Office Word 97 - 2003 and in some other cases it fails to
+ * save files due to a lock. The fix is to detect this case and
+ * create the activeX using CoCreateInstance().
+ */
+ boolean isOffice2007 = isOffice2007(true);
+ if (!isOffice2007 && COM.IsEqualGUID(appClsid, fileClsid)){
+ // Using the same application that created file, therefore, use default mechanism.
+ tempStorage = createTempStorage();
+ // Create ole object with storage object
+ long[] address = new long[1];
+ int result = COM.OleCreateFromFile(appClsid, fileName, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, iOleClientSite.getAddress(), tempStorage.getAddress(), address);
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
+ objIUnknown = new IUnknown(address[0]);
+ } else {
+ // Not using the same application that created file, therefore, copy from original file to a new storage file
+ IStorage storage = null;
+ if (COM.StgIsStorageFile(fileName) == COM.S_OK) {
+ long[] address = new long[1];
+ int mode = COM.STGM_READ | COM.STGM_TRANSACTED | COM.STGM_SHARE_EXCLUSIVE;
+ int result = COM.StgOpenStorage(fileName, 0, mode, 0, 0, address); //Does an AddRef if successful
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
+ storage = new IStorage(address[0]);
+ } else {
+ // Original file is not a Storage file so copy contents to a stream in a new storage file
+ long[] address = new long[1];
+ int mode = COM.STGM_READWRITE | COM.STGM_DIRECT | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE;
+ int result = COM.StgCreateDocfile(null, mode | COM.STGM_DELETEONRELEASE, 0, address); // Increments ref count if successful
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
+ storage = new IStorage(address[0]);
+ // Create a stream on the storage object.
+ // Word does not follow the standard and does not use "CONTENTS" as the name of
+ // its primary stream
+ String streamName = "CONTENTS"; //$NON-NLS-1$
+ GUID wordGUID = getClassID(WORDPROGID);
+ if (wordGUID != null && COM.IsEqualGUID(appClsid, wordGUID)) streamName = "WordDocument"; //$NON-NLS-1$
+ if (isOffice2007) streamName = "Package"; //$NON-NLS-1$
+ address = new long[1];
+ result = storage.CreateStream(streamName, mode, 0, 0, address); // Increments ref count if successful
+ if (result != COM.S_OK) {
+ storage.Release();
+ OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
+ }
+ IStream stream = new IStream(address[0]);
+ try {
+ // Copy over data in file to named stream
+ FileInputStream fileInput = new FileInputStream(file);
+ int increment = 1024*4;
+ byte[] buffer = new byte[increment];
+ int count = 0;
+ while((count = fileInput.read(buffer)) > 0){
+ long pv = OS.CoTaskMemAlloc(count);
+ OS.MoveMemory(pv, buffer, count);
+ result = stream.Write(pv, count, null) ;
+ OS.CoTaskMemFree(pv);
+ if (result != COM.S_OK) {
+ fileInput.close();
+ stream.Release();
+ storage.Release();
+ OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
+ }
+ }
+ fileInput.close();
+ stream.Commit(COM.STGC_DEFAULT);
+ stream.Release();
+ } catch (IOException err) {
+ stream.Release();
+ storage.Release();
+ OLE.error(OLE.ERROR_CANNOT_OPEN_FILE);
+ }
+ }
+
+ // Open a temporary storage object
+ tempStorage = createTempStorage();
+ // Copy over contents of file
+ int result = storage.CopyTo(0, null, null, tempStorage.getAddress());
+ storage.Release();
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
+
+ // create ole client
+ long[] ppv = new long[1];
+ result = COM.CoCreateInstance(appClsid, 0, COM.CLSCTX_INPROC_HANDLER | COM.CLSCTX_INPROC_SERVER, COM.IIDIUnknown, ppv);
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
+ objIUnknown = new IUnknown(ppv[0]);
+ // get the persistent storage of the ole client
+ ppv = new long[1];
+ result = objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv);
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
+ IPersistStorage iPersistStorage = new IPersistStorage(ppv[0]);
+ // load the contents of the file into the ole client site
+ result = iPersistStorage.Load(tempStorage.getAddress());
+ iPersistStorage.Release();
+ if (result != COM.S_OK)OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
+ }
+
+ // Init sinks
+ addObjectReferences();
+
+ if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING;
+}
+protected void addObjectReferences() {
+ //
+ long[] ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIPersist, ppvObject) == COM.S_OK) {
+ IPersist objIPersist = new IPersist(ppvObject[0]);
+ GUID tempid = new GUID();
+ if (objIPersist.GetClassID(tempid) == COM.S_OK)
+ objClsid = tempid;
+ objIPersist.Release();
+ }
+
+ //
+ ppvObject = new long[1];
+ int result = objIUnknown.QueryInterface(COM.IIDIViewObject2, ppvObject);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_INTERFACE_NOT_FOUND, result);
+ objIViewObject2 = new IViewObject2(ppvObject[0]);
+ objIViewObject2.SetAdvise(aspect, 0, iAdviseSink.getAddress());
+
+ //
+ ppvObject = new long[1];
+ result = objIUnknown.QueryInterface(COM.IIDIOleObject, ppvObject);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_INTERFACE_NOT_FOUND, result);
+ objIOleObject = new IOleObject(ppvObject[0]);
+ /*
+ * Feature in Windows. Despite the fact that the clientSite was provided during the
+ * creation of the OleObject (which is required by WMP11 - see bug 173556),
+ * some applications choose to ignore this optional parameter (see bug 211663)
+ * during OleCreate. The fix is to check whether the clientSite has already been set
+ * and set it. Note that setting it twice can result in assert failures.
+ */
+ long[] ppvClientSite = new long[1];
+ result = objIOleObject.GetClientSite(ppvClientSite);
+ if (ppvClientSite[0] == 0) {
+ objIOleObject.SetClientSite(iOleClientSite.getAddress());
+ } else {
+ Release(); // GetClientSite performs an AddRef so we must release it.
+ }
+ int[] pdwConnection = new int[1];
+ objIOleObject.Advise(iAdviseSink.getAddress(), pdwConnection);
+ objIOleObject.SetHostNames("main", "main"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // Notify the control object that it is embedded in an OLE container
+ COM.OleSetContainedObject(objIUnknown.getAddress(), true);
+
+ // Is OLE object linked or embedded?
+ ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIOleLink, ppvObject) == COM.S_OK) {
+ IOleLink objIOleLink = new IOleLink(ppvObject[0]);
+ long[] ppmk = new long[1];
+ if (objIOleLink.GetSourceMoniker(ppmk) == COM.S_OK) {
+ new IUnknown(ppmk[0]).Release();
+ type = COM.OLELINKED;
+ objIOleLink.BindIfRunning();
+ } else {
+ isStatic = true;
+ }
+ objIOleLink.Release();
+ }
+}
+protected int AddRef() {
+ refCount++;
+ return refCount;
+}
+private int CanInPlaceActivate() {
+ if (aspect == COM.DVASPECT_CONTENT && type == COM.OLEEMBEDDED)
+ return COM.S_OK;
+
+ return COM.S_FALSE;
+}
+private int ContextSensitiveHelp(int fEnterMode) {
+ return COM.S_OK;
+}
+protected void createCOMInterfaces() {
+
+ iOleClientSite = new COMObject(new int[]{2, 0, 0, 0, 3, 1, 0, 1, 0}){
+ @Override
+ public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ @Override
+ public long method3(long[] args) {return SaveObject();}
+ // method4 GetMoniker - not implemented
+ @Override
+ public long method5(long[] args) {return GetContainer(args[0]);}
+ @Override
+ public long method6(long[] args) {return ShowObject();}
+ @Override
+ public long method7(long[] args) {return OnShowWindow((int)args[0]);}
+ // method8 RequestNewObjectLayout - not implemented
+ };
+
+ iAdviseSink = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 0, 0}){
+ @Override
+ public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ @Override
+ public long method3(long[] args) {return OnDataChange(args[0], args[1]);}
+ @Override
+ public long method4(long[] args) {return OnViewChange((int)args[0], (int)args[1]);}
+ //method5 OnRename - not implemented
+ @Override
+ public long method6(long[] args) {OnSave();return 0;}
+ @Override
+ public long method7(long[] args) {return OnClose();}
+ };
+
+ iOleInPlaceSite = new COMObject(new int[]{2, 0, 0, 1, 1, 0, 0, 0, 5, 1, 1, 0, 0, 0, 1}){
+ @Override
+ public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ @Override
+ public long method3(long[] args) {return GetWindow(args[0]);}
+ @Override
+ public long method4(long[] args) {return ContextSensitiveHelp((int)args[0]);}
+ @Override
+ public long method5(long[] args) {return CanInPlaceActivate();}
+ @Override
+ public long method6(long[] args) {return OnInPlaceActivate();}
+ @Override
+ public long method7(long[] args) {return OnUIActivate();}
+ @Override
+ public long method8(long[] args) {return GetWindowContext(args[0], args[1], args[2], args[3], args[4]);}
+ @Override
+ public long method9(long[] args) {return Scroll(args[0]);}
+ @Override
+ public long method10(long[] args) {return OnUIDeactivate((int)args[0]);}
+ @Override
+ public long method11(long[] args) {return OnInPlaceDeactivate();}
+ // method12 DiscardUndoState - not implemented
+ // method13 DeactivateAndUndoChange - not implemented
+ @Override
+ public long method14(long[] args) {return OnPosRectChange(args[0]);}
+ };
+
+ iOleDocumentSite = new COMObject(new int[]{2, 0, 0, 1}){
+ @Override
+ public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ @Override
+ public long method3(long[] args) {return ActivateMe(args[0]);}
+ };
+}
+protected IStorage createTempStorage() {
+ long[] tempStorage = new long[1];
+ int grfMode = COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_DELETEONRELEASE;
+ int result = COM.StgCreateDocfile(null, grfMode, 0, tempStorage);
+ if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_FILE, result);
+ return new IStorage(tempStorage[0]);
+}
+/**
+ * Deactivates an active in-place object and discards the object's undo state.
+ */
+public void deactivateInPlaceClient() {
+ if (objIOleInPlaceObject != null) {
+ objIOleInPlaceObject.InPlaceDeactivate();
+ }
+}
+private void deleteTempStorage() {
+ //Destroy this item's contents in the temp root IStorage.
+ if (tempStorage != null){
+ tempStorage.Release();
+ }
+ tempStorage = null;
+}
+protected void disposeCOMInterfaces() {
+ if (iOleClientSite != null)
+ iOleClientSite.dispose();
+ iOleClientSite = null;
+
+ if (iAdviseSink != null)
+ iAdviseSink.dispose();
+ iAdviseSink = null;
+
+ if (iOleInPlaceSite != null)
+ iOleInPlaceSite.dispose();
+ iOleInPlaceSite = null;
+
+ if (iOleDocumentSite != null)
+ iOleDocumentSite.dispose();
+ iOleDocumentSite = null;
+}
+/**
+ * Requests that the OLE Document or ActiveX Control perform an action; actions are almost always
+ * changes to the activation state.
+ *
+ * @param verb the operation that is requested. This is one of the OLE.OLEIVERB_ values
+ *
+ * @return an HRESULT value indicating the success of the operation request; OLE.S_OK indicates
+ * success
+ */
+public int doVerb(int verb) {
+ // Not all OLE clients (for example PowerPoint) can be set into the running state in the constructor.
+ // The fix is to ensure that the client is in the running state before invoking any verb on it.
+ if (state == STATE_NONE) {
+ if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING;
+ }
+ if (state == STATE_NONE || isStatic)
+ return COM.E_FAIL;
+
+ // See PR: 1FV9RZW
+ RECT rect = new RECT();
+ OS.GetClientRect(handle, rect);
+ int result = objIOleObject.DoVerb(verb, null, iOleClientSite.getAddress(), 0, handle, rect);
+
+ if (state != STATE_RUNNING && inInit) {
+ updateStorage();
+ inInit = false;
+ }
+ return result;
+}
+/**
+ * Asks the OLE Document or ActiveX Control to execute a command from a standard
+ * list of commands. The OLE Document or ActiveX Control must support the IOleCommandTarget
+ * interface. The OLE Document or ActiveX Control does not have to support all the commands
+ * in the standard list. To check if a command is supported, you can call queryStatus with
+ * the cmdID.
+ *
+ * @param cmdID the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
+ * commands
+ * @param options the optional flags; these are the OLE.OLECMDEXECOPT_ values
+ * @param in the argument for the command
+ * @param out the return value of the command
+ *
+ * @return an HRESULT value; OLE.S_OK is returned if successful
+ *
+ */
+public int exec(int cmdID, int options, Variant in, Variant out) {
+
+ if (objIOleCommandTarget == null) {
+ long[] address = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIOleCommandTarget, address) != COM.S_OK)
+ return OLE.ERROR_INTERFACE_NOT_FOUND;
+ objIOleCommandTarget = new IOleCommandTarget(address[0]);
+ }
+
+ long inAddress = 0;
+ if (in != null){
+ inAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
+ in.getData(inAddress);
+ }
+ long outAddress = 0;
+ if (out != null){
+ outAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
+ out.getData(outAddress);
+ }
+
+ int result = objIOleCommandTarget.Exec(null, cmdID, options, inAddress, outAddress);
+
+ if (inAddress != 0){
+ COM.VariantClear(inAddress);
+ OS.GlobalFree(inAddress);
+ }
+ if (outAddress != 0) {
+ out.setData(outAddress);
+ COM.VariantClear(outAddress);
+ OS.GlobalFree(outAddress);
+ }
+
+ return result;
+}
+IDispatch getAutomationObject() {
+ long[] ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIDispatch, ppvObject) != COM.S_OK)
+ return null;
+ return new IDispatch(ppvObject[0]);
+}
+protected GUID getClassID(String clientName) {
+ // create a GUID struct to hold the result
+ GUID guid = new GUID();
+
+ // create a null terminated array of char
+ char[] buffer = null;
+ if (clientName != null) {
+ int count = clientName.length();
+ buffer = new char[count + 1];
+ clientName.getChars(0, count, buffer, 0);
+ }
+ if (COM.CLSIDFromProgID(buffer, guid) != COM.S_OK){
+ int result = COM.CLSIDFromString(buffer, guid);
+ if (result != COM.S_OK) return null;
+ }
+ return guid;
+}
+private int GetContainer(long ppContainer) {
+ /* Simple containers that do not support links to their embedded
+ * objects probably do not need to implement this method. Instead,
+ * they can return E_NOINTERFACE and set ppContainer to NULL.
+ */
+ if (ppContainer != 0)
+ OS.MoveMemory(ppContainer, new long[]{0}, C.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+private SIZE getExtent() {
+ SIZE sizel = new SIZE();
+ // get the current size of the embedded OLENatives object
+ if (objIOleObject != null) {
+ if ( objIViewObject2 != null && !COM.OleIsRunning(objIOleObject.getAddress())) {
+ objIViewObject2.GetExtent(aspect, -1, 0, sizel);
+ } else {
+ objIOleObject.GetExtent(aspect, sizel);
+ }
+ }
+ return xFormHimetricToPixels(sizel);
+}
+/**
+ * Returns the indent value that would be used to compute the clipping area
+ * of the active X object.
+ *
+ * NOTE: The indent value is no longer being used by the client site.
+ *
+ * @return the rectangle representing the indent
+ */
+public Rectangle getIndent() {
+ return new Rectangle(indent.left, indent.right, indent.top, indent.bottom);
+}
+/**
+ * Returns the program ID of the OLE Document or ActiveX Control.
+ *
+ * @return the program ID of the OLE Document or ActiveX Control
+ */
+public String getProgramID(){
+ return getProgID(appClsid);
+}
+String getProgID(GUID clsid) {
+ if (clsid != null){
+ long[] lplpszProgID = new long[1];
+ if (COM.ProgIDFromCLSID(clsid, lplpszProgID) == COM.S_OK) {
+ long hMem = lplpszProgID[0];
+ int length = OS.GlobalSize(hMem);
+ long ptr = OS.GlobalLock(hMem);
+ char[] buffer = new char[length];
+ OS.MoveMemory(buffer, ptr, length);
+ OS.GlobalUnlock(hMem);
+ OS.GlobalFree(hMem);
+
+ String result = new String(buffer);
+ // remove null terminator
+ int index = result.indexOf("\0");
+ return result.substring(0, index);
+ }
+ }
+ return null;
+}
+int ActivateMe(long pViewToActivate) {
+ if (pViewToActivate == 0) {
+ long[] ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIOleDocument, ppvObject) != COM.S_OK) return COM.E_FAIL;
+ IOleDocument objOleDocument = new IOleDocument(ppvObject[0]);
+ if (objOleDocument.CreateView(iOleInPlaceSite.getAddress(), 0, 0, ppvObject) != COM.S_OK) return COM.E_FAIL;
+ objOleDocument.Release();
+ objDocumentView = new IOleDocumentView(ppvObject[0]);
+ } else {
+ objDocumentView = new IOleDocumentView(pViewToActivate);
+ objDocumentView.AddRef();
+ objDocumentView.SetInPlaceSite(iOleInPlaceSite.getAddress());
+ }
+ objDocumentView.UIActivate(1);//TRUE
+ RECT rect = getRect();
+ objDocumentView.SetRect(rect);
+ objDocumentView.Show(1);//TRUE
+ return COM.S_OK;
+}
+protected int GetWindow(long phwnd) {
+ if (phwnd == 0)
+ return COM.E_INVALIDARG;
+ if (frame == null) {
+ OS.MoveMemory(phwnd, new long[] {0}, C.PTR_SIZEOF);
+ return COM.E_NOTIMPL;
+ }
+
+ // Copy the Window's handle into the memory passed in
+ OS.MoveMemory(phwnd, new long[] {handle}, C.PTR_SIZEOF);
+ return COM.S_OK;
+}
+RECT getRect() {
+ Rectangle area = DPIUtil.autoScaleUp(getClientArea()); // To Pixels
+ RECT rect = new RECT();
+ rect.left = area.x;
+ rect.top = area.y;
+ rect.right = area.x + area.width;
+ rect.bottom = area.y + area.height;
+ return rect;
+}
+private int GetWindowContext(long ppFrame, long ppDoc, long lprcPosRect, long lprcClipRect, long lpFrameInfo) {
+ if (frame == null || ppFrame == 0)
+ return COM.E_NOTIMPL;
+
+ // fill in frame handle
+ long iOleInPlaceFrame = frame.getIOleInPlaceFrame();
+ OS.MoveMemory(ppFrame, new long[] {iOleInPlaceFrame}, C.PTR_SIZEOF);
+ frame.AddRef();
+
+ // null out document handle
+ if (ppDoc != 0) OS.MoveMemory(ppDoc, new long[] {0}, C.PTR_SIZEOF);
+
+ // fill in position and clipping info
+ RECT rect = getRect();
+ if (lprcPosRect != 0) OS.MoveMemory(lprcPosRect, rect, RECT.sizeof);
+ if (lprcClipRect != 0) OS.MoveMemory(lprcClipRect, rect, RECT.sizeof);
+
+ // get frame info
+ OLEINPLACEFRAMEINFO frameInfo = new OLEINPLACEFRAMEINFO();
+ frameInfo.cb = OLEINPLACEFRAMEINFO.sizeof;
+ frameInfo.fMDIApp = 0;
+ frameInfo.hwndFrame = frame.handle;
+ Shell shell = getShell();
+ Menu menubar = shell.getMenuBar();
+ if (menubar != null && !menubar.isDisposed()) {
+ long hwnd = shell.handle;
+ int cAccel = (int)OS.SendMessage(hwnd, OS.WM_APP, 0, 0);
+ if (cAccel != 0) {
+ long hAccel = OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0);
+ if (hAccel != 0) {
+ frameInfo.cAccelEntries = cAccel;
+ frameInfo.haccel = hAccel;
+ }
+ }
+ }
+ COM.MoveMemory(lpFrameInfo, frameInfo, OLEINPLACEFRAMEINFO.sizeof);
+
+ return COM.S_OK;
+}
+boolean isICAClient() {
+ return getProgramID().startsWith("Citrix.ICAClient"); //$NON-NLS-1$
+}
+/**
+ * Returns whether ole document is dirty by checking whether the content
+ * of the file representing the document is dirty.
+ *
+ * @return true
if the document has been modified,
+ * false
otherwise.
+ * @since 3.1
+ */
+public boolean isDirty() {
+ /*
+ * Note: this method must return true unless it is absolutely clear that the
+ * contents of the Ole Document do not differ from the contents in the file
+ * on the file system.
+ */
+
+ // Get access to the persistent storage mechanism
+ long[] address = new long[1];
+ if (objIOleObject.QueryInterface(COM.IIDIPersistFile, address) != COM.S_OK)
+ return true;
+ IPersistFile permStorage = new IPersistFile(address[0]);
+ // Are the contents of the permanent storage different from the file?
+ int result = permStorage.IsDirty();
+ permStorage.Release();
+ if (result == COM.S_FALSE) return false;
+ return true;
+}
+@Override
+public boolean isFocusControl () {
+ checkWidget ();
+ long focusHwnd = OS.GetFocus();
+ if (objIOleInPlaceObject == null) return (handle == focusHwnd);
+ long[] phwnd = new long[1];
+ objIOleInPlaceObject.GetWindow(phwnd);
+ while (focusHwnd != 0) {
+ if (phwnd[0] == focusHwnd) return true;
+ focusHwnd = OS.GetParent(focusHwnd);
+ }
+ return false;
+}
+private boolean isOffice2007(boolean program) {
+ String programID = getProgramID();
+ if (programID == null) return false;
+ if (program) {
+ int lastDot = programID.lastIndexOf('.');
+ if (lastDot != -1) {
+ programID = programID.substring(0, lastDot);
+ GUID guid = getClassID(programID);
+ programID = getProgID(guid);
+ if (programID == null) return false;
+ }
+ }
+ if (programID.equals("Word.Document.12")) return true; //$NON-NLS-1$
+ if (programID.equals("Excel.Sheet.12")) return true; //$NON-NLS-1$
+ if (programID.equals("PowerPoint.Show.12")) return true; //$NON-NLS-1$
+ return false;
+}
+private int OnClose() {
+ return COM.S_OK;
+}
+private int OnDataChange(long pFormatetc, long pStgmed) {
+ return COM.S_OK;
+}
+private void onDispose(Event e) {
+ inDispose = true;
+
+ // remove listeners
+ removeListener(SWT.Dispose, listener);
+ removeListener(SWT.FocusIn, listener);
+ removeListener(SWT.FocusOut, listener);
+ removeListener(SWT.Paint, listener);
+ removeListener(SWT.Traverse, listener);
+ removeListener(SWT.KeyDown, listener);
+
+ if (state != STATE_NONE)
+ doVerb(OLE.OLEIVERB_DISCARDUNDOSTATE);
+ deactivateInPlaceClient();
+ releaseObjectInterfaces(); // Note, must release object interfaces before releasing frame
+ deleteTempStorage();
+
+ frame.removeListener(SWT.Resize, listener);
+ frame.removeListener(SWT.Move, listener);
+
+ frame.Release();
+ frame = null;
+}
+void onFocusIn(Event e) {
+ if (inDispose) return;
+ if (state != STATE_UIACTIVE) {
+ long[] ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIOleInPlaceObject, ppvObject) == COM.S_OK) {
+ IOleInPlaceObject objIOleInPlaceObject = new IOleInPlaceObject(ppvObject[0]);
+ objIOleInPlaceObject.Release();
+ doVerb(OLE.OLEIVERB_SHOW);
+ }
+ }
+ if (objIOleInPlaceObject == null) return;
+ if (isFocusControl()) return;
+ long[] phwnd = new long[1];
+ objIOleInPlaceObject.GetWindow(phwnd);
+ if (phwnd[0] == 0) return;
+ OS.SetFocus(phwnd[0]);
+}
+void onFocusOut(Event e) {
+}
+private int OnInPlaceActivate() {
+ state = STATE_INPLACEACTIVE;
+ frame.setCurrentDocument(this);
+ if (objIOleObject == null)
+ return COM.S_OK;
+ long[] ppvObject = new long[1];
+ if (objIOleObject.QueryInterface(COM.IIDIOleInPlaceObject, ppvObject) == COM.S_OK) {
+ objIOleInPlaceObject = new IOleInPlaceObject(ppvObject[0]);
+ }
+ return COM.S_OK;
+}
+private int OnInPlaceDeactivate() {
+ if (objIOleInPlaceObject != null) objIOleInPlaceObject.Release();
+ objIOleInPlaceObject = null;
+ state = STATE_RUNNING;
+ redraw();
+ Shell shell = getShell();
+ if (isFocusControl() || frame.isFocusControl()) {
+ shell.traverse(SWT.TRAVERSE_TAB_NEXT);
+ }
+ return COM.S_OK;
+}
+private int OnPosRectChange(long lprcPosRect) {
+ Point size = DPIUtil.autoScaleUp(getSize()); // To Pixels
+ setExtent(size.x, size.y);
+ return COM.S_OK;
+}
+private void onPaint(Event e) {
+ if (state == STATE_RUNNING || state == STATE_INPLACEACTIVE) {
+ SIZE size = getExtent();
+ Rectangle area = DPIUtil.autoScaleUp(getClientArea()); // To Pixels
+ RECT rect = new RECT();
+ if (getProgramID().startsWith("Excel.Sheet")) { //$NON-NLS-1$
+ rect.left = area.x; rect.right = area.x + (area.height * size.cx / size.cy);
+ rect.top = area.y; rect.bottom = area.y + area.height;
+ } else {
+ rect.left = area.x; rect.right = area.x + size.cx;
+ rect.top = area.y; rect.bottom = area.y + size.cy;
+ }
+
+ long pArea = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, RECT.sizeof);
+ OS.MoveMemory(pArea, rect, RECT.sizeof);
+ COM.OleDraw(objIUnknown.getAddress(), aspect, e.gc.handle, pArea);
+ OS.GlobalFree(pArea);
+ }
+}
+private void onResize(Event e) {
+ setBounds();
+}
+private void OnSave() {
+}
+private int OnShowWindow(int fShow) {
+ return COM.S_OK;
+}
+private int OnUIActivate() {
+ if (objIOleInPlaceObject == null) return COM.E_FAIL;
+ state = STATE_UIACTIVE;
+ long[] phwnd = new long[1];
+ if (objIOleInPlaceObject.GetWindow(phwnd) == COM.S_OK) {
+ OS.SetWindowPos(phwnd[0], OS.HWND_TOP, 0, 0, 0, 0, OS.SWP_NOSIZE | OS.SWP_NOMOVE);
+ }
+ return COM.S_OK;
+}
+int OnUIDeactivate(int fUndoable) {
+ // currently, we are ignoring the fUndoable flag
+ if (frame == null || frame.isDisposed()) return COM.S_OK;
+ state = STATE_INPLACEACTIVE;
+ frame.SetActiveObject(0,0);
+ redraw();
+ Shell shell = getShell();
+ if (isFocusControl() || frame.isFocusControl()) {
+ shell.traverse(SWT.TRAVERSE_TAB_NEXT);
+ }
+ Menu menubar = shell.getMenuBar();
+ if (menubar == null || menubar.isDisposed())
+ return COM.S_OK;
+
+ long shellHandle = shell.handle;
+ OS.SetMenu(shellHandle, menubar.handle);
+ return COM.OleSetMenuDescriptor(0, shellHandle, 0, 0, 0);
+}
+private void onTraverse(Event event) {
+ switch (event.detail) {
+ case SWT.TRAVERSE_ESCAPE:
+ case SWT.TRAVERSE_RETURN:
+ case SWT.TRAVERSE_TAB_NEXT:
+ case SWT.TRAVERSE_TAB_PREVIOUS:
+ case SWT.TRAVERSE_PAGE_NEXT:
+ case SWT.TRAVERSE_PAGE_PREVIOUS:
+ case SWT.TRAVERSE_MNEMONIC:
+ event.doit = true;
+ break;
+ }
+}
+private int OnViewChange(int dwAspect, int lindex) {
+ return COM.S_OK;
+}
+protected int QueryInterface(long riid, long ppvObject) {
+
+ if (riid == 0 || ppvObject == 0)
+ return COM.E_NOINTERFACE;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+
+ if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIOleClientSite)) {
+ OS.MoveMemory(ppvObject, new long[] {iOleClientSite.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIAdviseSink)) {
+ OS.MoveMemory(ppvObject, new long[] {iAdviseSink.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIOleInPlaceSite)) {
+ OS.MoveMemory(ppvObject, new long[] {iOleInPlaceSite.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIOleDocumentSite )) {
+ String progID = getProgramID();
+ if (!progID.startsWith("PowerPoint")) { //$NON-NLS-1$
+ OS.MoveMemory(ppvObject, new long[] {iOleDocumentSite.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ }
+ OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+/**
+ * Returns the status of the specified command. The status is any bitwise OR'd combination of
+ * SWTOLE.OLECMDF_SUPPORTED, SWTOLE.OLECMDF_ENABLED, SWTOLE.OLECMDF_LATCHED, SWTOLE.OLECMDF_NINCHED.
+ * You can query the status of a command before invoking it with OleClientSite.exec. The
+ * OLE Document or ActiveX Control must support the IOleCommandTarget to make use of this method.
+ *
+ * @param cmd the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
+ * commands
+ *
+ * @return the status of the specified command or 0 if unable to query the OLE Object; these are the
+ * OLE.OLECMDF_ values
+ */
+public int queryStatus(int cmd) {
+
+ if (objIOleCommandTarget == null) {
+ long[] address = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIOleCommandTarget, address) != COM.S_OK)
+ return 0;
+ objIOleCommandTarget = new IOleCommandTarget(address[0]);
+ }
+
+ OLECMD olecmd = new OLECMD();
+ olecmd.cmdID = cmd;
+
+ int result = objIOleCommandTarget.QueryStatus(null, 1, olecmd, 0);
+
+ if (result != COM.S_OK) return 0;
+
+ return olecmd.cmdf;
+}
+protected int Release() {
+ refCount--;
+
+ if (refCount == 0) {
+ disposeCOMInterfaces();
+ }
+ return refCount;
+}
+protected void releaseObjectInterfaces() {
+
+ if (objIOleInPlaceObject!= null)
+ objIOleInPlaceObject.Release();
+ objIOleInPlaceObject = null;
+
+ if (objIOleObject != null) {
+ objIOleObject.Close(COM.OLECLOSE_NOSAVE);
+ objIOleObject.Release();
+ }
+ objIOleObject = null;
+
+ if (objDocumentView != null){
+ objDocumentView.Release();
+ }
+ objDocumentView = null;
+
+ if (objIViewObject2 != null) {
+ objIViewObject2.SetAdvise(aspect, 0, 0);
+ objIViewObject2.Release();
+ }
+ objIViewObject2 = null;
+
+ if (objIOleCommandTarget != null)
+ objIOleCommandTarget.Release();
+ objIOleCommandTarget = null;
+
+ if (objIUnknown != null){
+ objIUnknown.Release();
+ }
+ objIUnknown = null;
+
+ if (COM.FreeUnusedLibraries) {
+ COM.CoFreeUnusedLibraries();
+ }
+}
+/**
+ * Saves the document to the specified file and includes OLE specific information if specified.
+ * This method must only be used for files that have an OLE Storage format. For example,
+ * a word file edited with Word.Document should be saved using this method because there is
+ * formating information that should be stored in the OLE specific Storage format.
+ *
+ * @param file the file to which the changes are to be saved
+ * @param includeOleInfo the flag to indicate whether OLE specific information should be saved.
+ *
+ * @return true if the save was successful
+ */
+public boolean save(File file, boolean includeOleInfo) {
+ /*
+ * Bug in Office 2007. Saving Office 2007 documents to compound file storage object
+ * causes the output file to be corrupted. The fix is to detect Office 2007 documents
+ * using the program ID and save only the content of the 'Package' stream.
+ */
+ if (isOffice2007(false)) {
+ return saveOffice2007(file);
+ }
+ if (includeOleInfo)
+ return saveToStorageFile(file);
+ return saveToTraditionalFile(file);
+}
+private boolean saveFromContents(long address, File file) {
+
+ boolean success = false;
+
+ IStream tempContents = new IStream(address);
+ tempContents.AddRef();
+
+ try {
+ FileOutputStream writer = new FileOutputStream(file);
+
+ int increment = 1024 * 4;
+ long pv = OS.CoTaskMemAlloc(increment);
+ int[] pcbWritten = new int[1];
+ while (tempContents.Read(pv, increment, pcbWritten) == COM.S_OK && pcbWritten[0] > 0) {
+ byte[] buffer = new byte[ pcbWritten[0]];
+ OS.MoveMemory(buffer, pv, pcbWritten[0]);
+ writer.write(buffer); // Note: if file does not exist, this will create the file the
+ // first time it is called
+ success = true;
+ }
+ OS.CoTaskMemFree(pv);
+
+ writer.close();
+
+ } catch (IOException err) {
+ }
+
+ tempContents.Release();
+
+ return success;
+}
+private boolean saveFromOle10Native(long address, File file) {
+
+ boolean success = false;
+
+ IStream tempContents = new IStream(address);
+ tempContents.AddRef();
+
+ // The "\1Ole10Native" stream contains a DWORD header whose value is the length
+ // of the native data that follows.
+ long pv = OS.CoTaskMemAlloc(4);
+ int[] size = new int[1];
+ int rc = tempContents.Read(pv, 4, null);
+ OS.MoveMemory(size, pv, 4);
+ OS.CoTaskMemFree(pv);
+ if (rc == COM.S_OK && size[0] > 0) {
+
+ // Read the data
+ byte[] buffer = new byte[size[0]];
+ pv = OS.CoTaskMemAlloc(size[0]);
+ rc = tempContents.Read(pv, size[0], null);
+ OS.MoveMemory(buffer, pv, size[0]);
+ OS.CoTaskMemFree(pv);
+
+ // open the file and write data into it
+ try {
+ FileOutputStream writer = new FileOutputStream(file);
+ writer.write(buffer); // Note: if file does not exist, this will create the file
+ writer.close();
+
+ success = true;
+ } catch (IOException err) {
+ }
+ }
+ tempContents.Release();
+
+ return success;
+}
+private int SaveObject() {
+
+ updateStorage();
+
+ return COM.S_OK;
+}
+private boolean saveOffice2007(File file) {
+ if (file == null || file.isDirectory()) return false;
+ if (!updateStorage()) return false;
+ boolean result = false;
+
+ /* Excel fails to open the package stream when the PersistStorage is not in hands off mode */
+ long[] ppv = new long[1];
+ IPersistStorage iPersistStorage = null;
+ if (objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv) == COM.S_OK) {
+ iPersistStorage = new IPersistStorage(ppv[0]);
+ tempStorage.AddRef();
+ iPersistStorage.HandsOffStorage();
+ }
+ long[] address = new long[1];
+ int grfMode = COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE;
+ if (tempStorage.OpenStream("Package", 0, grfMode, 0, address) == COM.S_OK) { //$NON-NLS-1$
+ result = saveFromContents(address[0], file);
+ }
+ if (iPersistStorage != null) {
+ iPersistStorage.SaveCompleted(tempStorage.getAddress());
+ tempStorage.Release();
+ iPersistStorage.Release();
+ }
+ return result;
+}
+/**
+ * Saves the document to the specified file and includes OLE specific information. This method
+ * must only be used for files that have an OLE Storage format. For example, a word file
+ * edited with Word.Document should be saved using this method because there is formating information
+ * that should be stored in the OLE specific Storage format.
+ *
+ * @param file the file to which the changes are to be saved
+ *
+ * @return true if the save was successful
+ */
+private boolean saveToStorageFile(File file) {
+ // The file will be saved using the formating of the current application - this
+ // may not be the format of the application that was originally used to create the file
+ // e.g. if an Excel file is opened in Word, the Word application will save the file in the
+ // Word format
+ // Note: if the file already exists, some applications will not overwrite the file
+ // In these cases, you should delete the file first (probably save the contents of the file in case the
+ // save fails)
+ if (file == null || file.isDirectory()) return false;
+ if (!updateStorage()) return false;
+
+ // get access to the persistent storage mechanism
+ long[] address = new long[1];
+ if (objIOleObject.QueryInterface(COM.IIDIPersistStorage, address) != COM.S_OK) return false;
+ IPersistStorage permStorage = new IPersistStorage(address[0]);
+ try {
+ address = new long[1];
+ char[] path = (file.getAbsolutePath()+"\0").toCharArray();
+ int mode = COM.STGM_TRANSACTED | COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE;
+ int result = COM.StgCreateDocfile(path, mode, 0, address); //Does an AddRef if successful
+ if (result != COM.S_OK) return false;
+ IStorage storage = new IStorage(address[0]);
+ try {
+ if (COM.OleSave(permStorage.getAddress(), storage.getAddress(), false) == COM.S_OK) {
+ if (storage.Commit(COM.STGC_DEFAULT) == COM.S_OK) {
+ return true;
+ }
+ }
+ } finally {
+ storage.Release();
+ }
+ } finally {
+ permStorage.Release();
+ }
+ return false;
+}
+/**
+ * Saves the document to the specified file. This method must be used for
+ * files that do not have an OLE Storage format. For example, a bitmap file edited with MSPaint
+ * should be saved using this method because bitmap is a standard format that does not include any
+ * OLE specific data.
+ *
+ * @param file the file to which the changes are to be saved
+ *
+ * @return true if the save was successful
+ */
+private boolean saveToTraditionalFile(File file) {
+ // Note: if the file already exists, some applications will not overwrite the file
+ // In these cases, you should delete the file first (probably save the contents of the file in case the
+ // save fails)
+ if (file == null || file.isDirectory())
+ return false;
+ if (!updateStorage())
+ return false;
+
+ long[] address = new long[1];
+ // Look for a CONTENTS stream
+ if (tempStorage.OpenStream("CONTENTS", 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) //$NON-NLS-1$
+ return saveFromContents(address[0], file);
+
+ // Look for Ole 1.0 object stream
+ if (tempStorage.OpenStream("\1Ole10Native", 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) //$NON-NLS-1$
+ return saveFromOle10Native(address[0], file);
+
+ return false;
+}
+private int Scroll(long scrollExtent) {
+ return COM.S_OK;
+}
+void setBorderSpace(RECT newBorderwidth) {
+ borderWidths = newBorderwidth;
+ // readjust size and location of client site
+ setBounds();
+}
+void setBounds() {
+ Rectangle area = DPIUtil.autoScaleUp(frame.getClientArea()); // To Pixels
+ setBounds(DPIUtil.autoScaleDown(borderWidths.left),
+ DPIUtil.autoScaleDown(borderWidths.top),
+ DPIUtil.autoScaleDown(area.width - borderWidths.left - borderWidths.right),
+ DPIUtil.autoScaleDown(area.height - borderWidths.top - borderWidths.bottom));
+ setObjectRects();
+}
+private void setExtent(int width, int height){
+ // Resize the width and height of the embedded/linked OLENatives object
+ // to the specified values.
+
+ if (objIOleObject == null || isStatic || inUpdate) return;
+ SIZE currentExtent = getExtent();
+ if (width == currentExtent.cx && height == currentExtent.cy) return;
+
+ SIZE newExtent = new SIZE();
+ newExtent.cx = width; newExtent.cy = height;
+ newExtent = xFormPixelsToHimetric(newExtent);
+
+ // Get the server running first, then do a SetExtent, then show it
+ boolean alreadyRunning = COM.OleIsRunning(objIOleObject.getAddress());
+ if (!alreadyRunning)
+ COM.OleRun(objIOleObject.getAddress());
+
+ if (objIOleObject.SetExtent(aspect, newExtent) == COM.S_OK){
+ inUpdate = true;
+ objIOleObject.Update();
+ inUpdate = false;
+ if (!alreadyRunning)
+ // Close server if it wasn't already running upon entering this method.
+ objIOleObject.Close(COM.OLECLOSE_SAVEIFDIRTY);
+ }
+}
+/**
+ * The indent value is no longer being used by the client site.
+ *
+ * @param newIndent the rectangle representing the indent amount
+ */
+public void setIndent(Rectangle newIndent) {
+ indent = new RECT();
+ indent.left = newIndent.x;
+ indent.right = newIndent.width;
+ indent.top = newIndent.y;
+ indent.bottom = newIndent.height;
+}
+private void setObjectRects() {
+ if (objIOleInPlaceObject == null) return;
+ // size the object to fill the available space
+ // leave a border
+ RECT rect = getRect();
+ objIOleInPlaceObject.SetObjectRects(rect, rect);
+}
+
+private int ShowObject() {
+ /* Tells the container to position the object so it is visible to
+ * the user. This method ensures that the container itself is
+ * visible and not minimized.
+ */
+ setBounds();
+ return COM.S_OK;
+}
+/**
+ * Displays a dialog with the property information for this OLE Object. The OLE Document or
+ * ActiveX Control must support the ISpecifyPropertyPages interface.
+ *
+ * @param title the name that will appear in the titlebar of the dialog
+ */
+public void showProperties(String title) {
+
+ // Get the Property Page information from the OLE Object
+ long[] ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDISpecifyPropertyPages, ppvObject) != COM.S_OK) return;
+ ISpecifyPropertyPages objISPP = new ISpecifyPropertyPages(ppvObject[0]);
+ CAUUID caGUID = new CAUUID();
+ int result = objISPP.GetPages(caGUID);
+ objISPP.Release();
+ if (result != COM.S_OK) return;
+
+ // create a frame in which to display the pages
+ char[] chTitle = null;
+ if (title != null) {
+ chTitle = new char[title.length()];
+ title.getChars(0, title.length(), chTitle, 0);
+ }
+ result = COM.OleCreatePropertyFrame(frame.handle, 10, 10, chTitle, 1, new long[] {objIUnknown.getAddress()}, caGUID.cElems, caGUID.pElems, COM.LOCALE_USER_DEFAULT, 0, 0);
+
+ // free the property page information
+ OS.CoTaskMemFree(caGUID.pElems);
+}
+private boolean updateStorage() {
+
+ if (tempStorage == null) return false;
+
+ long[] ppv = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv) != COM.S_OK) return false;
+ IPersistStorage iPersistStorage = new IPersistStorage(ppv[0]);
+
+ int result = COM.OleSave(iPersistStorage.getAddress(), tempStorage.getAddress(), true);
+
+ if (result != COM.S_OK){
+ // OleSave will fail for static objects, so do what OleSave does.
+ COM.WriteClassStg(tempStorage.getAddress(), objClsid);
+ result = iPersistStorage.Save(tempStorage.getAddress(), true);
+ }
+
+ tempStorage.Commit(COM.STGC_DEFAULT);
+ result = iPersistStorage.SaveCompleted(0);
+ iPersistStorage.Release();
+
+ return true;
+}
+private SIZE xFormHimetricToPixels(SIZE aSize) {
+ // Return a new Size which is the pixel transformation of a
+ // size in HIMETRIC units.
+
+ long hDC = OS.GetDC(0);
+ int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x
+ int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y
+ OS.ReleaseDC(0, hDC);
+ int cx = Compatibility.round(aSize.cx * xppi, 2540); // 2540 HIMETRIC units per inch
+ int cy = Compatibility.round(aSize.cy * yppi, 2540);
+ SIZE size = new SIZE();
+ size.cx = cx;
+ size.cy = cy;
+ return size;
+}
+private SIZE xFormPixelsToHimetric(SIZE aSize) {
+ // Return a new size which is the HIMETRIC transformation of a
+ // size in pixel units.
+
+ long hDC = OS.GetDC(0);
+ int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x
+ int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y
+ OS.ReleaseDC(0, hDC);
+ int cx = Compatibility.round(aSize.cx * 2540, xppi); // 2540 HIMETRIC units per inch
+ int cy = Compatibility.round(aSize.cy * 2540, yppi);
+ SIZE size = new SIZE();
+ size.cx = cx;
+ size.cy = cy;
+ return size;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleControlSite.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleControlSite.java
new file mode 100644
index 000000000..3d3d0da62
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleControlSite.java
@@ -0,0 +1,1018 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * OleControlSite provides a site to manage an embedded ActiveX Control within a container.
+ *
+ *
+ *
+ *
+ * Composite
,
+ * it does not make sense to add Control
children to it,
+ * or set a layout on it.
+ *
+ *
+ *
+ * @see OLE and ActiveX snippets
+ * @see SWT Examples: OLEExample, OleWebBrowser
+ */
+public class OleControlSite extends OleClientSite
+{
+ // interfaces for this container
+ private COMObject iOleControlSite;
+ private COMObject iDispatch;
+
+ // supporting Property Change attributes
+ private OlePropertyChangeSink olePropertyChangeSink;
+
+ // supporting Event Sink attributes
+ private OleEventSink[] oleEventSink = new OleEventSink[0];
+ private GUID[] oleEventSinkGUID = new GUID[0];
+ private long[] oleEventSinkIUnknown = new long[0];
+
+ // supporting information for the Control COM object
+ private CONTROLINFO currentControlInfo;
+ private int[] sitePropertyIds = new int[0];
+ private Variant[] sitePropertyValues = new Variant[0];
+
+ private Font font;
+
+ // work around for IE destroying the caret
+ static int SWT_RESTORECARET;
+
+ static final String SHELL_PROG_ID = "Shell.Explorer"; //$NON-NLS-1$
+
+/**
+ * Create an OleControlSite child widget using the OLE Document type associated with the
+ * specified file. The OLE Document type is determined either through header information in the file
+ * or through a Registry entry for the file extension. Use style bits to select a particular look
+ * or set of properties.
+ *
+ * @param parent a composite widget; must be an OleFrame
+ * @param style the bitwise OR'ing of widget styles
+ * @param file the file that is to be opened in this OLE Document
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.5
+ */
+public OleControlSite(Composite parent, int style, File file) {
+ super(parent, style, file);
+
+ // Init site properties
+ setSiteProperty(COM.DISPID_AMBIENT_USERMODE, new Variant(true));
+ setSiteProperty(COM.DISPID_AMBIENT_UIDEAD, new Variant(false));
+}
+/**
+ * Create an OleControlSite child widget using style bits
+ * to select a particular look or set of properties.
+ *
+ * @param parent a composite widget; must be an OleFrame
+ * @param style the bitwise OR'ing of widget styles
+ * @param progId the unique program identifier which has been registered for this ActiveX Control;
+ * the value of the ProgID key or the value of the VersionIndependentProgID key specified
+ * in the registry for this Control (for example, the VersionIndependentProgID for
+ * Internet Explorer is Shell.Explorer)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public OleControlSite(Composite parent, int style, String progId) {
+ super(parent, style);
+ try {
+
+ // check for licensing
+ appClsid = getClassID(progId);
+ if (appClsid == null) OLE.error(OLE.ERROR_INVALID_CLASSID);
+
+ long licinfo = getLicenseInfo(appClsid);
+ if (licinfo == 0) {
+
+ // Open a storage object
+ tempStorage = createTempStorage();
+
+ // Create ole object with storage object
+ long[] address = new long[1];
+ /*
+ * Bug in ICA Client 2.7. The creation of the IOleObject fails if the client
+ * site is provided to OleCreate(). The fix is to detect that the program
+ * id is an ICA Client and do not pass a client site to OleCreate().
+ * IOleObject.SetClientSite() is called later on.
+ */
+ long clientSite = isICAClient() ? 0 : iOleClientSite.getAddress();
+ int result = COM.OleCreate(appClsid, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, clientSite, tempStorage.getAddress(), address);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
+
+ objIUnknown = new IUnknown(address[0]);
+
+ } else {
+ // Prepare the ClassFactory
+ long[] ppvObject = new long[1];
+ try {
+ int result = COM.CoGetClassObject(appClsid, COM.CLSCTX_INPROC_HANDLER | COM.CLSCTX_INPROC_SERVER, 0, COM.IIDIClassFactory2, ppvObject);
+ if (result != COM.S_OK) {
+ OLE.error(OLE.ERROR_CANNOT_ACCESS_CLASSFACTORY, result);
+ }
+ IClassFactory2 classFactory = new IClassFactory2(ppvObject[0]);
+ // Create Com Object
+ ppvObject = new long[1];
+ result = classFactory.CreateInstanceLic(0, 0, COM.IIDIUnknown, licinfo, ppvObject);
+ classFactory.Release();
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CREATE_LICENSED_OBJECT, result);
+ } finally {
+ COM.SysFreeString(licinfo);
+ }
+
+ objIUnknown = new IUnknown(ppvObject[0]);
+
+ // Prepare a storage medium
+ ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppvObject) == COM.S_OK) {
+ IPersistStorage persist = new IPersistStorage(ppvObject[0]);
+ tempStorage = createTempStorage();
+ persist.InitNew(tempStorage.getAddress());
+ persist.Release();
+ }
+ }
+
+ // Init sinks
+ addObjectReferences();
+
+ // Init site properties
+ setSiteProperty(COM.DISPID_AMBIENT_USERMODE, new Variant(true));
+ setSiteProperty(COM.DISPID_AMBIENT_UIDEAD, new Variant(false));
+
+ if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state= STATE_RUNNING;
+
+ } catch (SWTError e) {
+ dispose();
+ disposeCOMInterfaces();
+ throw e;
+ }
+}
+/**
+ * Create an OleClientSite child widget to edit the specified file using the specified OLE Document
+ * application. Use style bits to select a particular look or set of properties.
+ * OleClientSite
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ * @exception SWTException
+ *
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ *
+ * @since 3.5
+ */
+public OleControlSite(Composite parent, int style, String progId, File file) {
+ super(parent, style, progId, file);
+
+ // Init site properties
+ setSiteProperty(COM.DISPID_AMBIENT_USERMODE, new Variant(true));
+ setSiteProperty(COM.DISPID_AMBIENT_UIDEAD, new Variant(false));
+}
+/**
+ * Adds the listener to receive events.
+ *
+ * @param eventID the id of the event
+ *
+ * @param listener the listener
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public void addEventListener(int eventID, OleListener listener) {
+ if (listener == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
+ GUID riid = getDefaultEventSinkGUID(objIUnknown);
+ if (riid != null) {
+ addEventListener(objIUnknown.getAddress(), riid, eventID, listener);
+ }
+
+}
+static GUID getDefaultEventSinkGUID(IUnknown unknown) {
+ // get Event Sink I/F from IProvideClassInfo2
+ long[] ppvObject = new long[1];
+ if (unknown.QueryInterface(COM.IIDIProvideClassInfo2, ppvObject) == COM.S_OK) {
+ IProvideClassInfo2 pci2 = new IProvideClassInfo2(ppvObject[0]);
+ GUID riid = new GUID();
+ int result = pci2.GetGUID(COM.GUIDKIND_DEFAULT_SOURCE_DISP_IID, riid);
+ pci2.Release();
+ if (result == COM.S_OK) return riid;
+ }
+
+ // get Event Sink I/F from IProvideClassInfo
+ if (unknown.QueryInterface(COM.IIDIProvideClassInfo, ppvObject) == COM.S_OK) {
+ IProvideClassInfo pci = new IProvideClassInfo(ppvObject[0]);
+ long[] ppTI = new long[1];
+ long[] ppEI = new long[1];
+ int result = pci.GetClassInfo(ppTI);
+ pci.Release();
+
+ if (result == COM.S_OK && ppTI[0] != 0) {
+ ITypeInfo classInfo = new ITypeInfo(ppTI[0]);
+ long[] ppTypeAttr = new long[1];
+ result = classInfo.GetTypeAttr(ppTypeAttr);
+ if (result == COM.S_OK && ppTypeAttr[0] != 0) {
+ TYPEATTR typeAttribute = new TYPEATTR();
+ COM.MoveMemory(typeAttribute, ppTypeAttr[0], TYPEATTR.sizeof);
+ classInfo.ReleaseTypeAttr(ppTypeAttr[0]);
+ int implMask = COM.IMPLTYPEFLAG_FDEFAULT | COM.IMPLTYPEFLAG_FSOURCE | COM.IMPLTYPEFLAG_FRESTRICTED;
+ int implBits = COM.IMPLTYPEFLAG_FDEFAULT | COM.IMPLTYPEFLAG_FSOURCE;
+
+ for (int i = 0; i < typeAttribute.cImplTypes; i++) {
+ int[] pImplTypeFlags = new int[1];
+ if (classInfo.GetImplTypeFlags(i, pImplTypeFlags) == COM.S_OK) {
+ if ((pImplTypeFlags[0] & implMask) == implBits) {
+ int[] pRefType = new int[1];
+ if (classInfo.GetRefTypeOfImplType(i, pRefType) == COM.S_OK) {
+ classInfo.GetRefTypeInfo(pRefType[0], ppEI);
+ }
+ }
+ }
+ }
+ }
+ classInfo.Release();
+
+ if (ppEI[0] != 0) {
+ ITypeInfo eventInfo = new ITypeInfo(ppEI[0]);
+ ppTypeAttr = new long[1];
+ result = eventInfo.GetTypeAttr(ppTypeAttr);
+ GUID riid = null;
+ if (result == COM.S_OK && ppTypeAttr[0] != 0) {
+ riid = new GUID();
+ COM.MoveMemory(riid, ppTypeAttr[0], GUID.sizeof);
+ eventInfo.ReleaseTypeAttr(ppTypeAttr[0]);
+ }
+ eventInfo.Release();
+ return riid;
+ }
+ }
+ }
+ return null;
+}
+
+/**
+ * Adds the listener to receive events.
+ *
+ * @since 2.0
+ *
+ * @param automation the automation object that provides the event notification
+ * @param eventID the id of the event
+ * @param listener the listener
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public void addEventListener(OleAutomation automation, int eventID, OleListener listener) {
+ if (listener == null || automation == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
+ long address = automation.getAddress();
+ IUnknown unknown = new IUnknown(address);
+ GUID riid = getDefaultEventSinkGUID(unknown);
+ if (riid != null) {
+ addEventListener(address, riid, eventID, listener);
+ }
+
+}
+/**
+ * Adds the listener to receive events.
+ *
+ * @since 3.2
+ *
+ * @param automation the automation object that provides the event notification
+ * @param eventSinkId the GUID of the event sink
+ * @param eventID the id of the event
+ * @param listener the listener
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public void addEventListener(OleAutomation automation, String eventSinkId, int eventID, OleListener listener) {
+ if (listener == null || automation == null || eventSinkId == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
+ long address = automation.getAddress();
+ if (address == 0) return;
+ char[] buffer = (eventSinkId +"\0").toCharArray();
+ GUID guid = new GUID();
+ if (COM.IIDFromString(buffer, guid) != COM.S_OK) return;
+ addEventListener(address, guid, eventID, listener);
+}
+
+void addEventListener(long iunknown, GUID guid, int eventID, OleListener listener) {
+ if (listener == null || iunknown == 0 || guid == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
+ // have we connected to this kind of event sink before?
+ int index = -1;
+ for (int i = 0; i < oleEventSinkGUID.length; i++) {
+ if (COM.IsEqualGUID(oleEventSinkGUID[i], guid)) {
+ if (iunknown == oleEventSinkIUnknown[i]) {
+ index = i;
+ break;
+ }
+ }
+ }
+ if (index != -1) {
+ oleEventSink[index].addListener(eventID, listener);
+ } else {
+ int oldLength = oleEventSink.length;
+ OleEventSink[] newOleEventSink = new OleEventSink[oldLength + 1];
+ GUID[] newOleEventSinkGUID = new GUID[oldLength + 1];
+ long[] newOleEventSinkIUnknown = new long[oldLength + 1];
+ System.arraycopy(oleEventSink, 0, newOleEventSink, 0, oldLength);
+ System.arraycopy(oleEventSinkGUID, 0, newOleEventSinkGUID, 0, oldLength);
+ System.arraycopy(oleEventSinkIUnknown, 0, newOleEventSinkIUnknown, 0, oldLength);
+ oleEventSink = newOleEventSink;
+ oleEventSinkGUID = newOleEventSinkGUID;
+ oleEventSinkIUnknown = newOleEventSinkIUnknown;
+
+ oleEventSink[oldLength] = new OleEventSink(this, iunknown, guid);
+ oleEventSinkGUID[oldLength] = guid;
+ oleEventSinkIUnknown[oldLength] = iunknown;
+ oleEventSink[oldLength].AddRef();
+ oleEventSink[oldLength].connect();
+ oleEventSink[oldLength].addListener(eventID, listener);
+
+ }
+}
+@Override
+protected void addObjectReferences() {
+
+ super.addObjectReferences();
+
+ // Get property change notification from control
+ connectPropertyChangeSink();
+
+ // Get access to the Control object
+ long[] ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIOleControl, ppvObject) == COM.S_OK) {
+ IOleControl objIOleControl = new IOleControl(ppvObject[0]);
+ // ask the control for its info in case users
+ // need to act on it
+ currentControlInfo = new CONTROLINFO();
+ objIOleControl.GetControlInfo(currentControlInfo);
+ objIOleControl.Release();
+ }
+}
+/**
+ * Adds the listener to receive events.
+ *
+ * @param propertyID the identifier of the property
+ * @param listener the listener
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public void addPropertyListener(int propertyID, OleListener listener) {
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ olePropertyChangeSink.addListener(propertyID, listener);
+}
+
+private void connectPropertyChangeSink() {
+ olePropertyChangeSink = new OlePropertyChangeSink(this);
+ olePropertyChangeSink.AddRef();
+ olePropertyChangeSink.connect(objIUnknown);
+}
+@Override
+protected void createCOMInterfaces () {
+ super.createCOMInterfaces();
+
+ // register each of the interfaces that this object implements
+ iOleControlSite = new COMObject(new int[]{2, 0, 0, 0, 1, 1, 3, 2, 1, 0}){
+ @Override
+ public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ @Override
+ public long method3(long[] args) {return OnControlInfoChanged();}
+ // method4 LockInPlaceActive - not implemented
+ // method5 GetExtendedControl - not implemented
+ // method6 TransformCoords - not implemented
+ // method7 Translate Accelerator - not implemented
+ @Override
+ public long method8(long[] args) {return OnFocus((int)args[0]);}
+ // method9 ShowPropertyFrame - not implemented
+ };
+
+ iDispatch = new COMObject(new int[]{2, 0, 0, 1, 3, 5, 8}){
+ @Override
+ public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ // method3 GetTypeInfoCount - not implemented
+ // method4 GetTypeInfo - not implemented
+ // method5 GetIDsOfNames - not implemented
+ @Override
+ public long method6(long[] args) {return Invoke((int)args[0], args[1], (int)args[2], (int)args[3], args[4], args[5], args[6], args[7]);}
+ };
+}
+private void disconnectEventSinks() {
+
+ for (int i = 0; i < oleEventSink.length; i++) {
+ OleEventSink sink = oleEventSink[i];
+ sink.disconnect();
+ sink.Release();
+ }
+ oleEventSink = new OleEventSink[0];
+ oleEventSinkGUID = new GUID[0];
+ oleEventSinkIUnknown = new long[0];
+}
+private void disconnectPropertyChangeSink() {
+
+ if (olePropertyChangeSink != null) {
+ olePropertyChangeSink.disconnect(objIUnknown);
+ olePropertyChangeSink.Release();
+ }
+ olePropertyChangeSink = null;
+}
+@Override
+protected void disposeCOMInterfaces() {
+ super.disposeCOMInterfaces();
+
+ if (iOleControlSite != null)
+ iOleControlSite.dispose();
+ iOleControlSite = null;
+
+ if (iDispatch != null)
+ iDispatch.dispose();
+ iDispatch = null;
+}
+@Override
+public Color getBackground () {
+
+ if (objIUnknown != null) {
+ // !! We are getting the OLE_COLOR - should we change this to the COLORREF value?
+ OleAutomation oleObject= new OleAutomation(this);
+ Variant varBackColor = oleObject.getProperty(COM.DISPID_BACKCOLOR);
+ oleObject.dispose();
+
+ if (varBackColor != null){
+ int[] colorRef = new int[1];
+ if (COM.OleTranslateColor(varBackColor.getInt(), 0, colorRef) == COM.S_OK)
+ return Color.win32_new(getDisplay(), colorRef[0]);
+ }
+ }
+
+ return super.getBackground();
+}
+@Override
+public Font getFont () {
+ if (font != null && !font.isDisposed()) return font;
+ if (objIUnknown != null) {
+ OleAutomation oleObject= new OleAutomation(this);
+ Variant varDispFont = oleObject.getProperty(COM.DISPID_FONT);
+ oleObject.dispose();
+
+ if (varDispFont != null){
+ OleAutomation iDispFont = varDispFont.getAutomation();
+ Variant lfFaceName = iDispFont.getProperty(COM.DISPID_FONT_NAME);
+ Variant lfHeight = iDispFont.getProperty(COM.DISPID_FONT_SIZE);
+ Variant lfItalic = iDispFont.getProperty(COM.DISPID_FONT_ITALIC);
+ //Variant lfCharSet = iDispFont.getProperty(COM.DISPID_FONT_CHARSET);
+ Variant lfBold = iDispFont.getProperty(COM.DISPID_FONT_BOLD);
+ iDispFont.dispose();
+
+ if (lfFaceName != null &&
+ lfHeight != null &&
+ lfItalic != null &&
+ lfBold != null){
+ int style = 3 * lfBold.getInt() + 2 * lfItalic.getInt();
+ font = new Font(getShell().getDisplay(), lfFaceName.getString(), lfHeight.getInt(), style);
+ return font;
+ }
+ }
+ }
+
+ return super.getFont();
+}
+@Override
+public Color getForeground () {
+
+ if (objIUnknown != null) {
+ // !! We are getting the OLE_COLOR - should we change this to the COLORREF value?
+ OleAutomation oleObject= new OleAutomation(this);
+ Variant varForeColor = oleObject.getProperty(COM.DISPID_FORECOLOR);
+ oleObject.dispose();
+
+ if (varForeColor != null){
+ int[] colorRef = new int[1];
+ if (COM.OleTranslateColor(varForeColor.getInt(), 0, colorRef) == COM.S_OK)
+ return Color.win32_new(getDisplay(), colorRef[0]);
+ }
+ }
+
+ return super.getForeground();
+}
+protected long getLicenseInfo(GUID clsid) {
+ long[] ppvObject = new long[1];
+ if (COM.CoGetClassObject(clsid, COM.CLSCTX_INPROC_HANDLER
+ | COM.CLSCTX_INPROC_SERVER, 0, COM.IIDIClassFactory, ppvObject) != COM.S_OK) {
+ return 0;
+ }
+ long result = 0;
+ IUnknown unknown = new IUnknown(ppvObject[0]);
+ if (unknown.QueryInterface(COM.IIDIClassFactory2, ppvObject) == COM.S_OK) {
+ IClassFactory2 classFactory = new IClassFactory2(ppvObject[0]);
+ LICINFO licinfo = new LICINFO();
+ if (classFactory.GetLicInfo(licinfo) == COM.S_OK) {
+ long[] pBstrKey = new long[1];
+ if (licinfo != null && licinfo.fRuntimeKeyAvail) {
+ if (classFactory.RequestLicKey(0, pBstrKey) == COM.S_OK) {
+ result = pBstrKey[0];
+ }
+ }
+ }
+ classFactory.Release();
+ }
+ unknown.Release();
+ return result;
+}
+/**
+ *
+ * Get the control site property specified by the dispIdMember, or
+ * null
if the dispId is not recognised.
+ *
+ * @param dispId the dispId
+ *
+ * @return the property value or null
+ *
+ * @since 2.1
+ */
+public Variant getSiteProperty(int dispId){
+ for (int i = 0; i < sitePropertyIds.length; i++) {
+ if (sitePropertyIds[i] == dispId) {
+ return sitePropertyValues[i];
+ }
+ }
+ return null;
+}
+@Override
+protected int GetWindow(long phwnd) {
+
+ if (phwnd == 0)
+ return COM.E_INVALIDARG;
+ if (frame == null) {
+ OS.MoveMemory(phwnd, new long[] {0}, C.PTR_SIZEOF);
+ return COM.E_NOTIMPL;
+ }
+
+ // Copy the Window's handle into the memory passed in
+ OS.MoveMemory(phwnd, new long[] {handle}, C.PTR_SIZEOF);
+ return COM.S_OK;
+}
+private int Invoke(int dispIdMember, long riid, int lcid, int dwFlags, long pDispParams, long pVarResult, long pExcepInfo, long pArgErr) {
+ if (pVarResult == 0 || dwFlags != COM.DISPATCH_PROPERTYGET) {
+ if (pExcepInfo != 0) OS.MoveMemory(pExcepInfo, new long [] {0}, C.PTR_SIZEOF);
+ if (pArgErr != 0) OS.MoveMemory(pArgErr, new int[] {0}, 4);
+ return COM.DISP_E_MEMBERNOTFOUND;
+ }
+ Variant result = getSiteProperty(dispIdMember);
+ if (result != null) {
+ if (pVarResult != 0) result.getData(pVarResult);
+ return COM.S_OK;
+ }
+ switch (dispIdMember) {
+ // indicate a false result
+ case COM.DISPID_AMBIENT_SUPPORTSMNEMONICS :
+ case COM.DISPID_AMBIENT_SHOWGRABHANDLES :
+ case COM.DISPID_AMBIENT_SHOWHATCHING :
+ if (pVarResult != 0) OS.MoveMemory(pVarResult, new long [] {0}, C.PTR_SIZEOF);
+ if (pExcepInfo != 0) OS.MoveMemory(pExcepInfo, new long [] {0}, C.PTR_SIZEOF);
+ if (pArgErr != 0) OS.MoveMemory(pArgErr, new int[] {0}, 4);
+ return COM.S_FALSE;
+
+ // not implemented
+ case COM.DISPID_AMBIENT_OFFLINEIFNOTCONNECTED :
+ case COM.DISPID_AMBIENT_BACKCOLOR :
+ case COM.DISPID_AMBIENT_FORECOLOR :
+ case COM.DISPID_AMBIENT_FONT :
+ case COM.DISPID_AMBIENT_LOCALEID :
+ case COM.DISPID_AMBIENT_SILENT :
+ case COM.DISPID_AMBIENT_MESSAGEREFLECT :
+ if (pVarResult != 0) OS.MoveMemory(pVarResult, new long [] {0}, C.PTR_SIZEOF);
+ if (pExcepInfo != 0) OS.MoveMemory(pExcepInfo, new long [] {0}, C.PTR_SIZEOF);
+ if (pArgErr != 0) OS.MoveMemory(pArgErr, new int[] {0}, 4);
+ return COM.E_NOTIMPL;
+
+ default :
+ if (pVarResult != 0) OS.MoveMemory(pVarResult, new long [] {0}, C.PTR_SIZEOF);
+ if (pExcepInfo != 0) OS.MoveMemory(pExcepInfo,new long [] {0}, C.PTR_SIZEOF);
+ if (pArgErr != 0) OS.MoveMemory(pArgErr, new int[] {0}, 4);
+ return COM.DISP_E_MEMBERNOTFOUND;
+ }
+}
+private int OnControlInfoChanged() {
+ long[] ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIOleControl, ppvObject) == COM.S_OK) {
+ IOleControl objIOleControl = new IOleControl(ppvObject[0]);
+ // ask the control for its info in case users
+ // need to act on it
+ currentControlInfo = new CONTROLINFO();
+ objIOleControl.GetControlInfo(currentControlInfo);
+ objIOleControl.Release();
+ }
+ return COM.S_OK;
+}
+@Override
+protected int OnUIDeactivate(int fUndoable) {
+ return super.OnUIDeactivate(fUndoable);
+}
+@Override
+void onFocusIn(Event e) {
+ String progID = getProgramID();
+ if (progID == null) return;
+ if (!progID.startsWith(SHELL_PROG_ID)) {
+ super.onFocusIn(e);
+ return;
+ }
+ if (objIOleInPlaceObject == null) return;
+ if (!isActivated) doVerb(OLE.OLEIVERB_UIACTIVATE);
+ if (isFocusControl()) return;
+ long[] phwnd = new long[1];
+ objIOleInPlaceObject.GetWindow(phwnd);
+ if (phwnd[0] == 0) return;
+ OS.SetFocus(phwnd[0]);
+}
+@Override
+void onFocusOut(Event e) {
+ if (objIOleInPlaceObject == null) return;
+ String progID = getProgramID();
+ if (progID == null) return;
+ if (!progID.startsWith(SHELL_PROG_ID)) {
+ super.onFocusOut(e);
+ return;
+ }
+
+ /*
+ * FocusOut is received when focus is reassigned between handles within
+ * our site. In such cases the site should not be UIDeactivated.
+ */
+ if (isFocusControl()) return;
+
+ /*
+ * Bug in Windows. When IE7 loses focus and UIDeactivate()
+ * is called, IE destroys the caret even though it is
+ * no longer owned by IE. If focus has moved to a control
+ * that shows a caret then the caret disappears. The fix
+ * is to detect this case and restore the caret.
+ */
+ int threadId = OS.GetCurrentThreadId();
+ GUITHREADINFO lpgui1 = new GUITHREADINFO();
+ lpgui1.cbSize = GUITHREADINFO.sizeof;
+ OS.GetGUIThreadInfo(threadId, lpgui1);
+ objIOleInPlaceObject.UIDeactivate();
+ if (SWT_RESTORECARET == 0) {
+ SWT_RESTORECARET = OS.RegisterWindowMessage (new TCHAR (0, "SWT_RESTORECARET", true));
+ }
+ if (lpgui1.hwndCaret != 0) {
+ GUITHREADINFO lpgui2 = new GUITHREADINFO();
+ lpgui2.cbSize = GUITHREADINFO.sizeof;
+ OS.GetGUIThreadInfo(threadId, lpgui2);
+ if (lpgui2.hwndCaret == 0 && lpgui1.hwndCaret == OS.GetFocus()) {
+ /*
+ * If the caret was not restored by SWT, put it back using
+ * the information from GUITHREADINFO. Note that this will
+ * not be correct when the caret has a bitmap. There is no
+ * API to query the bitmap that the caret is using.
+ */
+ if (OS.SendMessage (lpgui1.hwndCaret, SWT_RESTORECARET, 0, 0) == 0) {
+ int width = lpgui1.right - lpgui1.left;
+ int height = lpgui1.bottom - lpgui1.top;
+ OS.CreateCaret (lpgui1.hwndCaret, 0, width, height);
+ OS.SetCaretPos (lpgui1.left, lpgui1.top);
+ OS.ShowCaret (lpgui1.hwndCaret);
+ }
+ }
+ } else if (lpgui1.hwndFocus != 0 && lpgui1.hwndFocus == OS.GetFocus()) {
+ OS.SendMessage (lpgui1.hwndFocus, SWT_RESTORECARET, 0, 0);
+ }
+}
+private int OnFocus(int fGotFocus) {
+ return COM.S_OK;
+}
+@Override
+protected int QueryInterface(long riid, long ppvObject) {
+ int result = super.QueryInterface(riid, ppvObject);
+ if (result == COM.S_OK)
+ return result;
+ if (riid == 0 || ppvObject == 0)
+ return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+ if (COM.IsEqualGUID(guid, COM.IIDIOleControlSite)) {
+ OS.MoveMemory(ppvObject, new long[] {iOleControlSite.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIDispatch)) {
+ OS.MoveMemory(ppvObject, new long[] {iDispatch.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+@Override
+protected int Release() {
+ int result = super.Release();
+ if (result == 0) {
+ for (int i = 0; i < sitePropertyIds.length; i++) {
+ sitePropertyValues[i].dispose();
+ }
+ sitePropertyIds = new int[0];
+ sitePropertyValues = new Variant[0];
+ }
+ return result;
+}
+@Override
+protected void releaseObjectInterfaces() {
+
+ disconnectEventSinks();
+
+ disconnectPropertyChangeSink();
+
+ super.releaseObjectInterfaces();
+}
+/**
+ * Removes the listener.
+ *
+ * @param eventID the event identifier
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public void removeEventListener(int eventID, OleListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+
+ GUID riid = getDefaultEventSinkGUID(objIUnknown);
+ if (riid != null) {
+ removeEventListener(objIUnknown.getAddress(), riid, eventID, listener);
+ }
+}
+/**
+ * Removes the listener.
+ *
+ * @since 2.0
+ * @deprecated - use OleControlSite.removeEventListener(OleAutomation, int, OleListener)
+ *
+ * @param automation the automation object that provides the event notification
+ *
+ * @param guid the identifier of the events COM interface
+ *
+ * @param eventID the event identifier
+ *
+ * @param listener the listener
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+@Deprecated
+public void removeEventListener(OleAutomation automation, GUID guid, int eventID, OleListener listener) {
+ checkWidget();
+ if (automation == null || listener == null || guid == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ removeEventListener(automation.getAddress(), guid, eventID, listener);
+}
+/**
+ * Removes the listener.
+ *
+ * @param automation the automation object that provides the event notification
+ * @param eventID the event identifier
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ *
+ * @since 2.0
+ */
+public void removeEventListener(OleAutomation automation, int eventID, OleListener listener) {
+ checkWidget();
+ if (automation == null || listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ long address = automation.getAddress();
+ IUnknown unknown = new IUnknown(address);
+ GUID riid = getDefaultEventSinkGUID(unknown);
+ if (riid != null) {
+ removeEventListener(address, riid, eventID, listener);
+ }
+}
+void removeEventListener(long iunknown, GUID guid, int eventID, OleListener listener) {
+ if (listener == null || guid == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i = 0; i < oleEventSink.length; i++) {
+ if (COM.IsEqualGUID(oleEventSinkGUID[i], guid)) {
+ if (iunknown == oleEventSinkIUnknown[i]) {
+ oleEventSink[i].removeListener(eventID, listener);
+ if (!oleEventSink[i].hasListeners()) {
+ //free resources associated with event sink
+ oleEventSink[i].disconnect();
+ oleEventSink[i].Release();
+ int oldLength = oleEventSink.length;
+ if (oldLength == 1) {
+ oleEventSink = new OleEventSink[0];
+ oleEventSinkGUID = new GUID[0];
+ oleEventSinkIUnknown = new long[0];
+ } else {
+ OleEventSink[] newOleEventSink = new OleEventSink[oldLength - 1];
+ System.arraycopy(oleEventSink, 0, newOleEventSink, 0, i);
+ System.arraycopy(oleEventSink, i + 1, newOleEventSink, i, oldLength - i - 1);
+ oleEventSink = newOleEventSink;
+
+ GUID[] newOleEventSinkGUID = new GUID[oldLength - 1];
+ System.arraycopy(oleEventSinkGUID, 0, newOleEventSinkGUID, 0, i);
+ System.arraycopy(oleEventSinkGUID, i + 1, newOleEventSinkGUID, i, oldLength - i - 1);
+ oleEventSinkGUID = newOleEventSinkGUID;
+
+ long[] newOleEventSinkIUnknown = new long[oldLength - 1];
+ System.arraycopy(oleEventSinkIUnknown, 0, newOleEventSinkIUnknown, 0, i);
+ System.arraycopy(oleEventSinkIUnknown, i + 1, newOleEventSinkIUnknown, i, oldLength - i - 1);
+ oleEventSinkIUnknown = newOleEventSinkIUnknown;
+ }
+ }
+ return;
+ }
+ }
+ }
+}
+/**
+ * Removes the listener.
+ *
+ * @param propertyID the identifier of the property
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public void removePropertyListener(int propertyID, OleListener listener) {
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ olePropertyChangeSink.removeListener(propertyID, listener);
+}
+@Override
+public void setBackground (Color color) {
+
+ super.setBackground(color);
+
+ //set the background of the ActiveX Control
+ if (objIUnknown != null) {
+ OleAutomation oleObject= new OleAutomation(this);
+ oleObject.setProperty(COM.DISPID_BACKCOLOR, new Variant(color.handle));
+ oleObject.dispose();
+ }
+}
+@Override
+public void setFont (Font font) {
+
+ super.setFont(font);
+
+ //set the font of the ActiveX Control
+ if (objIUnknown != null) {
+
+ OleAutomation oleObject= new OleAutomation(this);
+ Variant varDispFont = oleObject.getProperty(COM.DISPID_FONT);
+ oleObject.dispose();
+
+ if (varDispFont != null){
+ OleAutomation iDispFont = varDispFont.getAutomation();
+ FontData[] fdata = font.getFontData();
+ iDispFont.setProperty(COM.DISPID_FONT_NAME, new Variant(fdata[0].getName()));
+ iDispFont.setProperty(COM.DISPID_FONT_SIZE, new Variant(fdata[0].getHeight()));
+ iDispFont.setProperty(COM.DISPID_FONT_ITALIC, new Variant(fdata[0].getStyle() & SWT.ITALIC));
+ //iDispFont.setProperty(COM.DISPID_FONT_CHARSET, new Variant(fdata[0].getCharset));
+ iDispFont.setProperty(COM.DISPID_FONT_BOLD, new Variant((fdata[0].getStyle() & SWT.BOLD)));
+ iDispFont.dispose();
+ }
+ }
+ this.font = font;
+ return;
+}
+@Override
+public void setForeground (Color color) {
+
+ super.setForeground(color);
+
+ //set the foreground of the ActiveX Control
+ if (objIUnknown != null) {
+ OleAutomation oleObject= new OleAutomation(this);
+ oleObject.setProperty(COM.DISPID_FORECOLOR, new Variant(color.handle));
+ oleObject.dispose();
+ }
+}
+/**
+ * Sets the control site property specified by the dispIdMember to a new value.
+ * The value will be disposed by the control site when it is no longer required
+ * using Variant.dispose. Passing a value of null will clear the dispId value.
+ *
+ * @param dispId the ID of the property as specified by the IDL of the ActiveX Control
+ * @param value The new value for the property as expressed in a Variant.
+ *
+ * @since 2.1
+ */
+public void setSiteProperty(int dispId, Variant value){
+ for (int i = 0; i < sitePropertyIds.length; i++) {
+ if (sitePropertyIds[i] == dispId) {
+ if (sitePropertyValues[i] != null) {
+ sitePropertyValues[i].dispose();
+ }
+ if (value != null) {
+ sitePropertyValues[i] = value;
+ } else {
+ int oldLength = sitePropertyIds.length;
+ int[] newSitePropertyIds = new int[oldLength - 1];
+ Variant[] newSitePropertyValues = new Variant[oldLength - 1];
+ System.arraycopy(sitePropertyIds, 0, newSitePropertyIds, 0, i);
+ System.arraycopy(sitePropertyIds, i + 1, newSitePropertyIds, i, oldLength - i - 1);
+ System.arraycopy(sitePropertyValues, 0, newSitePropertyValues, 0, i);
+ System.arraycopy(sitePropertyValues, i + 1, newSitePropertyValues, i, oldLength - i - 1);
+ sitePropertyIds = newSitePropertyIds;
+ sitePropertyValues = newSitePropertyValues;
+ }
+ return;
+ }
+ }
+ int oldLength = sitePropertyIds.length;
+ int[] newSitePropertyIds = new int[oldLength + 1];
+ Variant[] newSitePropertyValues = new Variant[oldLength + 1];
+ System.arraycopy(sitePropertyIds, 0, newSitePropertyIds, 0, oldLength);
+ System.arraycopy(sitePropertyValues, 0, newSitePropertyValues, 0, oldLength);
+ newSitePropertyIds[oldLength] = dispId;
+ newSitePropertyValues[oldLength] = value;
+ sitePropertyIds = newSitePropertyIds;
+ sitePropertyValues = newSitePropertyValues;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleEvent.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleEvent.java
new file mode 100644
index 000000000..cb08f6ede
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleEvent.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+
+import org.eclipse.swt.widgets.Widget;
+
+public class OleEvent {
+ public int type;
+ public Widget widget;
+ public int detail;
+ public boolean doit = true;
+ public Variant[] arguments;
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleEventSink.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleEventSink.java
new file mode 100644
index 000000000..cb3e57c1b
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleEventSink.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+final class OleEventSink
+{
+ private OleControlSite widget;
+
+ private COMObject iDispatch;
+ private int refCount;
+
+ private IUnknown objIUnknown;
+ private int eventCookie;
+ private GUID eventGuid;
+
+ private OleEventTable eventTable;
+
+OleEventSink(OleControlSite widget, long iUnknown, GUID riid) {
+
+ this.widget = widget;
+ this.eventGuid = riid;
+ this.objIUnknown = new IUnknown(iUnknown);
+
+ createCOMInterfaces();
+}
+
+void connect () {
+ long[] ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIConnectionPointContainer, ppvObject) == COM.S_OK) {
+ IConnectionPointContainer cpc = new IConnectionPointContainer(ppvObject[0]);
+ long[] ppCP = new long[1];
+ if (cpc.FindConnectionPoint(eventGuid, ppCP) == COM.S_OK) {
+ IConnectionPoint cp = new IConnectionPoint(ppCP[0]);
+ int[] pCookie = new int[1];
+ if (cp.Advise(iDispatch.getAddress(), pCookie) == COM.S_OK)
+ eventCookie = pCookie[0];
+ cp.Release();
+ }
+ cpc.Release();
+ }
+}
+void addListener(int eventID, OleListener listener) {
+ if (listener == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) eventTable = new OleEventTable ();
+ eventTable.hook(eventID, listener);
+}
+int AddRef() {
+ refCount++;
+ return refCount;
+}
+private void createCOMInterfaces() {
+ iDispatch = new COMObject(new int[]{2, 0, 0, 1, 3, 4, 8}){
+ @Override
+ public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
+ @Override
+ public long method1(long[] args) {return AddRef();}
+ @Override
+ public long method2(long[] args) {return Release();}
+ // method3 GetTypeInfoCount - not implemented
+ // method4 GetTypeInfo - not implemented
+ // method5 GetIDsOfNames - not implemented
+ @Override
+ public long method6(long[] args) {return Invoke((int)args[0], args[1], (int)args[2], (int)args[3], args[4], args[5], args[6], args[7]);}
+ };
+}
+void disconnect() {
+ // disconnect event sink
+ if (eventCookie != 0 && objIUnknown != null) {
+ long[] ppvObject = new long[1];
+ if (objIUnknown.QueryInterface(COM.IIDIConnectionPointContainer, ppvObject) == COM.S_OK) {
+ IConnectionPointContainer cpc = new IConnectionPointContainer(ppvObject[0]);
+ if (cpc.FindConnectionPoint(eventGuid, ppvObject) == COM.S_OK) {
+ IConnectionPoint cp = new IConnectionPoint(ppvObject[0]);
+ if (cp.Unadvise(eventCookie) == COM.S_OK) {
+ eventCookie = 0;
+ }
+ cp.Release();
+ }
+ cpc.Release();
+ }
+ }
+}
+private void disposeCOMInterfaces() {
+ if (iDispatch != null)
+ iDispatch.dispose();
+ iDispatch = null;
+
+}
+private int Invoke(int dispIdMember, long riid, int lcid, int dwFlags, long pDispParams, long pVarResult, long pExcepInfo, long pArgErr)
+{
+ if (eventTable == null || !eventTable.hooks(dispIdMember)) return COM.S_OK;
+
+ // Construct an array of the parameters that are passed in
+ // Note: parameters are passed in reverse order - here we will correct the order
+ Variant[] eventInfo = null;
+ if (pDispParams != 0) {
+ DISPPARAMS dispParams = new DISPPARAMS();
+ COM.MoveMemory(dispParams, pDispParams, DISPPARAMS.sizeof);
+ eventInfo = new Variant[dispParams.cArgs];
+ int size = VARIANT.sizeof;
+ long offset = (dispParams.cArgs - 1) * size;
+
+ for (int j = 0; j < dispParams.cArgs; j++){
+ eventInfo[j] = new Variant();
+ eventInfo[j].setData(dispParams.rgvarg + offset);
+ offset = offset - size;
+ }
+ }
+
+ OleEvent event = new OleEvent();
+ event.arguments = eventInfo;
+ notifyListener(dispIdMember,event);
+
+ if (eventInfo != null) {
+ for (int j = 0; j < eventInfo.length; j++){
+ eventInfo[j].dispose();
+ }
+ }
+
+ return COM.S_OK;
+}
+/**
+* Notify listeners of an event.
+*
+*
+* @exception SWTException
+*
+*/
+private void notifyListener (int eventType, OleEvent event) {
+ if (event == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ event.type = eventType;
+ event.widget = widget;
+ eventTable.sendEvent (event);
+}
+private int QueryInterface(long riid, long ppvObject) {
+
+ if (riid == 0 || ppvObject == 0)
+ return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+
+ if ( COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDispatch) ||
+ COM.IsEqualGUID(guid, eventGuid)) {
+ OS.MoveMemory(ppvObject, new long[] {iDispatch.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return OLE.S_OK;
+ }
+
+ OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+int Release() {
+ refCount--;
+ if (refCount == 0) {
+ disposeCOMInterfaces();
+ }
+
+ return refCount;
+}
+void removeListener(int eventID, OleListener listener) {
+ if (listener == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (eventID, listener);
+}
+boolean hasListeners() {
+ return eventTable.hasEntries();
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleEventTable.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleEventTable.java
new file mode 100644
index 000000000..41947f443
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleEventTable.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+
+/**
+* The OleEventTable class implements a simple
+* look up mechanism that maps an event type
+* to a listener. Multiple listeners for the
+* same event type are supported.
+*
+*/
+
+class OleEventTable {
+ int [] types;
+ OleListener [] handlers;
+void hook (int eventType, OleListener handler) {
+ if (types == null) types = new int [4];
+ if (handlers == null) handlers = new OleListener [4];
+ for (int i=0; i
+ *
+ *
+ *
+ *
+ *
+ * @see OLE and ActiveX snippets
+ * @see SWT Examples: OLEExample, OleWebBrowser
+ */
+final public class OleFrame extends Composite
+{
+ // Interfaces for this Ole Client Container
+ private COMObject iOleInPlaceFrame;
+
+ // Access to the embedded/linked Ole Object
+ private IOleInPlaceActiveObject objIOleInPlaceActiveObject;
+
+ private OleClientSite currentdoc;
+
+ private int refCount = 0;
+
+ private MenuItem[] fileMenuItems;
+ private MenuItem[] containerMenuItems;
+ private MenuItem[] windowMenuItems;
+
+ private Listener listener;
+
+ private long shellHandle;
+ private long oldMenuHandle;
+ private long newMenuHandle;
+ private static long lastActivatedMenuHandle;
+
+ private static String CHECK_FOCUS = "OLE_CHECK_FOCUS"; //$NON-NLS-1$
+ private static String HHOOK = "OLE_HHOOK"; //$NON-NLS-1$
+ private static String HHOOKMSG = "OLE_HHOOK_MSG"; //$NON-NLS-1$
+
+ private static boolean ignoreNextKey;
+ private static final short [] ACCENTS = new short [] {'~', '`', '\'', '^', '"'};
+
+ private static final String CONSUME_KEY = "org.eclipse.swt.OleFrame.ConsumeKey"; //$NON-NLS-1$
+ private static final String ACCEL_KEY_HIT = "org.eclipse.swt.internal.win32.accelKeyHit"; //$NON-NLS-1$
+
+/**
+ * Create an OleFrame child widget using style bits
+ * to select a particular look or set of properties.
+ *
+ * @param parent a composite widget (cannot be null)
+ * @param style the bitwise OR'ing of widget styles
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ */
+public OleFrame(Composite parent, int style) {
+ super(parent, style);
+
+ createCOMInterfaces();
+
+ // setup cleanup proc
+ listener = e -> {
+ switch (e.type) {
+ case SWT.Activate : onActivate(e); break;
+ case SWT.Deactivate : onDeactivate(e); break;
+ case SWT.Dispose : onDispose(e); break;
+ case SWT.Resize :
+ case SWT.Move : onResize(e); break;
+ default :
+ OLE.error(SWT.ERROR_NOT_IMPLEMENTED);
+ }
+ };
+
+
+ addListener(SWT.Activate, listener);
+ addListener(SWT.Deactivate, listener);
+ addListener(SWT.Dispose, listener);
+
+ // inform inplaceactiveobject whenever frame resizes
+ addListener(SWT.Resize, listener);
+
+ // inform inplaceactiveobject whenever frame moves
+ addListener(SWT.Move, listener);
+
+ // Maintain a reference to yourself so that when
+ // ClientSites close, they don't take the frame away
+ // with them.
+ this.AddRef();
+
+ // Check for focus change
+ Display display = getDisplay();
+ initCheckFocus(display);
+ initMsgHook(display);
+}
+private static void initCheckFocus (final Display display) {
+ if (display.getData(CHECK_FOCUS) != null) return;
+ display.setData(CHECK_FOCUS, CHECK_FOCUS);
+ final int time = 50;
+ final Runnable[] timer = new Runnable[1];
+ final Control[] lastFocus = new Control[1];
+ timer[0] = () -> {
+ if (lastFocus[0] instanceof OleClientSite && !lastFocus[0].isDisposed()) {
+ // ignore popup menus and dialogs
+ long hwnd = OS.GetFocus();
+ while (hwnd != 0) {
+ long ownerHwnd = OS.GetWindow(hwnd, OS.GW_OWNER);
+ if (ownerHwnd != 0) {
+ display.timerExec(time, timer[0]);
+ return;
+ }
+ hwnd = OS.GetParent(hwnd);
+ }
+ }
+ if (lastFocus[0] == null || lastFocus[0].isDisposed() || !lastFocus[0].isFocusControl()) {
+ Control currentFocus = display.getFocusControl();
+ if (currentFocus instanceof OleFrame) {
+ OleFrame frame = (OleFrame) currentFocus;
+ currentFocus = frame.getCurrentDocument();
+ }
+ if (lastFocus[0] != currentFocus) {
+ Event event = new Event();
+ if (lastFocus[0] instanceof OleClientSite && !lastFocus[0].isDisposed()) {
+ lastFocus[0].notifyListeners (SWT.FocusOut, event);
+ }
+ if (currentFocus instanceof OleClientSite && !currentFocus.isDisposed()) {
+ currentFocus.notifyListeners(SWT.FocusIn, event);
+ }
+ }
+ lastFocus[0] = currentFocus;
+ }
+ display.timerExec(time, timer[0]);
+ };
+ display.timerExec(time, timer[0]);
+}
+private static void initMsgHook(Display display) {
+ if (display.getData(HHOOK) != null) return;
+ final Callback callback = new Callback(OleFrame.class, "getMsgProc", 3); //$NON-NLS-1$
+ long address = callback.getAddress();
+ if (address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ int threadId = OS.GetCurrentThreadId();
+ final long hHook = OS.SetWindowsHookEx(OS.WH_GETMESSAGE, address, 0, threadId);
+ if (hHook == 0) {
+ callback.dispose();
+ return;
+ }
+ display.setData(HHOOK, new LONG(hHook));
+ display.setData(HHOOKMSG, new MSG());
+ display.disposeExec(() -> {
+ if (hHook != 0) OS.UnhookWindowsHookEx(hHook);
+ if (callback != null) callback.dispose();
+ });
+}
+static long getMsgProc(long code, long wParam, long lParam) {
+ Display display = Display.getCurrent();
+ if (display == null) return 0;
+ LONG hHook = (LONG)display.getData(HHOOK);
+ if (hHook == null) return 0;
+ if (code < 0 || (wParam & OS.PM_REMOVE) == 0) {
+ return OS.CallNextHookEx(hHook.value, (int)code, wParam, lParam);
+ }
+ MSG msg = (MSG)display.getData(HHOOKMSG);
+ OS.MoveMemory(msg, lParam, MSG.sizeof);
+ int message = msg.message;
+ if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) {
+ if (display != null) {
+ Widget widget = null;
+ long hwnd = msg.hwnd;
+ while (hwnd != 0) {
+ widget = display.findWidget (hwnd);
+ if (widget != null) break;
+ hwnd = OS.GetParent (hwnd);
+ }
+ if (widget != null && widget instanceof OleClientSite) {
+ OleClientSite site = (OleClientSite)widget;
+ if (site.handle == hwnd) {
+ boolean consumed = false;
+ /* Allow activeX control to translate accelerators except when a menu is active. */
+ int thread = OS.GetWindowThreadProcessId(msg.hwnd, null);
+ GUITHREADINFO lpgui = new GUITHREADINFO();
+ lpgui.cbSize = GUITHREADINFO.sizeof;
+ boolean rc = OS.GetGUIThreadInfo(thread, lpgui);
+ int mask = OS.GUI_INMENUMODE | OS.GUI_INMOVESIZE | OS.GUI_POPUPMENUMODE | OS.GUI_SYSTEMMENUMODE;
+ if (!rc || (lpgui.flags & mask) == 0) {
+ OleFrame frame = site.frame;
+ frame.setData(CONSUME_KEY, null);
+ display.setData(ACCEL_KEY_HIT, Boolean.TRUE);
+ consumed = frame.translateOleAccelerator(msg);
+ /* translateOleAccelerator() may send client events, ensure that the frame and display are still valid */
+ if (display.isDisposed()) return 0;
+ display.setData(ACCEL_KEY_HIT, Boolean.FALSE);
+ if (frame.isDisposed()) return 0;
+ String value = (String)frame.getData(CONSUME_KEY);
+ if (value != null) consumed = value.equals("true"); //$NON-NLS-1$
+ frame.setData(CONSUME_KEY, null);
+ }
+ boolean accentKey = false;
+ switch (msg.message) {
+ case OS.WM_KEYDOWN:
+ case OS.WM_SYSKEYDOWN: {
+ switch ((int)msg.wParam) {
+ case OS.VK_SHIFT:
+ case OS.VK_MENU:
+ case OS.VK_CONTROL:
+ case OS.VK_CAPITAL:
+ case OS.VK_NUMLOCK:
+ case OS.VK_SCROLL:
+ break;
+ default: {
+ int mapKey = OS.MapVirtualKey ((int)msg.wParam, 2);
+ if (mapKey != 0) {
+ accentKey = (mapKey & 0x80000000) != 0;
+ if (!accentKey) {
+ for (int i=0; iOleListener
provide a simple
+ * handleEvent()
method that is used internally
+ * by SWT to dispatch events.
+ * OleControlSite
+ * using the addEventListener()
method and removed
+ * using the removeEventListener()
method. When the
+ * specified event occurs, handleEvent()
will be
+ * sent to the instance.
+ *
+*
+* @exception SWTException
+*
+*/
+private void notifyListener (int eventType, OleEvent event) {
+ if (event == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ event.type = eventType;
+ event.widget = controlSite;
+ eventTable.sendEvent (event);
+}
+private int OnChanged(int dispID) {
+ if (eventTable == null || !eventTable.hooks(dispID)) return COM.S_OK;
+ OleEvent event = new OleEvent();
+ event.detail = OLE.PROPERTY_CHANGED;
+ notifyListener(dispID,event);
+ return COM.S_OK;
+}
+private int OnRequestEdit(int dispID) {
+ if (eventTable == null || !eventTable.hooks(dispID)) return COM.S_OK;
+ OleEvent event = new OleEvent();
+ event.doit = true;
+ event.detail = OLE.PROPERTY_CHANGING;
+ notifyListener(dispID,event);
+ return (event.doit) ? COM.S_OK : COM.S_FALSE;
+}
+private int QueryInterface(long riid, long ppvObject) {
+ if (riid == 0 || ppvObject == 0)
+ return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+ if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIPropertyNotifySink)) {
+ OS.MoveMemory(ppvObject, new long[] {iPropertyNotifySink.getAddress()}, C.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+int Release() {
+ refCount--;
+ if (refCount == 0) {
+ disposeCOMInterfaces();
+ }
+ return refCount;
+}
+void removeListener(int propertyID, OleListener listener) {
+ if (listener == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (propertyID, listener);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OlePropertyDescription.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OlePropertyDescription.java
new file mode 100644
index 000000000..9a710fc94
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OlePropertyDescription.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+
+public class OlePropertyDescription {
+ public int id;
+ public String name;
+ public int type;
+ public int flags;
+ public int kind;
+ public String description;
+ public String helpFile;
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/Variant.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/Variant.java
new file mode 100644
index 000000000..c75a3bccb
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/Variant.java
@@ -0,0 +1,1074 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.ole.win32;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+/**
+ *
+ * A Variant is a generic OLE mechanism for passing data of different types via a common interface.
+ *
+ * Variant
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * Variant
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ *
+ * @since 3.3
+ */
+public static void win32_copy (long pVarDest, Variant varSrc) {
+ varSrc.getData (pVarDest);
+}
+
+/**
+ * Invokes platform specific functionality to wrap a variant
+ * that was allocated in operating system memory.
+ * Variant
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * Variant
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ *
+ * @since 3.3
+ */
+public static Variant win32_new (long pVariant) {
+ Variant variant = new Variant ();
+ variant.setData (pVariant);
+ return variant;
+}
+
+/**
+ * Create an empty Variant object with type VT_EMPTY.
+ *
+ * @since 2.0
+ */
+public Variant() {
+ type = COM.VT_EMPTY;
+}
+/**
+ * Create a Variant object which represents a Java float as a VT_R4.
+ *
+ * @param val the Java float value that this Variant represents
+ *
+ */
+public Variant(float val) {
+ type = COM.VT_R4;
+ floatData = val;
+}
+/**
+ * Create a Variant object which represents a Java double as a VT_R8.
+ *
+ * @param val the Java double value that this Variant represents
+ *
+ * @since 3.2
+ */
+public Variant(double val) {
+ type = COM.VT_R8;
+ doubleData = val;
+}
+/**
+ * Create a Variant object which represents a Java int as a VT_I4.
+ *
+ * @param val the Java int value that this Variant represents
+ *
+ */
+ public Variant(int val) {
+ type = COM.VT_I4;
+ intData = val;
+}
+/**
+ * Create a Variant object which contains a reference to the data being transferred.
+ *
+ *
.
+ *
+ * @param ptr a pointer to the data being transferred.
+ * @param byRefType the type of the data being transferred such as OLE.VT_BSTR | OLE.VT_BYREF
+ *
+ */
+public Variant(long ptr, short byRefType) {
+ type = byRefType;
+ byRefPtr = ptr;
+}
+/**
+ * Create a Variant object which represents an IDispatch interface as a VT_Dispatch.
+ *
+ * @param automation the OleAutomation object that this Variant represents
+ *
+ */
+public Variant(OleAutomation automation) {
+ type = COM.VT_DISPATCH;
+ dispatchData = new IDispatch(automation.getAddress());
+}
+/**
+ * Create a Variant object which represents an IDispatch interface as a VT_Dispatch.
+ * short byRefType = OLE.VT_BSTR | OLE.VT_BYREF
+ *
+ */
+public OleAutomation getAutomation() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_DISPATCH) {
+ return new OleAutomation(dispatchData);
+ }
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_DISPATCH);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant autoVar = new Variant();
+ autoVar.setData(newPtr);
+ return autoVar.getAutomation();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr); // Note: This must absolutely be done AFTER the
+ // OleAutomation object is created as Variant Clear
+ // will result in a Release being performed on the
+ // Dispatch object
+ OS.GlobalFree(newPtr);
+ }
+}
+/**
+ * Returns the IDispatch object represented by this Variant.
+ *
+ *
+ *
+ */
+public IDispatch getDispatch() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_DISPATCH) {
+ return dispatchData;
+ }
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_DISPATCH);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant autoVar = new Variant();
+ autoVar.setData(newPtr);
+ return autoVar.getDispatch();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr); // Note: This must absolutely be done AFTER the
+ // OleAutomation object is created as Variant Clear
+ // will result in a Release being performed on the
+ // Dispatch object
+ OS.GlobalFree(newPtr);
+ }
+}
+/**
+ * Returns the Java boolean represented by this Variant.
+ *
+ *
+ *
+ *
+ */
+public boolean getBoolean() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_BOOL) {
+ return booleanData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_BOOL);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant boolVar = new Variant();
+ boolVar.setData(newPtr);
+ return boolVar.getBoolean();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr);
+ OS.GlobalFree(newPtr);
+ }
+}
+/**
+ * Returns a pointer to the referenced data represented by this Variant.
+ *
+ *
+ *
+ *
+ * @since 3.3
+ */
+public byte getByte() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_I1) {
+ return byteData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_I1);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant byteVar = new Variant();
+ byteVar.setData(newPtr);
+ return byteVar.getByte();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr);
+ OS.GlobalFree(newPtr);
+ }
+}
+/**
+ * Returns the Java char represented by this Variant.
+ *
+ *
+ *
+ *
+ * @since 3.3
+ */
+public char getChar() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_UI2) {
+ return charData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_UI2);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant charVar = new Variant();
+ charVar.setData(newPtr);
+ return charVar.getChar();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr);
+ OS.GlobalFree(newPtr);
+ }
+}
+void getData(long pData){
+ if (pData == 0) OLE.error(OLE.ERROR_OUT_OF_MEMORY);
+
+ COM.VariantInit(pData);
+
+ if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
+ //TODO - use VARIANT structure
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new long[]{byRefPtr}, C.PTR_SIZEOF);
+ return;
+ }
+
+ switch (type) {
+ case COM.VT_EMPTY :
+ case COM.VT_NULL :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ break;
+ case COM.VT_BOOL :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new short[]{(booleanData) ? OS.VARIANT_TRUE : OS.VARIANT_FALSE}, 2);
+ break;
+ case COM.VT_I1 :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new byte[]{byteData}, 1);
+ break;
+ case COM.VT_I2 :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new short[]{shortData}, 2);
+ break;
+ case COM.VT_UI2 :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new char[]{charData}, 2);
+ break;
+ case COM.VT_I4 :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new int[]{intData}, 4);
+ break;
+ case COM.VT_I8 :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new long[]{longData}, 8);
+ break;
+ case COM.VT_R4 :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new float[]{floatData}, 4);
+ break;
+ case COM.VT_R8 :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new double[]{doubleData}, 8);
+ break;
+ case COM.VT_DISPATCH :
+ dispatchData.AddRef();
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new long[]{dispatchData.getAddress()}, C.PTR_SIZEOF);
+ break;
+ case COM.VT_UNKNOWN :
+ unknownData.AddRef();
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ OS.MoveMemory(pData + 8, new long[]{unknownData.getAddress()}, C.PTR_SIZEOF);
+ break;
+ case COM.VT_BSTR :
+ OS.MoveMemory(pData, new short[] {type}, 2);
+ char[] data = (stringData+"\0").toCharArray();
+ long ptr = COM.SysAllocString(data);
+ OS.MoveMemory(pData + 8, new long[] {ptr}, C.PTR_SIZEOF);
+ break;
+
+ default :
+ OLE.error(SWT.ERROR_NOT_IMPLEMENTED);
+ }
+}
+/**
+ * Returns the Java double represented by this Variant.
+ *
+ *
+ *
+ *
+ * @since 3.2
+ */
+public double getDouble() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_R8) {
+ return doubleData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_R8);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant doubleVar = new Variant();
+ doubleVar.setData(newPtr);
+ return doubleVar.getDouble();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr);
+ OS.GlobalFree(newPtr);
+ }
+}
+
+/**
+ * Returns the Java float represented by this Variant.
+ *
+ *
+ *
+ */
+public float getFloat() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_R4) {
+ return floatData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_R4);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant floatVar = new Variant();
+ floatVar.setData(newPtr);
+ return floatVar.getFloat();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr);
+ OS.GlobalFree(newPtr);
+ }
+
+}
+/**
+ * Returns the Java int represented by this Variant.
+ *
+ *
+ *
+ */
+public int getInt() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_I4) {
+ return intData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_I4);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant intVar = new Variant();
+ intVar.setData(newPtr);
+ return intVar.getInt();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr);
+ OS.GlobalFree(newPtr);
+ }
+}
+/**
+ * Returns the Java long represented by this Variant.
+ *
+ *
+ *
+ *
+ * @since 3.2
+ */
+public long getLong() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_I8) {
+ return longData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_I8);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant longVar = new Variant();
+ longVar.setData(newPtr);
+ return longVar.getLong();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr);
+ OS.GlobalFree(newPtr);
+ }
+}
+/**
+ * Returns the Java short represented by this Variant.
+ *
+ *
+ *
+ */
+public short getShort() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_I2) {
+ return shortData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_I2);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant shortVar = new Variant();
+ shortVar.setData(newPtr);
+ return shortVar.getShort();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr);
+ OS.GlobalFree(newPtr);
+ }
+
+}
+/**
+ * Returns the Java String represented by this Variant.
+ *
+ *
+ *
+ */
+public String getString() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_BSTR) {
+ return stringData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_BSTR);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+
+ Variant stringVar = new Variant();
+ stringVar.setData(newPtr);
+ return stringVar.getString();
+
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr);
+ OS.GlobalFree(newPtr);
+ }
+}
+/**
+ * Returns the type of the variant type. This will be an OLE.VT_* value or
+ * a bitwise combination of OLE.VT_* values as in the case of
+ * OLE.VT_BSTR | OLE.VT_BYREF.
+ *
+ * @return the type of the variant data
+ *
+ * @since 2.0
+ */
+public short getType() {
+ return type;
+}
+/**
+ * Returns the IUnknown object represented by this Variant.
+ *
+ *
+ *
+ */
+public IUnknown getUnknown() {
+ if (type == COM.VT_EMPTY) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
+ }
+ if (type == COM.VT_UNKNOWN) {
+ return unknownData;
+ }
+
+ // try to coerce the value to the desired type
+ long oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof);
+ try {
+ getData(oldPtr);
+ int result = COM.VariantChangeType(newPtr, oldPtr, (short) 0, COM.VT_UNKNOWN);
+ if (result != COM.S_OK)
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
+ Variant unknownVar = new Variant();
+ unknownVar.setData(newPtr);
+ return unknownVar.getUnknown();
+ } finally {
+ COM.VariantClear(oldPtr);
+ OS.GlobalFree(oldPtr);
+ COM.VariantClear(newPtr); // Note: This must absolutely be done AFTER the
+ // IUnknown object is created as Variant Clear
+ // will result in a Release being performed on the
+ // Dispatch object
+ OS.GlobalFree(newPtr);
+ }
+}
+/**
+ * Update the by reference value of this variant with a new boolean value.
+ *
+ * @param val the new boolean value
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.1
+ */
+public void setByRef(boolean val) {
+ if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_BOOL) == 0) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
+ }
+ OS.MoveMemory(byRefPtr, new short[]{val ? OS.VARIANT_TRUE : OS.VARIANT_FALSE}, 2);
+}
+/**
+ * Update the by reference value of this variant with a new float value.
+ *
+ * @param val the new float value
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.1
+ */
+public void setByRef(float val) {
+ if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_R4) == 0) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
+ }
+ OS.MoveMemory(byRefPtr, new float[]{val}, 4);
+}
+/**
+ * Update the by reference value of this variant with a new integer value.
+ *
+ * @param val the new integer value
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.1
+ */
+public void setByRef(long val) {
+ if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_I8) == 0) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
+ }
+ OS.MoveMemory(byRefPtr, new long[]{val}, C.PTR_SIZEOF);
+}
+/**
+ * Update the by reference value of this variant with a new short value.
+ *
+ * @param val the new short value
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.1
+ */
+public void setByRef(short val) {
+ if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_I2) == 0) {
+ OLE.error(OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
+ }
+ OS.MoveMemory(byRefPtr, new short[]{val}, 2);
+}
+void setData(long pData){
+ if (pData == 0) OLE.error(SWT.ERROR_INVALID_ARGUMENT);
+
+ //TODO - use VARIANT structure
+ short[] dataType = new short[1];
+ OS.MoveMemory(dataType, pData, 2);
+ type = dataType[0];
+
+ if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
+ long[] newByRefPtr = new long[1];
+ OS.MoveMemory(newByRefPtr, pData + 8, C.PTR_SIZEOF);
+ byRefPtr = newByRefPtr[0];
+ return;
+ }
+
+ switch (type) {
+ case COM.VT_EMPTY :
+ case COM.VT_NULL :
+ break;
+ case COM.VT_BOOL :
+ short[] newBooleanData = new short[1];
+ OS.MoveMemory(newBooleanData, pData + 8, 2);
+ booleanData = (newBooleanData[0] != OS.VARIANT_FALSE);
+ break;
+ case COM.VT_I1 :
+ byte[] newByteData = new byte[1];
+ OS.MoveMemory(newByteData, pData + 8, 1);
+ byteData = newByteData[0];
+ break;
+ case COM.VT_I2 :
+ short[] newShortData = new short[1];
+ OS.MoveMemory(newShortData, pData + 8, 2);
+ shortData = newShortData[0];
+ break;
+ case COM.VT_UI2 :
+ char[] newCharData = new char[1];
+ OS.MoveMemory(newCharData, pData + 8, 2);
+ charData = newCharData[0];
+ break;
+ case COM.VT_I4 :
+ int[] newIntData = new int[1];
+ OS.MoveMemory(newIntData, pData + 8, 4);
+ intData = newIntData[0];
+ break;
+ case COM.VT_I8 :
+ long[] newLongData = new long[1];
+ OS.MoveMemory(newLongData, pData + 8, 8);
+ longData = newLongData[0];
+ break;
+ case COM.VT_R4 :
+ float[] newFloatData = new float[1];
+ OS.MoveMemory(newFloatData, pData + 8, 4);
+ floatData = newFloatData[0];
+ break;
+ case COM.VT_R8 :
+ double[] newDoubleData = new double[1];
+ OS.MoveMemory(newDoubleData, pData + 8, 8);
+ doubleData = newDoubleData[0];
+ break;
+ case COM.VT_DISPATCH : {
+ long[] ppvObject = new long[1];
+ OS.MoveMemory(ppvObject, pData + 8, C.PTR_SIZEOF);
+ if (ppvObject[0] == 0) {
+ type = COM.VT_EMPTY;
+ break;
+ }
+ dispatchData = new IDispatch(ppvObject[0]);
+ dispatchData.AddRef();
+ break;
+ }
+ case COM.VT_UNKNOWN : {
+ long[] ppvObject = new long[1];
+ OS.MoveMemory(ppvObject, pData + 8, C.PTR_SIZEOF);
+ if (ppvObject[0] == 0) {
+ type = COM.VT_EMPTY;
+ break;
+ }
+ unknownData = new IUnknown(ppvObject[0]);
+ unknownData.AddRef();
+ break;
+ }
+ case COM.VT_BSTR :
+ // get the address of the memory in which the string resides
+ long[] hMem = new long[1];
+ OS.MoveMemory(hMem, pData + 8, C.PTR_SIZEOF);
+ if (hMem[0] == 0) {
+ type = COM.VT_EMPTY;
+ break;
+ }
+ // Get the size of the string from the OS - the size is expressed in number
+ // of bytes - each unicode character is 2 bytes.
+ int size = COM.SysStringByteLen(hMem[0]);
+ if (size > 0){
+ // get the unicode character array from the global memory and create a String
+ char[] buffer = new char[(size + 1) /2]; // add one to avoid rounding errors
+ OS.MoveMemory(buffer, hMem[0], size);
+ stringData = new String(buffer);
+ } else {
+ stringData = ""; //$NON-NLS-1$
+ }
+ break;
+
+ default :
+ // try coercing it into one of the known forms
+ long newPData = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, sizeof);
+ if (COM.VariantChangeType(newPData, pData, (short) 0, COM.VT_R8) == COM.S_OK) {
+ setData(newPData);
+ } else if (COM.VariantChangeType(newPData, pData, (short) 0, COM.VT_I8) == COM.S_OK) {
+ setData(newPData);
+ } else if (COM.VariantChangeType(newPData, pData, (short) 0, COM.VT_BSTR) == COM.S_OK) {
+ setData(newPData);
+ }
+ COM.VariantClear(newPData);
+ OS.GlobalFree(newPData);
+ break;
+ }
+}
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the Variant
+ */
+@Override
+public String toString () {
+ switch (type) {
+ case COM.VT_BOOL :
+ return "VT_BOOL{"+booleanData+"}";
+ case COM.VT_I1 :
+ return "VT_I1{"+byteData+"}";
+ case COM.VT_I2 :
+ return "VT_I2{"+shortData+"}";
+ case COM.VT_UI2 :
+ return "VT_UI2{"+charData+"}";
+ case COM.VT_I4 :
+ return "VT_I4{"+intData+"}";
+ case COM.VT_I8 :
+ return "VT_I8{"+longData+"}";
+ case COM.VT_R4 :
+ return "VT_R4{"+floatData+"}";
+ case COM.VT_R8 :
+ return "VT_R8{"+doubleData+"}";
+ case COM.VT_BSTR :
+ return "VT_BSTR{"+stringData+"}";
+ case COM.VT_DISPATCH :
+ return "VT_DISPATCH{"+(dispatchData == null ? 0 : dispatchData.getAddress())+"}";
+ case COM.VT_UNKNOWN :
+ return "VT_UNKNOWN{"+(unknownData == null ? 0 : unknownData.getAddress())+"}";
+ case COM.VT_EMPTY :
+ return "VT_EMPTY";
+ case COM.VT_NULL :
+ return "VT_NULL";
+ }
+ if ((type & COM.VT_BYREF) != 0) {
+ return "VT_BYREF|"+(type & ~COM.VT_BYREF)+"{"+byRefPtr+"}";
+ }
+ return "Unsupported Type "+type;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/package.html b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/package.html
new file mode 100644
index 000000000..93c5fd16a
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/package.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+Package Specification
+This package contains the classes which provide the public API to the
+the Microsoft Win32 Object Linking and Embedding mechanism
+that the win32 variant of SWT is capable of using.
+
+ */
+public GLCanvas (Composite parent, int style, GLData data) {
+ super (parent, checkStyle (parent, style));
+ parent.getDisplay ().setData (USE_OWNDC_KEY, false);
+ if (data == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ PIXELFORMATDESCRIPTOR pfd = new PIXELFORMATDESCRIPTOR ();
+ pfd.nSize = (short) PIXELFORMATDESCRIPTOR.sizeof;
+ pfd.nVersion = 1;
+ pfd.dwFlags = WGL.PFD_DRAW_TO_WINDOW | WGL.PFD_SUPPORT_OPENGL;
+ pfd.dwLayerMask = WGL.PFD_MAIN_PLANE;
+ pfd.iPixelType = (byte) WGL.PFD_TYPE_RGBA;
+ if (data.doubleBuffer) pfd.dwFlags |= WGL.PFD_DOUBLEBUFFER;
+ if (data.stereo) pfd.dwFlags |= WGL.PFD_STEREO;
+ pfd.cRedBits = (byte) data.redSize;
+ pfd.cGreenBits = (byte) data.greenSize;
+ pfd.cBlueBits = (byte) data.blueSize;
+ pfd.cAlphaBits = (byte) data.alphaSize;
+ pfd.cDepthBits = (byte) data.depthSize;
+ pfd.cStencilBits = (byte) data.stencilSize;
+ pfd.cAccumRedBits = (byte) data.accumRedSize;
+ pfd.cAccumGreenBits = (byte) data.accumGreenSize;
+ pfd.cAccumBlueBits = (byte) data.accumBlueSize;
+ pfd.cAccumAlphaBits = (byte) data.accumAlphaSize;
+ pfd.cAccumBits = (byte) (pfd.cAccumRedBits + pfd.cAccumGreenBits + pfd.cAccumBlueBits + pfd.cAccumAlphaBits);
+
+ //FIXME - use wglChoosePixelFormatARB
+// if (data.sampleBuffers > 0) {
+// wglAttrib [pos++] = WGL.WGL_SAMPLE_BUFFERS_ARB;
+// wglAttrib [pos++] = data.sampleBuffers;
+// }
+// if (data.samples > 0) {
+// wglAttrib [pos++] = WGL.WGL_SAMPLES_ARB;
+// wglAttrib [pos++] = data.samples;
+// }
+
+ long hDC = OS.GetDC (handle);
+ pixelFormat = WGL.ChoosePixelFormat (hDC, pfd);
+ if (pixelFormat == 0 || !WGL.SetPixelFormat (hDC, pixelFormat, pfd)) {
+ OS.ReleaseDC (handle, hDC);
+ dispose ();
+ SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
+ context = WGL.wglCreateContext (hDC);
+ if (context == 0) {
+ OS.ReleaseDC (handle, hDC);
+ SWT.error (SWT.ERROR_NO_HANDLES);
+ }
+ OS.ReleaseDC (handle, hDC);
+ if (data.shareContext != null) {
+ WGL.wglShareLists (data.shareContext.context, context);
+ }
+
+ Listener listener = event -> {
+ switch (event.type) {
+ case SWT.Dispose:
+ WGL.wglDeleteContext (context);
+ break;
+ }
+ };
+ addListener (SWT.Dispose, listener);
+}
+
+static int checkStyle(Composite parent, int style) {
+ if (parent != null) {
+ parent.getDisplay ().setData (USE_OWNDC_KEY, true);
+ }
+ return style;
+}
+
+/**
+ * Returns a GLData object describing the created context.
+ *
+ * @return GLData description of the OpenGL context attributes
+ * @exception SWTException
+ *
+ */
+public GLData getGLData () {
+ checkWidget ();
+ GLData data = new GLData ();
+ PIXELFORMATDESCRIPTOR pfd = new PIXELFORMATDESCRIPTOR ();
+ pfd.nSize = (short) PIXELFORMATDESCRIPTOR.sizeof;
+ long hDC = OS.GetDC (handle);
+ WGL.DescribePixelFormat (hDC, pixelFormat, PIXELFORMATDESCRIPTOR.sizeof, pfd);
+ OS.ReleaseDC (handle, hDC);
+ data.doubleBuffer = (pfd.dwFlags & WGL.PFD_DOUBLEBUFFER) != 0;
+ data.stereo = (pfd.dwFlags & WGL.PFD_STEREO) != 0;
+ data.redSize = pfd.cRedBits;
+ data.greenSize = pfd.cGreenBits;
+ data.blueSize = pfd.cBlueBits;
+ data.alphaSize = pfd.cAlphaBits;
+ data.depthSize = pfd.cDepthBits;
+ data.stencilSize = pfd.cStencilBits;
+ data.accumRedSize = pfd.cAccumRedBits;
+ data.accumGreenSize = pfd.cAccumGreenBits;
+ data.accumBlueSize = pfd.cAccumBlueBits;
+ data.accumAlphaSize = pfd.cAccumAlphaBits;
+ return data;
+}
+
+/**
+ * Returns a boolean indicating whether the receiver's OpenGL context
+ * is the current context.
+ *
+ * @return true if the receiver holds the current OpenGL context,
+ * false otherwise
+ * @exception SWTException
+ *
+ */
+public boolean isCurrent () {
+ checkWidget ();
+ return WGL.wglGetCurrentContext () == context;
+}
+
+/**
+ * Sets the OpenGL context associated with this GLCanvas to be the
+ * current GL context.
+ *
+ * @exception SWTException
+ *
+ */
+public void setCurrent () {
+ checkWidget ();
+ if (WGL.wglGetCurrentContext () == context) return;
+ long hDC = OS.GetDC (handle);
+ WGL.wglMakeCurrent (hDC, context);
+ OS.ReleaseDC (handle, hDC);
+}
+
+/**
+ * Swaps the front and back color buffers.
+ *
+ * @exception SWTException
+ *
+ */
+public void swapBuffers () {
+ checkWidget ();
+ long hDC = OS.GetDC (handle);
+ WGL.SwapBuffers (hDC);
+ OS.ReleaseDC (handle, hDC);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/opengl/GLData.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/opengl/GLData.java
new file mode 100644
index 000000000..5a5ecc7ad
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/opengl/GLData.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2009 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.opengl;
+
+/**
+ * The GLData class is a device-independent description
+ * of the pixel format attributes of a GL drawable.
+ *
+ * @see GLCanvas
+ * @see OpenGL snippets
+ * @see Sample code and further information
+ *
+ * @since 3.2
+ */
+
+public class GLData {
+ /**
+ * Specifies a double-buffered surface. During context
+ * creation, only double-buffered formats are considered
+ * when set to true.
+ */
+ public boolean doubleBuffer;
+
+ /**
+ * Specifies a stereo surface. During context creation,
+ * only stereo formats are considered when set to true.
+ */
+ public boolean stereo;
+
+ /**
+ * The size in bits of the color buffer's red channel.
+ * During context creation, this specifies the minimum
+ * required red bits.
+ */
+ public int redSize;
+
+ /**
+ * The size in bits of the color buffer's green channel.
+ * During context creation, this specifies the minimum
+ * required green bits.
+ */
+ public int greenSize;
+
+ /**
+ * The size in bits of the color buffer's blue channel.
+ * During context creation, this specifies the minimum
+ * required blue bits.
+ */
+ public int blueSize;
+
+ /**
+ * The size in bits of the color buffer's alpha channel.
+ * During context creation, this specifies the minimum
+ * required alpha bits.
+ */
+ public int alphaSize;
+
+ /**
+ * The size in bits of the depth buffer. During context
+ * creation, the smallest depth buffer of at least the
+ * specified value is preferred, or zero for no depth
+ * buffer.
+ */
+ public int depthSize;
+
+ /**
+ * The desired number of stencil bitplanes. During
+ * context creation, the smallest stencil buffer of at
+ * least the specified value is preferred, or zero for
+ * no stencil buffer.
+ */
+ public int stencilSize;
+
+ /**
+ * The size in bits of the accumulation buffer's red
+ * channel. During context creation, this specifies the
+ * minimum required red bits.
+ */
+ public int accumRedSize;
+
+ /**
+ * The size in bits of the accumulation buffer's green
+ * channel. During context creation, this specifies the
+ * minimum required green bits.
+ */
+ public int accumGreenSize;
+
+ /**
+ * The size in bits of the accumulation buffer's blue
+ * channel. During context creation, this specifies the
+ * minimum required blue bits.
+ */
+ public int accumBlueSize;
+
+ /**
+ * The size in bits of the accumulation buffer's alpha
+ * channel. During context creation, this specifies the
+ * minimum required alpha bits.
+ */
+ public int accumAlphaSize;
+
+ /**
+ * The number of multisample buffers used by this context.
+ * During context creation, this specifies the minimum
+ * number of multisample buffers requested.
+ */
+ public int sampleBuffers;
+
+ /**
+ * The number of samples accepted in the multisample buffer.
+ * During creation, pixel formats with the smallest number of
+ * samples that meets or exceeds the specified minimum number
+ * are preferred.
+ */
+ public int samples;
+
+ /**
+ * Another GLCanvas whose texture namespace and display lists
+ * should be shared.
+ *
+ * @since 3.5
+ */
+ public GLCanvas shareContext;
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the data
+ */
+@Override
+public String toString() {
+ return (doubleBuffer ? "doubleBuffer," : "") +
+ (stereo ? "stereo," : "") +
+ "r:" + redSize + " g:" + greenSize + " b:" + blueSize + " a:" + alphaSize + "," +
+ "depth:" + depthSize + ",stencil:" + stencilSize +
+ ",accum r:" + accumRedSize + "g:" + accumGreenSize + "b:" + accumBlueSize + "a:" + accumAlphaSize +
+ ",sampleBuffers:" + sampleBuffers + ",samples:" + samples;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/opengl/package.html b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/opengl/package.html
new file mode 100644
index 000000000..3ad94aefa
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/opengl/package.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+Package Specification
+This package contains widgets for integrating OpenGL graphics
+into SWT applications.
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/package.html b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/package.html
new file mode 100644
index 000000000..31459b907
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/package.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+Package Specification
+This package provides the class SWT
which contains all of the
+constants used by SWT as well as a small selection of error handling routines
+and queries such as getPlatform
and getVersion
.
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/PrintDialog.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/PrintDialog.java
new file mode 100644
index 000000000..38af0a711
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/PrintDialog.java
@@ -0,0 +1,544 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.printing;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Instances of this class allow the user to select
+ * a printer and various print-related parameters
+ * prior to starting a print job.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public PrintDialog (Shell parent) {
+ this (parent, SWT.PRIMARY_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public PrintDialog (Shell parent, int style) {
+ super (parent, checkStyle(parent, style));
+ checkSubclass ();
+}
+
+static int checkBits (int style, int int0, int int1, int int2, int int3, int int4, int int5) {
+ int mask = int0 | int1 | int2 | int3 | int4 | int5;
+ if ((style & mask) == 0) style |= int0;
+ if ((style & int0) != 0) style = (style & ~mask) | int0;
+ if ((style & int1) != 0) style = (style & ~mask) | int1;
+ if ((style & int2) != 0) style = (style & ~mask) | int2;
+ if ((style & int3) != 0) style = (style & ~mask) | int3;
+ if ((style & int4) != 0) style = (style & ~mask) | int4;
+ if ((style & int5) != 0) style = (style & ~mask) | int5;
+ return style;
+}
+
+static int checkStyle (Shell parent, int style) {
+ int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
+ if ((style & SWT.SHEET) != 0) {
+ style &= ~SWT.SHEET;
+ if ((style & mask) == 0) {
+ style |= parent == null ? SWT.APPLICATION_MODAL : SWT.PRIMARY_MODAL;
+ }
+ }
+ if ((style & mask) == 0) {
+ style |= SWT.APPLICATION_MODAL;
+ }
+ style &= ~SWT.MIRRORED;
+ if ((style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)) == 0) {
+ if (parent != null) {
+ if ((parent.getStyle () & SWT.LEFT_TO_RIGHT) != 0) style |= SWT.LEFT_TO_RIGHT;
+ if ((parent.getStyle () & SWT.RIGHT_TO_LEFT) != 0) style |= SWT.RIGHT_TO_LEFT;
+ }
+ }
+ return checkBits (style, SWT.LEFT_TO_RIGHT, SWT.RIGHT_TO_LEFT, 0, 0, 0, 0);
+}
+
+/**
+ * Sets the printer data that will be used when the dialog
+ * is opened.
+ *
+ *
+ *
+ * @return the scope setting that the user selected
+ */
+public int getScope() {
+ return printerData.scope;
+}
+
+/**
+ * Sets the scope of the print job. The user will see this
+ * setting when the dialog is opened. This can have one of
+ * the following values:
+ * PrinterData.ALL_PAGES
PrinterData.PAGE_RANGE
PrinterData.SELECTION
+ *
+ *
+ * @param scope the scope setting when the dialog is opened
+ */
+public void setScope(int scope) {
+ printerData.scope = scope;
+}
+
+/**
+ * Returns the start page setting that the user selected
+ * before pressing OK in the dialog.
+ * PrinterData.ALL_PAGES
PrinterData.PAGE_RANGE
PrinterData.SELECTION
PrinterData.PAGE_RANGE
.
+ * PrinterData.PAGE_RANGE
.
+ * PrinterData.PAGE_RANGE
.
+ * PrinterData.PAGE_RANGE
.
+ *
+ *
+ */
+public PrinterData open() {
+ /* Get the owner HWND for the dialog */
+ Control parent = getParent();
+ int style = getStyle();
+ long hwndOwner = parent.handle;
+ long hwndParent = parent.handle;
+
+ /*
+ * Feature in Windows. There is no API to set the BIDI orientation
+ * of a print dialog. It is always inherited from the parent. The fix
+ * is to create a hidden parent and set the orientation in the hidden
+ * parent for the dialog to inherit.
+ */
+ boolean enabled = false;
+ int dialogOrientation = style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+ int parentOrientation = parent.getStyle() & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+ if (dialogOrientation != parentOrientation) {
+ int exStyle = OS.WS_EX_NOINHERITLAYOUT;
+ if (dialogOrientation == SWT.RIGHT_TO_LEFT) exStyle |= OS.WS_EX_LAYOUTRTL;
+ hwndOwner = OS.CreateWindowEx (
+ exStyle,
+ DialogClass,
+ null,
+ 0,
+ OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
+ hwndParent,
+ 0,
+ OS.GetModuleHandle (null),
+ null);
+ enabled = OS.IsWindowEnabled (hwndParent);
+ if (enabled) OS.EnableWindow (hwndParent, false);
+ }
+
+ PrinterData data = null;
+ PRINTDLG pd = new PRINTDLG();
+ pd.lStructSize = PRINTDLG.sizeof;
+ pd.hwndOwner = hwndOwner;
+
+ boolean success = false;
+ if (printerData.name != null) {
+ /* Ensure that the printer name is in the current list of printers. */
+ PrinterData printerList[] = Printer.getPrinterList();
+ if (printerList.length > 0) {
+ for (int p = 0; p < printerList.length; p++) {
+ if (printerList[p].name.equals(printerData.name)) {
+ success = true;
+ break;
+ }
+ }
+ }
+ if (success) {
+ /* Initialize PRINTDLG DEVNAMES for the specified printer. */
+ TCHAR buffer = new TCHAR(0, printerData.name, true);
+ int size = buffer.length() * TCHAR.sizeof;
+ short[] offsets = new short[4]; // DEVNAMES (4 offsets)
+ int offsetsSize = offsets.length * 2; // 2 bytes each
+ offsets[1] = (short) offsets.length; // offset 1 points to wDeviceOffset
+ long hMem = OS.GlobalAlloc(OS.GMEM_MOVEABLE | OS.GMEM_ZEROINIT, offsetsSize + size);
+ long ptr = OS.GlobalLock(hMem);
+ OS.MoveMemory(ptr, offsets, offsetsSize);
+ OS.MoveMemory(ptr + offsetsSize, buffer, size);
+ OS.GlobalUnlock(hMem);
+ pd.hDevNames = hMem;
+ }
+ }
+ Display display = parent.getDisplay();
+ String externalLoopKey = "org.eclipse.swt.internal.win32.externalEventLoop";
+ if (!success) {
+ /* Initialize PRINTDLG fields, including DEVMODE, for the default printer. */
+ pd.Flags = OS.PD_RETURNDEFAULT;
+ display.setData(externalLoopKey, Boolean.TRUE);
+ display.sendPreExternalEventDispatchEvent ();
+ success = OS.PrintDlg(pd);
+ display.setData(externalLoopKey, Boolean.FALSE);
+ display.sendPostExternalEventDispatchEvent ();
+ if (success) {
+ if (pd.hDevNames != 0) {
+ OS.GlobalFree(pd.hDevNames);
+ pd.hDevNames = 0;
+ }
+ }
+ }
+
+ if (success) {
+ /*
+ * If user setup info from a previous print dialog was specified,
+ * then restore the previous DEVMODE struct.
+ */
+ byte devmodeData [] = printerData.otherData;
+ if (devmodeData != null && devmodeData.length != 0) {
+ long hMem = OS.GlobalAlloc(OS.GMEM_MOVEABLE | OS.GMEM_ZEROINIT, devmodeData.length);
+ long ptr = OS.GlobalLock(hMem);
+ OS.MoveMemory(ptr, devmodeData, devmodeData.length);
+ OS.GlobalUnlock(hMem);
+ if (pd.hDevMode != 0) OS.GlobalFree(pd.hDevMode);
+ pd.hDevMode = hMem;
+ }
+
+ /* Initialize the DEVMODE struct's fields from the printerData. */
+ long hMem = pd.hDevMode;
+ if (hMem == 0) {
+ hMem = OS.GlobalAlloc(OS.GMEM_MOVEABLE | OS.GMEM_ZEROINIT, DEVMODE.sizeof);
+ pd.hDevMode = hMem;
+ }
+ long ptr = OS.GlobalLock(hMem);
+ DEVMODE devmode = new DEVMODE ();
+ OS.MoveMemory(devmode, ptr, DEVMODE.sizeof);
+ if (printerData.name != null) {
+ /* Copy PRINTDLG DEVNAMES into DEVMODE dmDeviceName (truncate if necessary). */
+ int max = Math.min(printerData.name.length(), OS.CCHDEVICENAME - 1);
+ for (int i = 0; i < max; i++) {
+ devmode.dmDeviceName[i] = printerData.name.charAt(i);
+ }
+ }
+ devmode.dmFields |= OS.DM_ORIENTATION;
+ devmode.dmOrientation = printerData.orientation == PrinterData.PORTRAIT ? OS.DMORIENT_PORTRAIT : OS.DMORIENT_LANDSCAPE;
+ if (printerData.copyCount != 1) {
+ devmode.dmFields |= OS.DM_COPIES;
+ devmode.dmCopies = (short)printerData.copyCount;
+ }
+ if (printerData.collate != false) {
+ devmode.dmFields |= OS.DM_COLLATE;
+ devmode.dmCollate = OS.DMCOLLATE_TRUE;
+ }
+ if (printerData.duplex != SWT.DEFAULT) {
+ devmode.dmFields |= OS.DM_DUPLEX;
+ switch (printerData.duplex) {
+ case PrinterData.DUPLEX_SHORT_EDGE: devmode.dmDuplex = OS.DMDUP_HORIZONTAL; break;
+ case PrinterData.DUPLEX_LONG_EDGE: devmode.dmDuplex = OS.DMDUP_VERTICAL; break;
+ default: devmode.dmDuplex = OS.DMDUP_SIMPLEX;
+ }
+ }
+ OS.MoveMemory(ptr, devmode, DEVMODE.sizeof);
+ OS.GlobalUnlock(hMem);
+
+ pd.Flags = OS.PD_USEDEVMODECOPIESANDCOLLATE;
+ if (printerData.printToFile) pd.Flags |= OS.PD_PRINTTOFILE;
+ switch (printerData.scope) {
+ case PrinterData.PAGE_RANGE: pd.Flags |= OS.PD_PAGENUMS; break;
+ case PrinterData.SELECTION: pd.Flags |= OS.PD_SELECTION; break;
+ default: pd.Flags |= OS.PD_ALLPAGES;
+ }
+ pd.nMinPage = 1;
+ pd.nMaxPage = -1;
+ pd.nFromPage = (short) Math.min (0xFFFF, Math.max (1, printerData.startPage));
+ pd.nToPage = (short) Math.min (0xFFFF, Math.max (1, printerData.endPage));
+
+ Shell [] shells = display.getShells();
+ if ((getStyle() & (SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) {
+ for (int i=0; iPrinter
object may be constructed by providing
+ * a PrinterData
object which identifies the printer.
+ * A PrintDialog
presents a print dialog to the user
+ * and returns an initialized instance of PrinterData
.
+ * Alternatively, calling new Printer()
will construct a
+ * printer object for the user's default printer.
+ * Printer.dispose()
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * PrinterData
objects
+ * representing all available printers. If there are no
+ * printers, the array will be empty.
+ *
+ * @return an array of PrinterData objects representing the available printers
+ */
+public static PrinterData[] getPrinterList() {
+ int length = 1024;
+ /* Use the character encoding for the default locale */
+ TCHAR buf = new TCHAR(0, length);
+ TCHAR nullBuf = new TCHAR(0, 1);
+ int n = OS.GetProfileString(profile, null, nullBuf, buf, length);
+ if (n == 0) return new PrinterData[0];
+ String[] deviceNames = new String[5];
+ int nameCount = 0;
+ int index = 0;
+ for (int i = 0; i < n; i++) {
+ if (buf.tcharAt(i) == 0) {
+ if (nameCount == deviceNames.length) {
+ String[] newNames = new String[deviceNames.length + 5];
+ System.arraycopy(deviceNames, 0, newNames, 0, deviceNames.length);
+ deviceNames = newNames;
+ }
+ deviceNames[nameCount] = buf.toString(index, i - index);
+ nameCount++;
+ index = i + 1;
+ }
+ }
+ PrinterData printerList[] = new PrinterData[nameCount];
+ for (int p = 0; p < nameCount; p++) {
+ String device = deviceNames[p];
+ String driver = ""; //$NON-NLS-1$
+ if (OS.GetProfileString(profile, new TCHAR(0, device, true), nullBuf, buf, length) > 0) {
+ int commaIndex = 0;
+ while (buf.tcharAt(commaIndex) != ',' && commaIndex < length) commaIndex++;
+ if (commaIndex < length) {
+ driver = buf.toString(0, commaIndex);
+ }
+ }
+ printerList[p] = new PrinterData(driver, device);
+ }
+ return printerList;
+}
+
+/**
+ * Returns a PrinterData
object representing
+ * the default printer or null
if there is no
+ * default printer.
+ *
+ * @return the default printer data or null
+ *
+ * @since 2.1
+ */
+public static PrinterData getDefaultPrinterData() {
+ String deviceName = null;
+ int length = 1024;
+ /* Use the character encoding for the default locale */
+ TCHAR buf = new TCHAR(0, length);
+ TCHAR nullBuf = new TCHAR(0, 1);
+ int n = OS.GetProfileString(appName, keyName, nullBuf, buf, length);
+ if (n == 0) return null;
+ int commaIndex = 0;
+ while(buf.tcharAt(commaIndex) != ',' && commaIndex < length) commaIndex++;
+ if (commaIndex < length) {
+ deviceName = buf.toString(0, commaIndex);
+ }
+ if (deviceName == null) return null;
+ String driver = ""; //$NON-NLS-1$
+ if (OS.GetProfileString(profile, new TCHAR(0, deviceName, true), nullBuf, buf, length) > 0) {
+ commaIndex = 0;
+ while (buf.tcharAt(commaIndex) != ',' && commaIndex < length) commaIndex++;
+ if (commaIndex < length) {
+ driver = buf.toString(0, commaIndex);
+ }
+ }
+ return new PrinterData(driver, deviceName);
+}
+
+static DeviceData checkNull (PrinterData data) {
+ if (data == null) data = new PrinterData();
+ if (data.driver == null || data.name == null) {
+ PrinterData defaultPrinter = getDefaultPrinterData();
+ if (defaultPrinter == null) SWT.error(SWT.ERROR_NO_HANDLES);
+ data.driver = defaultPrinter.driver;
+ data.name = defaultPrinter.name;
+ }
+ return data;
+}
+
+/**
+ * Constructs a new printer representing the default printer.
+ *
+ *
+ *
+ * @see Device#dispose
+ */
+public Printer() {
+ this(null);
+}
+
+/**
+ * Constructs a new printer given a PrinterData
+ * object representing the desired printer. If the argument
+ * is null, then the default printer will be used.
+ *
+ *
+ * @exception SWTError
+ *
+ *
+ * @see Device#dispose
+ */
+public Printer(PrinterData data) {
+ super(checkNull(data));
+}
+
+/**
+ * Creates the printer handle.
+ * This method is called internally by the instance creation
+ * mechanism of the Device
class.
+ * @param deviceData the device data
+ */
+@Override
+protected void create(DeviceData deviceData) {
+ data = (PrinterData)deviceData;
+ /* Use the character encoding for the default locale */
+ TCHAR driver = new TCHAR(0, data.driver, true);
+ TCHAR device = new TCHAR(0, data.name, true);
+ long lpInitData = 0;
+ byte devmodeData [] = data.otherData;
+ long hHeap = OS.GetProcessHeap();
+ if (devmodeData != null && devmodeData.length != 0) {
+ /* If user setup info from a print dialog was specified, restore the DEVMODE struct. */
+ lpInitData = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, devmodeData.length);
+ OS.MoveMemory(lpInitData, devmodeData, devmodeData.length);
+ } else {
+ long [] hPrinter = new long [1];
+ OS.OpenPrinter(device, hPrinter, 0);
+ if (hPrinter[0] != 0) {
+ int dwNeeded = OS.DocumentProperties(0, hPrinter[0], device, 0, 0, 0);
+ if (dwNeeded >= 0) {
+ lpInitData = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, dwNeeded);
+ int rc = OS.DocumentProperties(0, hPrinter[0], device, lpInitData, 0, OS.DM_OUT_BUFFER);
+ if (rc != OS.IDOK) {
+ OS.HeapFree(hHeap, 0, lpInitData);
+ lpInitData = 0;
+ }
+ }
+ OS.ClosePrinter(hPrinter[0]);
+ }
+ }
+
+ /* Initialize DEVMODE struct fields from the printerData. */
+ if (lpInitData != 0) {
+ DEVMODE devmode = new DEVMODE ();
+ OS.MoveMemory(devmode, lpInitData, DEVMODE.sizeof);
+ devmode.dmFields |= OS.DM_ORIENTATION;
+ devmode.dmOrientation = data.orientation == PrinterData.LANDSCAPE ? OS.DMORIENT_LANDSCAPE : OS.DMORIENT_PORTRAIT;
+ if (data.copyCount != 1) {
+ devmode.dmFields |= OS.DM_COPIES;
+ devmode.dmCopies = (short)data.copyCount;
+ }
+ if (data.collate != false) {
+ devmode.dmFields |= OS.DM_COLLATE;
+ devmode.dmCollate = OS.DMCOLLATE_TRUE;
+ }
+ if (data.duplex != SWT.DEFAULT) {
+ devmode.dmFields |= OS.DM_DUPLEX;
+ switch (data.duplex) {
+ case PrinterData.DUPLEX_SHORT_EDGE: devmode.dmDuplex = OS.DMDUP_HORIZONTAL; break;
+ case PrinterData.DUPLEX_LONG_EDGE: devmode.dmDuplex = OS.DMDUP_VERTICAL; break;
+ default: devmode.dmDuplex = OS.DMDUP_SIMPLEX;
+ }
+ }
+ OS.MoveMemory(lpInitData, devmode, DEVMODE.sizeof);
+ }
+ handle = OS.CreateDC(driver, device, 0, lpInitData);
+ if (lpInitData != 0) OS.HeapFree(hHeap, 0, lpInitData);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * Printer
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * Printer
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ *
+ *
+ * @see #startPage
+ * @see #endPage
+ * @see #endJob
+ */
+public boolean startJob(String jobName) {
+ checkDevice();
+ DOCINFO di = new DOCINFO();
+ di.cbSize = DOCINFO.sizeof;
+ long hHeap = OS.GetProcessHeap();
+ long lpszDocName = 0;
+ if (jobName != null && jobName.length() != 0) {
+ /* Use the character encoding for the default locale */
+ TCHAR buffer = new TCHAR(0, jobName, true);
+ int byteCount = buffer.length() * TCHAR.sizeof;
+ lpszDocName = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory(lpszDocName, buffer, byteCount);
+ di.lpszDocName = lpszDocName;
+ }
+ long lpszOutput = 0;
+ if (data.printToFile) {
+ if (data.fileName == null) {
+ /* Prompt the user for a file name. */
+ data.fileName = "FILE:"; //$NON-NLS-1$
+ }
+ /* Use the character encoding for the default locale */
+ TCHAR buffer = new TCHAR(0, data.fileName, true);
+ int byteCount = buffer.length() * TCHAR.sizeof;
+ lpszOutput = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory(lpszOutput, buffer, byteCount);
+ di.lpszOutput = lpszOutput;
+ }
+ int rc = OS.StartDoc(handle, di);
+ if (lpszDocName != 0) OS.HeapFree(hHeap, 0, lpszDocName);
+ if (lpszOutput != 0) OS.HeapFree(hHeap, 0, lpszOutput);
+ return rc > 0;
+}
+
+/**
+ * Ends the current print job.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #startJob
+ * @see #startPage
+ * @see #endPage
+ */
+public void endJob() {
+ checkDevice();
+ OS.EndDoc(handle);
+}
+
+/**
+ * Cancels a print job in progress.
+ *
+ * @exception SWTException
+ *
+ */
+public void cancelJob() {
+ checkDevice();
+ OS.AbortDoc(handle);
+}
+
+/**
+ * Starts a page and returns true if the page started successfully
+ * and false otherwise.
+ *
+ *
+ *
+ * @see #endPage
+ * @see #startJob
+ * @see #endJob
+ */
+public boolean startPage() {
+ checkDevice();
+ int rc = OS.StartPage(handle);
+ if (rc <= 0) OS.AbortDoc(handle);
+ return rc > 0;
+}
+
+/**
+ * Ends the current page.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #startPage
+ * @see #startJob
+ * @see #endJob
+ */
+public void endPage() {
+ checkDevice();
+ OS.EndPage(handle);
+}
+
+/**
+ * Returns a point whose x coordinate is the horizontal
+ * dots per inch of the printer, and whose y coordinate
+ * is the vertical dots per inch of the printer.
+ *
+ * @return the horizontal and vertical DPI
+ *
+ * @exception SWTException
+ *
+ */
+@Override
+public Point getDPI() {
+ checkDevice();
+ int dpiX = OS.GetDeviceCaps(handle, OS.LOGPIXELSX);
+ int dpiY = OS.GetDeviceCaps(handle, OS.LOGPIXELSY);
+ return new Point(dpiX, dpiY);
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location.
+ *
+ *
+ *
+ * @see #getClientArea
+ * @see #computeTrim
+ */
+@Override
+public Rectangle getBounds() {
+ checkDevice();
+ int width = OS.GetDeviceCaps(handle, OS.PHYSICALWIDTH);
+ int height = OS.GetDeviceCaps(handle, OS.PHYSICALHEIGHT);
+ return new Rectangle(0, 0, width, height);
+}
+
+/**
+ * Returns a rectangle which describes the area of the
+ * receiver which is capable of displaying data.
+ *
+ *
+ *
+ * @see #getBounds
+ * @see #computeTrim
+ */
+@Override
+public Rectangle getClientArea () {
+ checkDevice();
+ int width = OS.GetDeviceCaps(handle, OS.HORZRES);
+ int height = OS.GetDeviceCaps(handle, OS.VERTRES);
+ return new Rectangle(0, 0, width, height);
+}
+
+/**
+ * Given a client area (as described by the arguments),
+ * returns a rectangle, relative to the client area's coordinates,
+ * that is the client area expanded by the printer's trim (or minimum margins).
+ *
+ *
+ *
+ * @param x the x coordinate of the client area
+ * @param y the y coordinate of the client area
+ * @param width the width of the client area
+ * @param height the height of the client area
+ * @return a rectangle, relative to the client area's coordinates, that is
+ * the client area expanded by the printer's trim (or minimum margins)
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getBounds
+ * @see #getClientArea
+ */
+public Rectangle computeTrim(int x, int y, int width, int height) {
+ checkDevice();
+ int printX = -OS.GetDeviceCaps(handle, OS.PHYSICALOFFSETX);
+ int printY = -OS.GetDeviceCaps(handle, OS.PHYSICALOFFSETY);
+ int printWidth = OS.GetDeviceCaps(handle, OS.HORZRES);
+ int printHeight = OS.GetDeviceCaps(handle, OS.VERTRES);
+ int paperWidth = OS.GetDeviceCaps(handle, OS.PHYSICALWIDTH);
+ int paperHeight = OS.GetDeviceCaps(handle, OS.PHYSICALHEIGHT);
+ int hTrim = paperWidth - printWidth;
+ int vTrim = paperHeight - printHeight;
+ return new Rectangle(x + printX, y + printY, width + hTrim, height + vTrim);
+}
+
+/**
+ * Returns a PrinterData
object representing the
+ * target printer for this print job.
+ *
+ * @return a PrinterData object describing the receiver
+ */
+public PrinterData getPrinterData() {
+ return data;
+}
+
+/**
+ * Checks the validity of this device.
+ *
+ * @exception SWTException
+ *
+ */
+@Override
+protected void checkDevice() {
+ if (handle == 0) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
+}
+
+/**
+ * Releases any internal state prior to destroying this printer.
+ * This method is called internally by the dispose
+ * mechanism of the Device
class.
+ */
+@Override
+protected void release() {
+ super.release();
+ data = null;
+}
+
+/**
+ * Destroys the printer handle.
+ * This method is called internally by the dispose
+ * mechanism of the Device
class.
+ */
+@Override
+protected void destroy() {
+ if (handle != 0) OS.DeleteDC(handle);
+ handle = 0;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/PrinterData.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/PrinterData.java
new file mode 100644
index 000000000..3f8ce5ff1
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/PrinterData.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.printing;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class are descriptions of a print job
+ * in terms of the printer, and the scope and type of printing
+ * that is desired. For example, the number of pages and copies
+ * can be specified, as well as whether or not the print job
+ * should go to a file.
+ * dispose()
method is provided.
+ *
+ *
+ */
+ public int scope = ALL_PAGES;
+
+ /**
+ * the start page of a page range, used when scope is PAGE_RANGE.
+ * This value can be from 1 to the maximum number of pages for the platform.
+ */
+ public int startPage = 1;
+
+ /**
+ * the end page of a page range, used when scope is PAGE_RANGE.
+ * This value can be from 1 to the maximum number of pages for the platform.
+ */
+ public int endPage = 1;
+
+ /**
+ * whether or not the print job should go to a file
+ */
+ public boolean printToFile = false;
+
+ /**
+ * the name of the file to print to if printToFile is true.
+ * Note that this field is ignored if printToFile is false.
+ */
+ public String fileName;
+
+ /**
+ * the number of copies to print.
+ * Note that this field may be controlled by the printer driver
+ * In other words, the printer itself may be capable of printing
+ * multiple copies, and if so, the value of this field will always be 1.
+ */
+ public int copyCount = 1;
+
+ /**
+ * whether or not the printer should collate the printed paper
+ * Note that this field may be controlled by the printer driver.
+ * In other words, the printer itself may be capable of doing the
+ * collation, and if so, the value of this field will always be false.
+ */
+ public boolean collate = false;
+
+ /**
+ * The orientation of the paper, which can be either PORTRAIT
+ * or LANDSCAPE.
+ *
+ * @since 3.5
+ */
+ public int orientation = PORTRAIT;
+
+ /**
+ * Single-sided or double-sided printing, expressed as one of the
+ * following values:
+ * ALL_PAGES
PAGE_RANGE
SELECTION
+ *
+ * SWT.DEFAULT
DUPLEX_NONE
DUPLEX_LONG_EDGE
DUPLEX_SHORT_EDGE
SWT.DEFAULT
, meaning do not set a value;
+ * use the printer's default duplex setting.
+ * A printer's default value is typically single-sided,
+ * however it can default to double-sided in order to save paper.
+ * scope
field value indicating that
+ * all pages should be printed
+ */
+ public static final int ALL_PAGES = 0;
+
+ /**
+ * scope
field value indicating that
+ * the range of pages specified by startPage and endPage
+ * should be printed
+ */
+ public static final int PAGE_RANGE = 1;
+
+ /**
+ * scope
field value indicating that
+ * the current selection should be printed
+ */
+ public static final int SELECTION = 2;
+
+ /**
+ * orientation
field value indicating
+ * portrait paper orientation
+ *
+ * @since 3.5
+ */
+ public static final int PORTRAIT = 1;
+
+ /**
+ * orientation
field value indicating
+ * landscape paper orientation
+ *
+ * @since 3.5
+ */
+ public static final int LANDSCAPE = 2;
+
+ /**
+ * duplex
field value indicating
+ * single-sided printing.
+ * duplex
field value indicating
+ * double-sided printing for binding on the long edge.
+ * duplex
field value indicating
+ * double-sided printing for binding on the short edge.
+ * PrintDialog
.
+ * On GTK, this contains a copy of the print_settings and page_setup
+ * returned from the PrintDialog
.
+ * On OS X Cocoa, this contains a copy of the PrintSettings and PageFormat
+ * returned from the PrintDialog
.
+ * This field is not currently used on the X/Window System.
+ */
+ byte [] otherData;
+
+ /**
+ * Constructs an instance of this class that can be
+ * used to print to the default printer.
+ *
+ * @see Printer#getDefaultPrinterData
+ */
+ public PrinterData() {
+ }
+
+ /**
+ * Constructs an instance of this class with the given
+ * printer driver and printer name.
+ *
+ * @param driver the printer driver for the printer
+ * @param name the name of the printer
+ *
+ * @see #driver
+ * @see #name
+ */
+ public PrinterData(String driver, String name) {
+ this.driver = driver;
+ this.name = name;
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+ @Override
+ public String toString() {
+ return "PrinterData {" + "driver = " + driver + ", name = " + name + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/package.html b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/package.html
new file mode 100644
index 000000000..4de089197
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/package.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+Package Specification
+This package contains the classes which provide printing support for SWT.
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/program/Program.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/program/Program.java
new file mode 100644
index 000000000..dd390980c
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/program/Program.java
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.program;
+
+import java.util.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent programs and
+ * their associated file extensions in the operating
+ * system.
+ *
+ * @see Program snippets
+ * @see Sample code and further information
+ */
+public final class Program {
+ String name;
+ String command;
+ String iconName;
+ String extension;
+ static final String [] ARGUMENTS = new String [] {"%1", "%l", "%L"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+Program () {
+}
+
+static String assocQueryString (int assocStr, TCHAR key, boolean expand) {
+ TCHAR pszOut = new TCHAR(0, 1024);
+ int[] pcchOut = new int[1];
+ pcchOut[0] = pszOut.length();
+ int flags = OS.ASSOCF_NOTRUNCATE | OS.ASSOCF_INIT_IGNOREUNKNOWN;
+ int result = OS.AssocQueryString (flags, assocStr, key, null, pszOut, pcchOut);
+ if (result == OS.E_POINTER) {
+ pszOut = new TCHAR(0, pcchOut [0]);
+ result = OS.AssocQueryString (flags, assocStr, key, null, pszOut, pcchOut);
+ }
+ if (result == 0) {
+ if (expand) {
+ int length = OS.ExpandEnvironmentStrings (pszOut, null, 0);
+ if (length != 0) {
+ TCHAR lpDst = new TCHAR (0, length);
+ OS.ExpandEnvironmentStrings (pszOut, lpDst, length);
+ return lpDst.toString (0, Math.max (0, length - 1));
+ } else {
+ return "";
+ }
+ } else {
+ return pszOut.toString (0, Math.max (0, pcchOut [0] - 1));
+ }
+ }
+ return null;
+}
+
+/**
+ * Finds the program that is associated with an extension.
+ * The extension may or may not begin with a '.'. Note that
+ * a Display
must already exist to guarantee that
+ * this method returns an appropriate result.
+ *
+ * @param extension the program extension
+ * @return the program or null
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public static Program findProgram (String extension) {
+ if (extension == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (extension.length () == 0) return null;
+ if (extension.charAt (0) != '.') extension = "." + extension; //$NON-NLS-1$
+ /* Use the character encoding for the default locale */
+ TCHAR key = new TCHAR (0, extension, true);
+ Program program = null;
+ String command = assocQueryString (OS.ASSOCSTR_COMMAND, key, true);
+ if (command != null) {
+ String name = null;
+ if (name == null) name = assocQueryString (OS.ASSOCSTR_FRIENDLYDOCNAME, key, false);
+ if (name == null) name = assocQueryString (OS.ASSOCSTR_FRIENDLYAPPNAME, key, false);
+ if (name == null) name = "";
+ String iconName = assocQueryString (OS.ASSOCSTR_DEFAULTICON, key, true);
+ if (iconName == null) iconName = "";
+ program = new Program ();
+ program.name = name;
+ program.command = command;
+ program.iconName = iconName;
+ program.extension = extension;
+ }
+ return program;
+}
+
+/**
+ * Answer all program extensions in the operating system. Note
+ * that a Display
must already exist to guarantee
+ * that this method returns an appropriate result.
+ *
+ * @return an array of extensions
+ */
+public static String [] getExtensions () {
+ String [] extensions = new String [1024];
+ char [] lpName = new char [1024];
+ int [] lpcName = {lpName.length};
+ FILETIME ft = new FILETIME ();
+ int dwIndex = 0, count = 0;
+ while (OS.RegEnumKeyEx (OS.HKEY_CLASSES_ROOT, dwIndex, lpName, lpcName, null, null, null, ft) != OS.ERROR_NO_MORE_ITEMS) {
+ String extension = new String (lpName, 0, lpcName [0]);
+ lpcName [0] = lpName.length;
+ if (extension.length () > 0 && extension.charAt (0) == '.') {
+ if (count == extensions.length) {
+ String [] newExtensions = new String [extensions.length + 1024];
+ System.arraycopy (extensions, 0, newExtensions, 0, extensions.length);
+ extensions = newExtensions;
+ }
+ extensions [count++] = extension;
+ }
+ dwIndex++;
+ }
+ if (count != extensions.length) {
+ String [] newExtension = new String [count];
+ System.arraycopy (extensions, 0, newExtension, 0, count);
+ extensions = newExtension;
+ }
+ return extensions;
+}
+
+static String getKeyValue (String string, boolean expand) {
+ /* Use the character encoding for the default locale */
+ TCHAR key = new TCHAR (0, string, true);
+ long [] phkResult = new long [1];
+ if (OS.RegOpenKeyEx (OS.HKEY_CLASSES_ROOT, key, 0, OS.KEY_READ, phkResult) != 0) {
+ return null;
+ }
+ String result = null;
+ int [] lpcbData = new int [1];
+ if (OS.RegQueryValueEx (phkResult [0], (TCHAR) null, 0, null, (TCHAR) null, lpcbData) == 0) {
+ result = "";
+ int length = lpcbData [0] / TCHAR.sizeof;
+ /*
+ * Crash is seen when the size of REG_SZ entry in HKEY_CLASSES_ROOT
+ * is not multiple of a Unicode byte length. The REG_SZ entry in
+ * Windows registry may not have been stored with the proper
+ * terminating null characters: e.g. non null terminated string or a
+ * single byte null terminated. Refer below MSDN article on this:
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms724884
+ * %28v=vs.85%29.aspx Hence solution is to adjust the buffer length
+ * accordingly. Refer Bug 157010 for more details.
+ */
+ if (lpcbData [0] % TCHAR.sizeof != 0) {
+ length++;
+ }
+ if (length != 0) {
+ char [] lpData = new char [length];
+ if (OS.RegQueryValueEx (phkResult [0], null, 0, null, lpData, lpcbData) == 0) {
+ if (expand) {
+ length = OS.ExpandEnvironmentStrings (lpData, null, 0);
+ if (length != 0) {
+ char [] lpDst = new char [length];
+ OS.ExpandEnvironmentStrings (lpData, lpDst, length);
+ result = new String (lpDst, 0, length - 1);
+ }
+ } else {
+ result = new String (lpData, 0, length - 1);
+ }
+ }
+ }
+ }
+ if (phkResult [0] != 0) OS.RegCloseKey (phkResult [0]);
+ return result;
+}
+
+static Program getProgram (String key, String extension) {
+
+ /* Name */
+ String name = getKeyValue (key, false);
+ if (name == null || name.length () == 0) {
+ name = key;
+ }
+
+ /* Command */
+ String DEFAULT_COMMAND = "\\shell"; //$NON-NLS-1$
+ String defaultCommand = getKeyValue (key + DEFAULT_COMMAND, true);
+ if (defaultCommand == null || defaultCommand.length() == 0) defaultCommand = "open"; //$NON-NLS-1$
+ String COMMAND = "\\shell\\" + defaultCommand + "\\command"; //$NON-NLS-1$
+ String command = getKeyValue (key + COMMAND, true);
+ if (command == null || command.length () == 0) return null;
+
+ /* Icon */
+ String DEFAULT_ICON = "\\DefaultIcon"; //$NON-NLS-1$
+ String iconName = getKeyValue (key + DEFAULT_ICON, true);
+ if (iconName == null) iconName = ""; //$NON-NLS-1$
+
+ /* Program */
+ Program program = new Program ();
+ program.name = name;
+ program.command = command;
+ program.iconName = iconName;
+ program.extension = extension;
+ return program;
+}
+
+/**
+ * Answers all available programs in the operating system. Note
+ * that a Display
must already exist to guarantee
+ * that this method returns an appropriate result.
+ *
+ * @return an array of programs
+ */
+public static Program [] getPrograms () {
+ LinkedHashSetDisplay
must already
+ * exist to guarantee that this method returns an appropriate result.
+ *
+ * @param fileName the file or program name or URL (http:// or https://)
+ * @return true
if the file is launched, otherwise false
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public static boolean launch (String fileName) {
+ return launch(fileName, null);
+}
+
+/**
+ * Launches the operating system executable associated with the file or
+ * URL (http:// or https://). If the file is an executable then the
+ * executable is launched. The program is launched with the specified
+ * working directory only when the workingDir
exists and
+ * fileName
is an executable.
+ * Note that a Display
must already exist to guarantee
+ * that this method returns an appropriate result.
+ *
+ * @param fileName the file name or program name or URL (http:// or https://)
+ * @param workingDir the name of the working directory or null
+ * @return true
if the file is launched, otherwise false
+ *
+ * @exception IllegalArgumentException
+ *
+ *
+ * @since 3.6
+ */
+public static boolean launch (String fileName, String workingDir) {
+ if (fileName == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+
+ /* Use the character encoding for the default locale */
+ long hHeap = OS.GetProcessHeap ();
+ TCHAR buffer = new TCHAR (0, fileName, true);
+ int byteCount = buffer.length () * TCHAR.sizeof;
+ long lpFile = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory (lpFile, buffer, byteCount);
+
+ long lpDirectory = 0;
+ if (workingDir != null && OS.PathIsExe(lpFile)) {
+ TCHAR buffer1 = new TCHAR (0, workingDir, true);
+ byteCount = buffer1.length () * TCHAR.sizeof;
+ lpDirectory = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory (lpDirectory, buffer1, byteCount);
+ }
+
+ SHELLEXECUTEINFO info = new SHELLEXECUTEINFO ();
+ info.cbSize = SHELLEXECUTEINFO.sizeof;
+ info.lpFile = lpFile;
+ info.lpDirectory = lpDirectory;
+ info.nShow = OS.SW_SHOW;
+ boolean result = OS.ShellExecuteEx (info);
+ if (lpFile != 0) OS.HeapFree (hHeap, 0, lpFile);
+ if (lpDirectory != 0) OS.HeapFree (hHeap, 0, lpDirectory);
+ return result;
+}
+
+/**
+ * Executes the program with the file as the single argument
+ * in the operating system. It is the responsibility of the
+ * programmer to ensure that the file contains valid data for
+ * this program.
+ *
+ * @param fileName the file or program name
+ * @return true
if the file is launched, otherwise false
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public boolean execute (String fileName) {
+ if (fileName == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ int index = 0;
+ boolean append = true;
+ String prefix = command, suffix = ""; //$NON-NLS-1$
+ while (index < ARGUMENTS.length) {
+ int i = command.indexOf (ARGUMENTS [index]);
+ if (i != -1) {
+ append = false;
+ prefix = command.substring (0, i);
+ suffix = command.substring (i + ARGUMENTS [index].length (), command.length ());
+ break;
+ }
+ index++;
+ }
+ if (append) fileName = " \"" + fileName + "\"";
+ String commandLine = prefix + fileName + suffix;
+ long hHeap = OS.GetProcessHeap ();
+ /* Use the character encoding for the default locale */
+ TCHAR buffer = new TCHAR (0, commandLine, true);
+ int byteCount = buffer.length () * TCHAR.sizeof;
+ long lpCommandLine = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory (lpCommandLine, buffer, byteCount);
+ STARTUPINFO lpStartupInfo = new STARTUPINFO ();
+ lpStartupInfo.cb = STARTUPINFO.sizeof;
+ PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION ();
+ boolean success = OS.CreateProcess (0, lpCommandLine, 0, 0, false, 0, 0, 0, lpStartupInfo, lpProcessInformation);
+ if (lpCommandLine != 0) OS.HeapFree (hHeap, 0, lpCommandLine);
+ if (lpProcessInformation.hProcess != 0) OS.CloseHandle (lpProcessInformation.hProcess);
+ if (lpProcessInformation.hThread != 0) OS.CloseHandle (lpProcessInformation.hThread);
+ return success;
+}
+
+/**
+ * Returns the receiver's image data. This is the icon
+ * that is associated with the receiver in the operating
+ * system.
+ *
+ * @return the image data for the program, may be null
+ */
+public ImageData getImageData () {
+ if (extension != null) {
+ SHFILEINFO shfi = new SHFILEINFO ();
+ int flags = OS.SHGFI_ICON | OS.SHGFI_SMALLICON | OS.SHGFI_USEFILEATTRIBUTES;
+ TCHAR pszPath = new TCHAR (0, extension, true);
+ OS.SHGetFileInfo (pszPath.chars, OS.FILE_ATTRIBUTE_NORMAL, shfi, SHFILEINFO.sizeof, flags);
+ if (shfi.hIcon != 0) {
+ Image image = Image.win32_new (null, SWT.ICON, shfi.hIcon);
+ /* Fetch the ImageData at 100% zoom and return */
+ ImageData imageData = image.getImageData ();
+ image.dispose ();
+ return imageData;
+ }
+ }
+ int nIconIndex = 0;
+ String fileName = iconName;
+ int index = iconName.indexOf (',');
+ if (index != -1) {
+ fileName = iconName.substring (0, index);
+ String iconIndex = iconName.substring (index + 1, iconName.length ()).trim ();
+ try {
+ nIconIndex = Integer.parseInt (iconIndex);
+ } catch (NumberFormatException e) {}
+ }
+ int length = fileName.length ();
+ if (length > 1 && fileName.charAt (0) == '\"') {
+ if (fileName.charAt (length - 1) == '\"') {
+ fileName = fileName.substring (1, length - 1);
+ }
+ }
+ /* Use the character encoding for the default locale */
+ TCHAR lpszFile = new TCHAR (0, fileName, true);
+ long [] phiconSmall = new long[1], phiconLarge = null;
+ OS.ExtractIconEx (lpszFile, nIconIndex, phiconLarge, phiconSmall, 1);
+ if (phiconSmall [0] == 0) return null;
+ Image image = Image.win32_new (null, SWT.ICON, phiconSmall [0]);
+ /* Fetch the ImageData at 100% zoom and return */
+ ImageData imageData = image.getImageData ();
+ image.dispose ();
+ return imageData;
+}
+
+/**
+ * Returns the receiver's name. This is as short and
+ * descriptive a name as possible for the program. If
+ * the program has no descriptive name, this string may
+ * be the executable name, path or empty.
+ *
+ * @return the name of the program
+ */
+public String getName () {
+ return name;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the same object using a class
+ * specific comparison.
+ *
+ * @param other the object to compare with this object
+ * @return true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals(Object other) {
+ if (this == other) return true;
+ if (other instanceof Program) {
+ final Program program = (Program) other;
+ return name.equals(program.name) && command.equals(program.command)
+ && iconName.equals(program.iconName);
+ }
+ return false;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ */
+@Override
+public int hashCode() {
+ return name.hashCode() ^ command.hashCode() ^ iconName.hashCode();
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the program
+ */
+@Override
+public String toString () {
+ return "Program {" + name + "}"; //$NON-NLS-1$ //$NON-NLS-2$
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/program/package.html b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/program/package.html
new file mode 100644
index 000000000..99d655607
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/program/package.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+Package Specification
+This package contains class Program
which provides access to facilities for
+discovering operating system specific aspects of external program launching.
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Button.java
new file mode 100644
index 000000000..feb543a56
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Button.java
@@ -0,0 +1,1493 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Conrad Groth - Bug 23837 [FEEP] Button, do not respect foreground and background color on Windows
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent a selectable user interface object that
+ * issues notification when pressed and released.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#ARROW
+ * @see SWT#CHECK
+ * @see SWT#PUSH
+ * @see SWT#RADIO
+ * @see SWT#TOGGLE
+ * @see SWT#FLAT
+ * @see SWT#UP
+ * @see SWT#DOWN
+ * @see SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Button (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+void _setImage (Image image) {
+ if ((style & SWT.COMMAND) != 0) return;
+ if (imageList != null) imageList.dispose ();
+ imageList = null;
+ if (image != null) {
+ imageList = new ImageList (style & SWT.RIGHT_TO_LEFT);
+ if (OS.IsWindowEnabled (handle)) {
+ imageList.add (image);
+ } else {
+ if (disabledImage != null) disabledImage.dispose ();
+ disabledImage = new Image (display, image, SWT.IMAGE_DISABLE);
+ imageList.add (disabledImage);
+ }
+ BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
+ buttonImageList.himl = imageList.getHandle ();
+ int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
+ newBits &= ~(OS.BS_LEFT | OS.BS_CENTER | OS.BS_RIGHT);
+ if ((style & SWT.LEFT) != 0) newBits |= OS.BS_LEFT;
+ if ((style & SWT.CENTER) != 0) newBits |= OS.BS_CENTER;
+ if ((style & SWT.RIGHT) != 0) newBits |= OS.BS_RIGHT;
+ if (text.length () == 0) {
+ if ((style & SWT.LEFT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
+ if ((style & SWT.CENTER) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_CENTER;
+ if ((style & SWT.RIGHT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_RIGHT;
+ } else {
+ buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
+ buttonImageList.margin_left = computeLeftMargin ();
+ buttonImageList.margin_right = MARGIN;
+ newBits &= ~(OS.BS_CENTER | OS.BS_RIGHT);
+ newBits |= OS.BS_LEFT;
+ }
+ if (newBits != oldBits) {
+ OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
+ OS.InvalidateRect (handle, null, true);
+ }
+ OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
+ } else {
+ OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, 0);
+ }
+ /*
+ * Bug in Windows. Under certain cirumstances yet to be
+ * isolated, BCM_SETIMAGELIST does not redraw the control
+ * when a new image is set. The fix is to force a redraw.
+ */
+ OS.InvalidateRect (handle, null, true);
+}
+
+void _setText (String text) {
+ int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
+ newBits &= ~(OS.BS_LEFT | OS.BS_CENTER | OS.BS_RIGHT);
+ if ((style & SWT.LEFT) != 0) newBits |= OS.BS_LEFT;
+ if ((style & SWT.CENTER) != 0) newBits |= OS.BS_CENTER;
+ if ((style & SWT.RIGHT) != 0) newBits |= OS.BS_RIGHT;
+ if (imageList != null) {
+ BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
+ buttonImageList.himl = imageList.getHandle ();
+ if (text.length () == 0) {
+ if ((style & SWT.LEFT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
+ if ((style & SWT.CENTER) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_CENTER;
+ if ((style & SWT.RIGHT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_RIGHT;
+ } else {
+ buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
+ buttonImageList.margin_left = computeLeftMargin ();
+ buttonImageList.margin_right = MARGIN;
+ newBits &= ~(OS.BS_CENTER | OS.BS_RIGHT);
+ newBits |= OS.BS_LEFT;
+ }
+ OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
+ }
+ if (newBits != oldBits) {
+ OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
+ OS.InvalidateRect (handle, null, true);
+ }
+ /*
+ * Bug in Windows. When a Button control is right-to-left and
+ * is disabled, the first pixel of the text is clipped. The fix
+ * is to append a space to the text.
+ */
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ if (!OS.IsAppThemed ()) {
+ text = OS.IsWindowEnabled (handle) ? text : text + " ";
+ }
+ }
+ TCHAR buffer = new TCHAR (getCodePage (), text, true);
+ OS.SetWindowText (handle, buffer);
+ if ((state & HAS_AUTO_DIRECTION) != 0) {
+ updateTextDirection (AUTO_TEXT_DIRECTION);
+ }
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the control is selected by the user, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called when the control is selected by the user.
+ * widgetDefaultSelected
is not called.
+ * SWT.RADIO
style bit is set, the widgetSelected
method is
+ * also called when the receiver loses selection because another item in the same radio group
+ * was selected by the user. During widgetSelected
the application can use
+ * getSelection()
to determine the current selected state of the receiver.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ return OS.CallWindowProc (ButtonProc, hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ style = checkBits (style, SWT.PUSH, SWT.ARROW, SWT.CHECK, SWT.RADIO, SWT.TOGGLE, COMMAND_LINK ? SWT.COMMAND : 0);
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+ return checkBits (style, SWT.CENTER, SWT.LEFT, SWT.RIGHT, 0, 0, 0);
+ }
+ if ((style & (SWT.CHECK | SWT.RADIO)) != 0) {
+ return checkBits (style, SWT.LEFT, SWT.RIGHT, SWT.CENTER, 0, 0, 0);
+ }
+ if ((style & SWT.ARROW) != 0) {
+ style |= SWT.NO_FOCUS;
+ return checkBits (style, SWT.UP, SWT.DOWN, SWT.LEFT, SWT.RIGHT, 0, 0);
+ }
+ return style;
+}
+
+void click () {
+ /*
+ * Feature in Windows. BM_CLICK sends a fake WM_LBUTTONDOWN and
+ * WM_LBUTTONUP in order to click the button. This causes the
+ * application to get unexpected mouse events. The fix is to
+ * ignore mouse events when they are caused by BM_CLICK.
+ */
+ ignoreMouse = true;
+ OS.SendMessage (handle, OS.BM_CLICK, 0, 0);
+ ignoreMouse = false;
+}
+
+// TODO: this method ignores the style LEFT, CENTER or RIGHT
+int computeLeftMargin () {
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) == 0) return MARGIN;
+ int margin = 0;
+ if (image != null && text.length () != 0) {
+ Rectangle bounds = image.getBoundsInPixels ();
+ margin += bounds.width + MARGIN * 2;
+ long oldFont = 0;
+ long hDC = OS.GetDC (handle);
+ long newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ char [] buffer = text.toCharArray ();
+ RECT rect = new RECT ();
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE;
+ OS.DrawText (hDC, buffer, buffer.length, rect, flags);
+ margin += rect.right - rect.left;
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ OS.GetClientRect (handle, rect);
+ margin = Math.max (MARGIN, (rect.right - rect.left - margin) / 2);
+ }
+ return margin;
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0, border = getBorderWidthInPixels ();
+ if ((style & SWT.ARROW) != 0) {
+ if ((style & (SWT.UP | SWT.DOWN)) != 0) {
+ width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
+ height += OS.GetSystemMetrics (OS.SM_CYVSCROLL);
+ } else {
+ width += OS.GetSystemMetrics (OS.SM_CXHSCROLL);
+ height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
+ }
+ } else {
+ if ((style & SWT.COMMAND) != 0) {
+ SIZE size = new SIZE ();
+ if (wHint != SWT.DEFAULT) {
+ size.cx = wHint;
+ OS.SendMessage (handle, OS.BCM_GETIDEALSIZE, 0, size);
+ width = size.cx;
+ height = size.cy;
+ } else {
+ OS.SendMessage (handle, OS.BCM_GETIDEALSIZE, 0, size);
+ width = size.cy;
+ height = size.cy;
+ size.cy = 0;
+ while (size.cy != height) {
+ size.cx = width++;
+ size.cy = 0;
+ OS.SendMessage (handle, OS.BCM_GETIDEALSIZE, 0, size);
+ }
+ }
+ } else {
+ int extra = 0;
+ boolean hasImage = image != null, hasText = true;
+ if (hasImage) {
+ if (image != null) {
+ Rectangle rect = image.getBoundsInPixels ();
+ width = rect.width;
+ if (hasText && text.length () != 0) {
+ width += MARGIN * 2;
+ }
+ height = rect.height;
+ extra = MARGIN * 2;
+ }
+ }
+ if (hasText) {
+ long oldFont = 0;
+ long hDC = OS.GetDC (handle);
+ long newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ TEXTMETRIC lptm = new TEXTMETRIC ();
+ OS.GetTextMetrics (hDC, lptm);
+ int length = text.length ();
+ if (length == 0) {
+ height = Math.max (height, lptm.tmHeight);
+ } else {
+ extra = Math.max (MARGIN * 2, lptm.tmAveCharWidth);
+ char [] buffer = text.toCharArray ();
+ RECT rect = new RECT ();
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE;
+ if ((style & SWT.WRAP) != 0 && wHint != SWT.DEFAULT) {
+ flags = OS.DT_CALCRECT | OS.DT_WORDBREAK;
+ rect.right = wHint - width - 2 * border;
+ if (isRadioOrCheck()) {
+ rect.right -= CHECK_WIDTH + 3;
+ } else {
+ rect.right -= 6;
+ }
+ if (!OS.IsAppThemed ()) {
+ rect.right -= 2;
+ if (isRadioOrCheck()) {
+ rect.right -= 2;
+ }
+ }
+ }
+ OS.DrawText (hDC, buffer, buffer.length, rect, flags);
+ width += rect.right - rect.left;
+ height = Math.max (height, rect.bottom - rect.top);
+ }
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ }
+ if (isRadioOrCheck()) {
+ width += CHECK_WIDTH + extra;
+ height = Math.max (height, CHECK_HEIGHT + 3);
+ }
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+ width += 12; height += 10;
+ }
+ }
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ width += border * 2;
+ height += border * 2;
+ return new Point (width, height);
+}
+
+@Override
+void createHandle () {
+ /*
+ * Feature in Windows. When a button is created,
+ * it clears the UI state for all controls in the
+ * shell by sending WM_CHANGEUISTATE with UIS_SET,
+ * UISF_HIDEACCEL and UISF_HIDEFOCUS to the parent.
+ * This is undocumented and unexpected. The fix
+ * is to ignore the WM_CHANGEUISTATE, when sent
+ * from CreateWindowEx().
+ */
+ parent.state |= IGNORE_WM_CHANGEUISTATE;
+ super.createHandle ();
+ parent.state &= ~IGNORE_WM_CHANGEUISTATE;
+
+ if (OS.IsAppThemed ()) {
+ /* Set the theme background.
+ *
+ * NOTE: On Vista this causes problems when the tab
+ * key is pressed for push buttons so disable the
+ * theme background drawing for these widgets for
+ * now.
+ */
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) == 0) {
+ state |= THEME_BACKGROUND;
+ }
+
+ /*
+ * Bug in Windows. For some reason, the HBRUSH that
+ * is returned from WM_CTRLCOLOR is misaligned when
+ * the button uses it to draw. If the brush is a solid
+ * color, this does not matter. However, if the brush
+ * contains an image, the image is misaligned. The
+ * fix is to draw the background in WM_CTRLCOLOR.
+ *
+ * NOTE: For comctl32.dll 6.0 with themes disabled,
+ * drawing in WM_ERASEBKGND will draw on top of the
+ * text of the control.
+ */
+ if ((style & SWT.RADIO) != 0) {
+ state |= DRAW_BACKGROUND;
+ }
+ }
+}
+
+private boolean customBackgroundDrawing() {
+ return buttonBackground != -1 && !isRadioOrCheck();
+}
+
+private boolean customDrawing() {
+ return customBackgroundDrawing() || customForegroundDrawing();
+}
+
+private boolean customForegroundDrawing() {
+ return foreground != -1 && !text.isEmpty() && OS.IsWindowEnabled(handle);
+}
+
+@Override
+int defaultBackground () {
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+ return OS.GetSysColor (OS.COLOR_BTNFACE);
+ }
+ return super.defaultBackground ();
+}
+
+@Override
+int defaultForeground () {
+ return OS.GetSysColor (OS.COLOR_BTNTEXT);
+}
+
+@Override
+void enableWidget (boolean enabled) {
+ super.enableWidget (enabled);
+ /*
+ * Bug in Windows. When a Button control is right-to-left and
+ * is disabled, the first pixel of the text is clipped. The fix
+ * is to append a space to the text.
+ */
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ if (!OS.IsAppThemed ()) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ boolean hasImage = (bits & (OS.BS_BITMAP | OS.BS_ICON)) != 0;
+ if (!hasImage) {
+ String string = enabled ? text : text + " ";
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ OS.SetWindowText (handle, buffer);
+ }
+ }
+ }
+ /*
+ * Bug in Windows. When a button has the style BS_CHECKBOX
+ * or BS_RADIOBUTTON, is checked, and is displaying both an
+ * image and some text, when BCM_SETIMAGELIST is used to
+ * assign an image list for each of the button states, the
+ * button does not draw properly. When the user drags the
+ * mouse in and out of the button, it draws using a blank
+ * image. The fix is to set the complete image list only
+ * when the button is disabled.
+ */
+ updateImageList ();
+}
+
+/**
+ * Returns a value which describes the position of the
+ * text or image in the receiver. The value will be one of
+ * LEFT
, RIGHT
or CENTER
+ * unless the receiver is an ARROW
button, in
+ * which case, the alignment will indicate the direction of
+ * the arrow (one of LEFT
, RIGHT
,
+ * UP
or DOWN
).
+ *
+ * @return the alignment
+ *
+ * @exception SWTException
+ *
+ */
+public int getAlignment () {
+ checkWidget ();
+ if ((style & SWT.ARROW) != 0) {
+ if ((style & SWT.UP) != 0) return SWT.UP;
+ if ((style & SWT.DOWN) != 0) return SWT.DOWN;
+ if ((style & SWT.LEFT) != 0) return SWT.LEFT;
+ if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
+ return SWT.UP;
+ }
+ if ((style & SWT.LEFT) != 0) return SWT.LEFT;
+ if ((style & SWT.CENTER) != 0) return SWT.CENTER;
+ if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
+ return SWT.LEFT;
+}
+
+@Override
+public Color getBackground () {
+ if (isRadioOrCheck()) {
+ return super.getBackground();
+ }
+ checkWidget ();
+ if (buttonBackground != -1) {
+ return Color.win32_new (display, buttonBackground, buttonBackgroundAlpha);
+ }
+ return Color.win32_new (display, defaultBackground());
+}
+
+boolean getDefault () {
+ if ((style & SWT.PUSH) == 0) return false;
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ return (bits & OS.BS_DEFPUSHBUTTON) != 0;
+}
+
+/**
+ * Returns true
if the receiver is grayed,
+ * and false otherwise. When the widget does not have
+ * the CHECK
style, return false.
+ *
+ * @return the grayed state of the checkbox
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public boolean getGrayed () {
+ checkWidget();
+ if ((style & SWT.CHECK) == 0) return false;
+ return grayed;
+}
+
+/**
+ * Returns the receiver's image if it has one, or null
+ * if it does not.
+ *
+ * @return the receiver's image
+ *
+ * @exception SWTException
+ *
+ */
+public Image getImage () {
+ checkWidget ();
+ return image;
+}
+
+/**
+ * Returns the widget message. When the widget is created
+ * with the style SWT.COMMAND
, the message text
+ * is displayed to provide further information for the user.
+ *
+ * @return the widget message
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.3
+ */
+/*public*/ String getMessage () {
+ checkWidget ();
+ return message;
+}
+
+@Override
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns true
if the receiver is selected,
+ * and false otherwise.
+ * CHECK
or RADIO
,
+ * it is selected when it is checked. When it is of type TOGGLE
,
+ * it is selected when it is pushed in. If the receiver is of any other type,
+ * this method returns false.
+ *
+ * @return the selection state
+ *
+ * @exception SWTException
+ *
+ */
+public boolean getSelection () {
+ checkWidget ();
+ if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return false;
+ return isChecked();
+}
+
+/**
+ * Returns the receiver's text, which will be an empty
+ * string if it has never been set or if the receiver is
+ * an ARROW
button.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException
+ *
+ */
+public String getText () {
+ checkWidget ();
+ if ((style & SWT.ARROW) != 0) return "";
+ return text;
+}
+
+private boolean isChecked() {
+ long flags = OS.SendMessage (handle, OS.BM_GETCHECK, 0, 0);
+ return flags != OS.BST_UNCHECKED;
+}
+
+private boolean isRadioOrCheck() {
+ return (style & (SWT.RADIO | SWT.CHECK)) != 0;
+}
+
+@Override
+boolean isTabItem () {
+ if ((style & SWT.PUSH) != 0) return isTabGroup ();
+ return super.isTabItem ();
+}
+
+@Override
+boolean mnemonicHit (char ch) {
+ if (!setFocus ()) return false;
+ /*
+ * Feature in Windows. When a radio button gets focus,
+ * it selects the button in WM_SETFOCUS. Therefore, it
+ * is not necessary to click the button or send events
+ * because this has already happened in WM_SETFOCUS.
+ */
+ if ((style & SWT.RADIO) == 0) click ();
+ return true;
+}
+
+@Override
+boolean mnemonicMatch (char key) {
+ char mnemonic = findMnemonic (getText ());
+ if (mnemonic == '\0') return false;
+ return Character.toUpperCase (key) == Character.toUpperCase (mnemonic);
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ if (imageList != null) imageList.dispose ();
+ imageList = null;
+ if (disabledImage != null) disabledImage.dispose ();
+ disabledImage = null;
+ if (image2 != null) image2.dispose ();
+ image2 = null;
+ text = null;
+ image = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+@Override
+int resolveTextDirection() {
+ return (style & SWT.ARROW) != 0 ? SWT.NONE : BidiUtil.resolveTextDirection(text);
+}
+
+void selectRadio () {
+ /*
+ * This code is intentionally commented. When two groups
+ * of radio buttons with the same parent are separated by
+ * another control, the correct behavior should be that
+ * the two groups act independently. This is consistent
+ * with radio tool and menu items. The commented code
+ * implements this behavior.
+ */
+// int index = 0;
+// Control [] children = parent._getChildren ();
+// while (index < children.length && children [index] != this) index++;
+// int i = index - 1;
+// while (i >= 0 && children [i].setRadioSelection (false)) --i;
+// int j = index + 1;
+// while (j < children.length && children [j].setRadioSelection (false)) j++;
+// setSelection (true);
+ Control [] children = parent._getChildren ();
+ for (int i=0; iRIGHT
or CENTER
+ * unless the receiver is an ARROW
button, in
+ * which case, the argument indicates the direction of
+ * the arrow (one of LEFT
, RIGHT
,
+ * UP
or DOWN
).
+ *
+ * @param alignment the new alignment
+ *
+ * @exception SWTException
+ *
+ */
+public void setAlignment (int alignment) {
+ checkWidget ();
+ if ((style & SWT.ARROW) != 0) {
+ if ((style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) == 0) return;
+ style &= ~(SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
+ style |= alignment & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
+ OS.InvalidateRect (handle, null, true);
+ return;
+ }
+ if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
+ style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
+ newBits &= ~(OS.BS_LEFT | OS.BS_CENTER | OS.BS_RIGHT);
+ if ((style & SWT.LEFT) != 0) newBits |= OS.BS_LEFT;
+ if ((style & SWT.CENTER) != 0) newBits |= OS.BS_CENTER;
+ if ((style & SWT.RIGHT) != 0) newBits |= OS.BS_RIGHT;
+ if (imageList != null) {
+ BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
+ buttonImageList.himl = imageList.getHandle ();
+ if (text.length () == 0) {
+ if ((style & SWT.LEFT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
+ if ((style & SWT.CENTER) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_CENTER;
+ if ((style & SWT.RIGHT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_RIGHT;
+ } else {
+ buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
+ buttonImageList.margin_left = computeLeftMargin ();
+ buttonImageList.margin_right = MARGIN;
+ newBits &= ~(OS.BS_CENTER | OS.BS_RIGHT);
+ newBits |= OS.BS_LEFT;
+ }
+ OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
+ }
+ if (newBits != oldBits) {
+ OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
+ OS.InvalidateRect (handle, null, true);
+ }
+}
+
+/**
+ * Sets the button's background color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+@Override
+public void setBackground (Color color) {
+ checkWidget ();
+ if (isRadioOrCheck()) {
+ super.setBackground(color);
+ } else {
+ setButtonBackground (color);
+ }
+}
+
+private void setButtonBackground (Color color) {
+ int pixel = -1;
+ int alpha = 255;
+ if (color != null) {
+ if (color.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ pixel = color.handle;
+ alpha = color.getAlpha();
+ }
+ if (pixel == buttonBackground && alpha == buttonBackgroundAlpha) return;
+ buttonBackground = pixel;
+ buttonBackgroundAlpha = alpha;
+ updateBackgroundColor ();
+}
+
+void setDefault (boolean value) {
+ if ((style & SWT.PUSH) == 0) return;
+ long hwndShell = menuShell ().handle;
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if (value) {
+ bits |= OS.BS_DEFPUSHBUTTON;
+ OS.SendMessage (hwndShell, OS.DM_SETDEFID, handle, 0);
+ } else {
+ bits &= ~OS.BS_DEFPUSHBUTTON;
+ OS.SendMessage (hwndShell, OS.DM_SETDEFID, 0, 0);
+ }
+ OS.SendMessage (handle, OS.BM_SETSTYLE, bits, 1);
+}
+
+@Override
+public boolean setFocus () {
+ checkWidget ();
+ /*
+ * Feature in Windows. When a radio button gets focus,
+ * it selects the button in WM_SETFOCUS. The fix is to
+ * not assign focus to an unselected radio button.
+ */
+ if ((style & SWT.RADIO) != 0 && !isChecked () && display.fixFocus) return false;
+ return super.setFocus ();
+}
+
+/**
+ * Sets the receiver's image to the argument, which may be
+ * null
indicating that no image should be displayed.
+ * null
)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setImage (Image image) {
+ checkWidget ();
+ if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((style & SWT.ARROW) != 0) return;
+ this.image = image;
+ /* This code is intentionally commented */
+// if (OS.COMCTL32_MAJOR < 6) {
+// if (image == null || text.length () != 0) {
+// _setText (text);
+// return;
+// }
+// }
+ _setImage (image);
+}
+
+/**
+ * Sets the grayed state of the receiver. This state change
+ * only applies if the control was created with the SWT.CHECK
+ * style.
+ *
+ * @param grayed the new grayed state
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public void setGrayed (boolean grayed) {
+ checkWidget ();
+ if ((style & SWT.CHECK) == 0) return;
+ this.grayed = grayed;
+ long flags = OS.SendMessage (handle, OS.BM_GETCHECK, 0, 0);
+ if (grayed) {
+ if (flags == OS.BST_CHECKED) updateSelection (OS.BST_INDETERMINATE);
+ } else {
+ if (flags == OS.BST_INDETERMINATE) updateSelection (OS.BST_CHECKED);
+ }
+}
+
+/**
+ * Sets the widget message. When the widget is created
+ * with the style SWT.COMMAND
, the message text
+ * is displayed to provide further information for the user.
+ *
+ * @param message the new message
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.3
+ */
+/*public*/ void setMessage (String message) {
+ checkWidget ();
+ if (message == null) error (SWT.ERROR_NULL_ARGUMENT);
+ this.message = message;
+ if ((style & SWT.COMMAND) != 0) {
+ int length = message.length ();
+ char [] chars = new char [length + 1];
+ message.getChars(0, length, chars, 0);
+ OS.SendMessage (handle, OS.BCM_SETNOTE, 0, chars);
+ }
+}
+
+@Override
+boolean setRadioFocus (boolean tabbing) {
+ if ((style & SWT.RADIO) == 0 || !getSelection ()) return false;
+ return tabbing ? setTabItemFocus () : setFocus ();
+}
+
+@Override
+boolean setRadioSelection (boolean value) {
+ if ((style & SWT.RADIO) == 0) return false;
+ if (getSelection () != value) {
+ setSelection (value);
+ sendSelectionEvent (SWT.Selection);
+ }
+ return true;
+}
+
+/**
+ * Sets the selection state of the receiver, if it is of type CHECK
,
+ * RADIO
, or TOGGLE
.
+ *
+ * CHECK
or RADIO
,
+ * it is selected when it is checked. When it is of type TOGGLE
,
+ * it is selected when it is pushed in.
+ *
+ * @param selected the new selection state
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (boolean selected) {
+ checkWidget ();
+ if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return;
+ int flags = selected ? OS.BST_CHECKED : OS.BST_UNCHECKED;
+ if ((style & SWT.CHECK) != 0) {
+ if (selected && grayed) flags = OS.BST_INDETERMINATE;
+ }
+ updateSelection (flags);
+}
+
+/**
+ * Sets the receiver's text.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((style & SWT.ARROW) != 0) return;
+ text = string;
+ /* This code is intentionally commented */
+// if (OS.COMCTL32_MAJOR < 6) {
+// if (text.length () == 0 && image != null) {
+// _setImage (image);
+// return;
+// }
+// }
+ _setText (string);
+}
+
+@Override
+boolean updateTextDirection(int textDirection) {
+ if (super.updateTextDirection(textDirection)) {
+// TODO: Keep for now, to follow up
+// int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT;
+// style &= ~SWT.MIRRORED;
+// style &= ~flags;
+// style |= textDirection & flags;
+// updateOrientation ();
+// checkMirrored ();
+ return true;
+ }
+ return false;
+}
+
+void updateImageList () {
+ if (imageList != null) {
+ BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
+ OS.SendMessage (handle, OS.BCM_GETIMAGELIST, 0, buttonImageList);
+ if (imageList != null) imageList.dispose ();
+ imageList = new ImageList (style & SWT.RIGHT_TO_LEFT);
+ if (OS.IsWindowEnabled (handle)) {
+ imageList.add (image);
+ } else {
+ if (disabledImage != null) disabledImage.dispose ();
+ disabledImage = new Image (display, image, SWT.IMAGE_DISABLE);
+ imageList.add (disabledImage);
+ }
+ buttonImageList.himl = imageList.getHandle ();
+ OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
+ /*
+ * Bug in Windows. Under certain cirumstances yet to be
+ * isolated, BCM_SETIMAGELIST does not redraw the control
+ * when an image is set. The fix is to force a redraw.
+ */
+ OS.InvalidateRect (handle, null, true);
+ }
+}
+
+@Override
+void updateOrientation () {
+ super.updateOrientation ();
+ updateImageList ();
+}
+
+void updateSelection (int flags) {
+ if (flags != OS.SendMessage (handle, OS.BM_GETCHECK, 0, 0)) {
+ /*
+ * Feature in Windows. When BM_SETCHECK is used
+ * to set the checked state of a radio or check
+ * button, it sets the WS_TABSTOP style. This
+ * is undocumented and unwanted. The fix is
+ * to save and restore the window style bits.
+ */
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((style & SWT.CHECK) != 0) {
+ if (flags == OS.BST_INDETERMINATE) {
+ bits &= ~OS.BS_CHECKBOX;
+ bits |= OS.BS_3STATE;
+ } else {
+ bits |= OS.BS_CHECKBOX;
+ bits &= ~OS.BS_3STATE;
+ }
+ if (bits != OS.GetWindowLong (handle, OS.GWL_STYLE)) {
+ OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+ }
+ }
+ OS.SendMessage (handle, OS.BM_SETCHECK, flags, 0);
+ if (bits != OS.GetWindowLong (handle, OS.GWL_STYLE)) {
+ OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+ }
+ }
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle ();
+ if ((style & SWT.FLAT) != 0) bits |= OS.BS_FLAT;
+ if ((style & SWT.ARROW) != 0) return bits | OS.BS_OWNERDRAW;
+ if ((style & SWT.LEFT) != 0) bits |= OS.BS_LEFT;
+ if ((style & SWT.CENTER) != 0) bits |= OS.BS_CENTER;
+ if ((style & SWT.RIGHT) != 0) bits |= OS.BS_RIGHT;
+ if ((style & SWT.WRAP) != 0) bits |= OS.BS_MULTILINE;
+ if ((style & SWT.PUSH) != 0) return bits | OS.BS_PUSHBUTTON | OS.WS_TABSTOP;
+ if ((style & SWT.CHECK) != 0) return bits | OS.BS_CHECKBOX | OS.WS_TABSTOP;
+ if ((style & SWT.RADIO) != 0) return bits | OS.BS_RADIOBUTTON;
+ if ((style & SWT.TOGGLE) != 0) return bits | OS.BS_PUSHLIKE | OS.BS_CHECKBOX | OS.WS_TABSTOP;
+ if ((style & SWT.COMMAND) != 0) return bits | OS.BS_COMMANDLINK | OS.WS_TABSTOP;
+ return bits | OS.BS_PUSHBUTTON | OS.WS_TABSTOP;
+}
+
+@Override
+TCHAR windowClass () {
+ return ButtonClass;
+}
+
+@Override
+long windowProc () {
+ return ButtonProc;
+}
+
+@Override
+LRESULT WM_GETDLGCODE (long wParam, long lParam) {
+ LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
+ if (result != null) return result;
+ if ((style & SWT.ARROW) != 0) {
+ return new LRESULT (OS.DLGC_STATIC);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_GETOBJECT (long wParam, long lParam) {
+ /*
+ * Ensure that there is an accessible object created for this
+ * control because support for radio button position in group
+ * accessibility is implemented in the accessibility package.
+ */
+ if ((style & SWT.RADIO) != 0) {
+ if (accessible == null) accessible = new_Accessible (this);
+ }
+ return super.WM_GETOBJECT (wParam, lParam);
+}
+
+@Override
+LRESULT WM_KILLFOCUS (long wParam, long lParam) {
+ LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
+ if ((style & SWT.PUSH) != 0 && getDefault ()) {
+ menuShell ().setDefaultButton (null, false);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
+ if (ignoreMouse) return null;
+ return super.WM_LBUTTONDOWN (wParam, lParam);
+}
+
+@Override
+LRESULT WM_LBUTTONUP (long wParam, long lParam) {
+ if (ignoreMouse) return null;
+ return super.WM_LBUTTONUP (wParam, lParam);
+}
+
+@Override
+LRESULT WM_SETFOCUS (long wParam, long lParam) {
+ /*
+ * Feature in Windows. When Windows sets focus to
+ * a radio button, it sets the WS_TABSTOP style.
+ * This is undocumented and unwanted. The fix is
+ * to save and restore the window style bits.
+ */
+ int bits = 0;
+ if ((style & SWT.RADIO) != 0) {
+ bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ }
+ LRESULT result = super.WM_SETFOCUS (wParam, lParam);
+ if ((style & SWT.RADIO) != 0) {
+ OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+ }
+ if ((style & SWT.PUSH) != 0) {
+ menuShell ().setDefaultButton (this, false);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ if (result != null) return result;
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+ if (imageList != null && text.length () != 0) {
+ BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
+ OS.SendMessage (handle, OS.BCM_GETIMAGELIST, 0, buttonImageList);
+ buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
+ buttonImageList.margin_left = computeLeftMargin ();
+ buttonImageList.margin_right = MARGIN;
+ OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_SYSCOLORCHANGE (long wParam, long lParam) {
+ LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam);
+ if (result != null) return result;
+ if (image2 != null) _setImage (image);
+ return result;
+}
+
+@Override
+LRESULT WM_UPDATEUISTATE (long wParam, long lParam) {
+ LRESULT result = super.WM_UPDATEUISTATE (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. When WM_UPDATEUISTATE is sent to
+ * a button, it sends WM_CTLCOLORBTN to get the foreground
+ * and background. If drawing happens in WM_CTLCOLORBTN,
+ * it will overwrite the contents of the control. The
+ * fix is draw the button without drawing the background
+ * and avoid the button window proc.
+ *
+ * NOTE: This only happens for radio, check and toggle
+ * buttons.
+ */
+ if ((style & (SWT.RADIO | SWT.CHECK | SWT.TOGGLE)) != 0) {
+ boolean redraw = findImageControl () != null;
+ if (!redraw) {
+ if ((state & THEME_BACKGROUND) != 0) {
+ if (OS.IsAppThemed ()) {
+ redraw = findThemeControl () != null;
+ }
+ }
+ if (!redraw) redraw = findBackgroundControl () != null;
+ }
+ if (redraw) {
+ OS.InvalidateRect (handle, null, false);
+ long code = OS.DefWindowProc (handle, OS.WM_UPDATEUISTATE, wParam, lParam);
+ return new LRESULT (code);
+ }
+ }
+ /*
+ * Feature in Windows. Push and toggle buttons draw directly
+ * in WM_UPDATEUISTATE rather than damaging and drawing later
+ * in WM_PAINT. This means that clients who hook WM_PAINT
+ * expecting to get all the drawing will not. The fix is to
+ * redraw the control when paint events are hooked.
+ */
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+ if (hooks (SWT.Paint) || filters (SWT.Paint) || customDrawing()) {
+ OS.InvalidateRect (handle, null, true);
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT wmCommandChild (long wParam, long lParam) {
+ int code = OS.HIWORD (wParam);
+ switch (code) {
+ case OS.BN_CLICKED:
+ case OS.BN_DOUBLECLICKED:
+ if ((style & (SWT.CHECK | SWT.TOGGLE)) != 0) {
+ setSelection (!getSelection ());
+ } else {
+ if ((style & SWT.RADIO) != 0) {
+ if ((parent.getStyle () & SWT.NO_RADIO_GROUP) != 0) {
+ setSelection (!getSelection ());
+ } else {
+ selectRadio ();
+ }
+ }
+ }
+ sendSelectionEvent (SWT.Selection);
+ }
+ return super.wmCommandChild (wParam, lParam);
+}
+
+@Override
+LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
+ switch (hdr.code) {
+ case OS.NM_CUSTOMDRAW:
+ // this message will not appear for owner-draw buttons (currently the ARROW button).
+
+ NMCUSTOMDRAW nmcd = new NMCUSTOMDRAW ();
+ OS.MoveMemory (nmcd, lParam, NMCUSTOMDRAW.sizeof);
+
+ switch (nmcd.dwDrawStage) {
+ case OS.CDDS_PREPAINT: {
+ // buttons are ignoring SetBkColor, SetBkMode and SetTextColor
+ if (customBackgroundDrawing()) {
+ int pixel = buttonBackground;
+ if ((nmcd.uItemState & OS.CDIS_SELECTED) != 0) {
+ pixel = getDifferentColor(buttonBackground);
+ } else if ((nmcd.uItemState & OS.CDIS_HOT) != 0) {
+ pixel = getSlightlyDifferentColor(buttonBackground);
+ }
+ if ((style & SWT.TOGGLE) != 0 && isChecked()) {
+ pixel = getDifferentColor(buttonBackground);
+ }
+ RECT rect = new RECT ();
+ OS.SetRect (rect, nmcd.left+2, nmcd.top+2, nmcd.right-2, nmcd.bottom-2);
+ long brush = OS.CreateSolidBrush(pixel);
+ OS.FillRect(nmcd.hdc, rect, brush);
+ OS.DeleteObject(brush);
+ }
+ if (customForegroundDrawing()) {
+ /*
+ * Check-box/Radio buttons are native widget which honors
+ * the Win OS zoom level for both 'Square' and 'Text' part
+ * [Note: By-design SWT doesn't control native auto-scaling]
+ * Hence, custom fore-ground draw logic should auto-scale
+ * text-padding as per OS Native DPI level to fix bug 506371
+ */
+ int radioOrCheckTextPadding = DPIUtil.autoScaleUpUsingNativeDPI(16);
+ int border = isRadioOrCheck() ? 0 : 3;
+ int left = nmcd.left + border;
+ int right = nmcd.right - border;
+ if (image != null) {
+ GCData data = new GCData();
+ data.device = display;
+ GC gc = GC.win32_new (nmcd.hdc, data);
+
+ int margin = computeLeftMargin();
+ int imageWidth = image.getBoundsInPixels().width;
+ left += (imageWidth + (isRadioOrCheck() ? 2 * MARGIN : MARGIN)); // for SWT.RIGHT_TO_LEFT right and left are inverted
+
+ int x = margin + (isRadioOrCheck() ? radioOrCheckTextPadding : 3);
+ int y = Math.max (0, (nmcd.bottom - image.getBoundsInPixels().height) / 2);
+ gc.drawImage (image, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(y));
+ gc.dispose ();
+ }
+
+ left += isRadioOrCheck() ? radioOrCheckTextPadding : 0;
+ RECT textRect = new RECT ();
+ OS.SetRect (textRect, left, nmcd.top + border, right, nmcd.bottom - border);
+
+ // draw text
+ char [] buffer = text.toCharArray ();
+ int flags = 0;
+ if ((style & SWT.WRAP) != 0) {
+ flags |= OS.DT_WORDBREAK;
+ if (!isRadioOrCheck() && image != null) {
+ textRect.right -= MARGIN;
+ }
+ } else {
+ flags |= OS.DT_SINGLELINE; // TODO: this always draws the prefix
+ }
+ OS.DrawText(nmcd.hdc, buffer, buffer.length, textRect, flags | OS.DT_CALCRECT);
+ OS.OffsetRect(textRect, 0, Math.max(0, (nmcd.bottom - textRect.bottom - border) / 2));
+ if (image != null) {
+ // The default button with an image doesn't respect the text alignment. So we do the same for styled buttons.
+ flags |= OS.DT_LEFT;
+ if (!isRadioOrCheck()) {
+ OS.OffsetRect(textRect, Math.max(MARGIN, (right - textRect.right) / 2 + 1), 0);
+ }
+ } else if ((style & SWT.LEFT) != 0) {
+ flags |= OS.DT_LEFT;
+ } else if ((style & SWT.RIGHT) != 0) {
+ flags |= OS.DT_RIGHT;
+ OS.OffsetRect(textRect, right - textRect.right, 0);
+ } else {
+ flags |= OS.DT_CENTER;
+ OS.OffsetRect(textRect, (right - textRect.right) / 2, 0);
+ }
+ OS.SetBkMode(nmcd.hdc, OS.TRANSPARENT);
+ OS.SetTextColor(nmcd.hdc, foreground);
+ OS.DrawText(nmcd.hdc, buffer, buffer.length, textRect, flags);
+
+ // draw focus rect
+ if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
+ RECT focusRect = new RECT ();
+ if (isRadioOrCheck()) {
+ if (text.length() > 0) {
+ OS.SetRect(focusRect, textRect.left-1, textRect.top, Math.min(nmcd.right, textRect.right+1), Math.min(nmcd.bottom, textRect.bottom+1));
+ } else {
+ /*
+ * With custom foreground, draw focus rectangle for CheckBox
+ * and Radio buttons considering the native text padding
+ * value(which is DPI aware). See bug 508141 for details.
+ */
+ OS.SetRect (focusRect, nmcd.left+1+radioOrCheckTextPadding, nmcd.top, nmcd.right-2, nmcd.bottom-1);
+ }
+ } else {
+ OS.SetRect (focusRect, nmcd.left+2, nmcd.top+3, nmcd.right-2, nmcd.bottom-3);
+ }
+ OS.DrawFocusRect(nmcd.hdc, focusRect);
+ }
+ return new LRESULT (OS.CDRF_SKIPDEFAULT);
+ }
+ return new LRESULT (OS.CDRF_DODEFAULT);
+ }
+ }
+ break;
+ }
+ return super.wmNotifyChild (hdr, wParam, lParam);
+}
+
+@Override
+LRESULT wmDrawChild (long wParam, long lParam) {
+ if ((style & SWT.ARROW) == 0) return super.wmDrawChild (wParam, lParam);
+ DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
+ OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
+ RECT rect = new RECT ();
+ OS.SetRect (rect, struct.left, struct.top, struct.right, struct.bottom);
+ if (OS.IsAppThemed ()) {
+ int iStateId = OS.ABS_LEFTNORMAL;
+ switch (style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) {
+ case SWT.UP: iStateId = OS.ABS_UPNORMAL; break;
+ case SWT.DOWN: iStateId = OS.ABS_DOWNNORMAL; break;
+ case SWT.LEFT: iStateId = OS.ABS_LEFTNORMAL; break;
+ case SWT.RIGHT: iStateId = OS.ABS_RIGHTNORMAL; break;
+ }
+ /*
+ * Feature in Windows. DrawThemeBackground() does not mirror the drawing.
+ * The fix is switch left to right and right to left.
+ */
+ if ((style & SWT.MIRRORED) != 0) {
+ if ((style & (SWT.LEFT | SWT.RIGHT)) != 0) {
+ iStateId = iStateId == OS.ABS_RIGHTNORMAL ? OS.ABS_LEFTNORMAL : OS.ABS_RIGHTNORMAL;
+ }
+ }
+ /*
+ * NOTE: The normal, hot, pressed and disabled state is
+ * computed relying on the fact that the increment between
+ * the direction states is invariant (always separated by 4).
+ */
+ if (!getEnabled ()) iStateId += OS.ABS_UPDISABLED - OS.ABS_UPNORMAL;
+ if ((struct.itemState & OS.ODS_SELECTED) != 0) iStateId += OS.ABS_UPPRESSED - OS.ABS_UPNORMAL;
+ OS.DrawThemeBackground (display.hScrollBarTheme (), struct.hDC, OS.SBP_ARROWBTN, iStateId, rect, null);
+ } else {
+ int uState = OS.DFCS_SCROLLLEFT;
+ switch (style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) {
+ case SWT.UP: uState = OS.DFCS_SCROLLUP; break;
+ case SWT.DOWN: uState = OS.DFCS_SCROLLDOWN; break;
+ case SWT.LEFT: uState = OS.DFCS_SCROLLLEFT; break;
+ case SWT.RIGHT: uState = OS.DFCS_SCROLLRIGHT; break;
+ }
+ if (!getEnabled ()) uState |= OS.DFCS_INACTIVE;
+ if ((style & SWT.FLAT) == SWT.FLAT) uState |= OS.DFCS_FLAT;
+ if ((struct.itemState & OS.ODS_SELECTED) != 0) uState |= OS.DFCS_PUSHED;
+ OS.DrawFrameControl (struct.hDC, rect, OS.DFC_SCROLL, uState);
+ }
+ return null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Canvas.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Canvas.java
new file mode 100644
index 000000000..f7b8fb9a1
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Canvas.java
@@ -0,0 +1,489 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2013 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class provide a surface for drawing
+ * arbitrary graphics.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#getStyle
+ */
+public Canvas (Composite parent, int style) {
+ super (parent, style);
+}
+
+void clearArea (int x, int y, int width, int height) {
+ checkWidget ();
+ if (OS.IsWindowVisible (handle)) {
+ RECT rect = new RECT ();
+ OS.SetRect (rect, x, y, x + width, y + height);
+ long hDC = OS.GetDCEx (handle, 0, OS.DCX_CACHE | OS.DCX_CLIPCHILDREN | OS.DCX_CLIPSIBLINGS);
+ drawBackground (hDC, rect);
+ OS.ReleaseDC (handle, hDC);
+ }
+}
+
+/**
+ * Fills the interior of the rectangle specified by the arguments,
+ * with the receiver's background.
+ *
+ * @param gc the gc where the rectangle is to be filled
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled
+ * @param height the height of the rectangle to be filled
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.2
+ */
+public void drawBackground (GC gc, int x, int y, int width, int height) {
+ x = DPIUtil.autoScaleUp(x);
+ y = DPIUtil.autoScaleUp(y);
+ width = DPIUtil.autoScaleUp(width);
+ height = DPIUtil.autoScaleUp(height);
+ drawBackgroundInPixels(gc, x, y, width, height, 0, 0);
+}
+
+/**
+ * Returns the caret.
+ *
+ *
+ */
+public Caret getCaret () {
+ checkWidget ();
+ return caret;
+}
+
+/**
+ * Returns the IME.
+ *
+ * @return the IME
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public IME getIME () {
+ checkWidget ();
+ return ime;
+}
+
+@Override
+void releaseChildren (boolean destroy) {
+ if (caret != null) {
+ caret.release (false);
+ caret = null;
+ }
+ if (ime != null) {
+ ime.release (false);
+ ime = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+@Override
+void reskinChildren (int flags) {
+ if (caret != null) caret.reskin (flags);
+ if (ime != null) ime.reskin (flags);
+ super.reskinChildren (flags);
+}
+
+/**
+ * Scrolls a rectangular area of the receiver by first copying
+ * the source area to the destination and then causing the area
+ * of the source which is not covered by the destination to
+ * be repainted. Children that intersect the rectangle are
+ * optionally moved during the operation. In addition, all outstanding
+ * paint events are flushed before the source area is copied to
+ * ensure that the contents of the canvas are drawn correctly.
+ *
+ * @param destX the x coordinate of the destination
+ * @param destY the y coordinate of the destination
+ * @param x the x coordinate of the source
+ * @param y the y coordinate of the source
+ * @param width the width of the area
+ * @param height the height of the area
+ * @param all true
if children should be scrolled, and false
otherwise
+ *
+ * @exception SWTException
+ *
+ */
+public void scroll (int destX, int destY, int x, int y, int width, int height, boolean all) {
+ checkWidget ();
+ destX = DPIUtil.autoScaleUp(destX);
+ destY = DPIUtil.autoScaleUp(destY);
+ x = DPIUtil.autoScaleUp(x);
+ y = DPIUtil.autoScaleUp(y);
+ width = DPIUtil.autoScaleUp(width);
+ height = DPIUtil.autoScaleUp(height);
+ scrollInPixels(destX, destY, x, y, width, height, all);
+}
+
+void scrollInPixels (int destX, int destY, int x, int y, int width, int height, boolean all) {
+ forceResize ();
+ boolean isFocus = caret != null && caret.isFocusCaret ();
+ if (isFocus) caret.killFocus ();
+ RECT sourceRect = new RECT ();
+ OS.SetRect (sourceRect, x, y, x + width, y + height);
+ RECT clientRect = new RECT ();
+ OS.GetClientRect (handle, clientRect);
+ if (OS.IntersectRect (clientRect, sourceRect, clientRect)) {
+ int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (handle, null, 0, flags);
+ }
+ int deltaX = destX - x, deltaY = destY - y;
+ if (findImageControl () != null) {
+ int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
+ if (all) flags |= OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (handle, sourceRect, 0, flags);
+ OS.OffsetRect (sourceRect, deltaX, deltaY);
+ OS.RedrawWindow (handle, sourceRect, 0, flags);
+ } else {
+ int flags = OS.SW_INVALIDATE | OS.SW_ERASE;
+ /*
+ * Feature in Windows. If any child in the widget tree partially
+ * intersects the scrolling rectangle, Windows moves the child
+ * and copies the bits that intersect the scrolling rectangle but
+ * does not redraw the child.
+ *
+ * Feature in Windows. When any child in the widget tree does not
+ * intersect the scrolling rectangle but the parent does intersect,
+ * Windows does not move the child. This is the documented (but
+ * strange) Windows behavior.
+ *
+ * The fix is to not use SW_SCROLLCHILDREN and move the children
+ * explicitly after scrolling.
+ */
+// if (all) flags |= OS.SW_SCROLLCHILDREN;
+ OS.ScrollWindowEx (handle, deltaX, deltaY, sourceRect, null, 0, null, flags);
+ }
+ if (all) {
+ Control [] children = _getChildren ();
+ for (int i=0; i
+ *
+ * @exception SWTException
+ *
+ */
+public void setCaret (Caret caret) {
+ checkWidget ();
+ Caret newCaret = caret;
+ Caret oldCaret = this.caret;
+ this.caret = newCaret;
+ if (hasFocus ()) {
+ if (oldCaret != null) oldCaret.killFocus ();
+ if (newCaret != null) {
+ if (newCaret.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ newCaret.setFocus ();
+ }
+ }
+}
+
+@Override
+public void setFont (Font font) {
+ checkWidget ();
+ if (caret != null) caret.setFont (font);
+ super.setFont (font);
+}
+
+/**
+ * Sets the receiver's IME.
+ *
+ * @param ime the new IME for the receiver, may be null
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public void setIME (IME ime) {
+ checkWidget ();
+ if (ime != null && ime.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ this.ime = ime;
+}
+
+@Override
+TCHAR windowClass () {
+ if (display.useOwnDC) return display.windowOwnDCClass;
+ return super.windowClass ();
+}
+
+@Override
+long windowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (msg == Display.SWT_RESTORECARET) {
+ if ((state & CANVAS) != 0) {
+ if (caret != null) {
+ caret.killFocus ();
+ caret.setFocus ();
+ return 1;
+ }
+ }
+ }
+ return super.windowProc (hwnd, msg, wParam, lParam);
+}
+
+@Override
+LRESULT WM_CHAR (long wParam, long lParam) {
+ LRESULT result = super.WM_CHAR (wParam, lParam);
+ if (result != null) return result;
+ if (caret != null) {
+ switch ((int)wParam) {
+ case SWT.DEL:
+ case SWT.BS:
+ case SWT.ESC:
+ break;
+ default: {
+ if (OS.GetKeyState (OS.VK_CONTROL) >= 0) {
+ int [] value = new int [1];
+ if (OS.SystemParametersInfo (OS.SPI_GETMOUSEVANISH, 0, value, 0)) {
+ if (value [0] != 0) OS.SetCursor (0);
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_IME_COMPOSITION (long wParam, long lParam) {
+ if (ime != null) {
+ LRESULT result = ime.WM_IME_COMPOSITION (wParam, lParam);
+ if (result != null) return result;
+ }
+ return super.WM_IME_COMPOSITION (wParam, lParam);
+}
+
+@Override
+LRESULT WM_IME_COMPOSITION_START (long wParam, long lParam) {
+ if (ime != null) {
+ LRESULT result = ime.WM_IME_COMPOSITION_START (wParam, lParam);
+ if (result != null) return result;
+ }
+ return super.WM_IME_COMPOSITION_START (wParam, lParam);
+}
+
+@Override
+LRESULT WM_IME_ENDCOMPOSITION (long wParam, long lParam) {
+ if (ime != null) {
+ LRESULT result = ime.WM_IME_ENDCOMPOSITION (wParam, lParam);
+ if (result != null) return result;
+ }
+ return super.WM_IME_ENDCOMPOSITION (wParam, lParam);
+}
+
+@Override
+LRESULT WM_INPUTLANGCHANGE (long wParam, long lParam) {
+ LRESULT result = super.WM_INPUTLANGCHANGE (wParam, lParam);
+ if (caret != null && caret.isFocusCaret ()) {
+ caret.setIMEFont ();
+ caret.resizeIME ();
+ }
+ return result;
+}
+
+
+@Override
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_KEYDOWN (wParam, lParam);
+ if (result != null) return result;
+ if (ime != null) {
+ ime.WM_KEYDOWN (wParam, lParam);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_KILLFOCUS (long wParam, long lParam) {
+ if (ime != null) {
+ LRESULT result = ime.WM_KILLFOCUS (wParam, lParam);
+ if (result != null) return result;
+ }
+ Caret caret = this.caret;
+ LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
+ if (caret != null) caret.killFocus ();
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
+ if (ime != null) {
+ LRESULT result = ime.WM_LBUTTONDOWN (wParam, lParam);
+ if (result != null) return result;
+ }
+ return super.WM_LBUTTONDOWN (wParam, lParam);
+}
+
+@Override
+LRESULT WM_SETFOCUS (long wParam, long lParam) {
+ LRESULT result = super.WM_SETFOCUS (wParam, lParam);
+ if (caret != null && caret.isFocusCaret ()) caret.setFocus ();
+ return result;
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ if (caret != null && caret.isFocusCaret ()) caret.resizeIME ();
+ return result;
+}
+
+@Override
+LRESULT WM_WINDOWPOSCHANGED (long wParam, long lParam) {
+ LRESULT result = super.WM_WINDOWPOSCHANGED (wParam, lParam);
+ //if (result != null) return result;
+ /*
+ * Bug in Windows. When a window with style WS_EX_LAYOUTRTL
+ * that contains a caret is resized, Windows does not move the
+ * caret in relation to the mirrored origin in the top right.
+ * The fix is to hide the caret in WM_WINDOWPOSCHANGING and
+ * show the caret in WM_WINDOWPOSCHANGED.
+ */
+ boolean isFocus = (style & SWT.RIGHT_TO_LEFT) != 0 && caret != null && caret.isFocusCaret ();
+ if (isFocus) caret.setFocus ();
+ return result;
+}
+
+@Override
+LRESULT WM_WINDOWPOSCHANGING (long wParam, long lParam) {
+ LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Bug in Windows. When a window with style WS_EX_LAYOUTRTL
+ * that contains a caret is resized, Windows does not move the
+ * caret in relation to the mirrored origin in the top right.
+ * The fix is to hide the caret in WM_WINDOWPOSCHANGING and
+ * show the caret in WM_WINDOWPOSCHANGED.
+ */
+ boolean isFocus = (style & SWT.RIGHT_TO_LEFT) != 0 && caret != null && caret.isFocusCaret ();
+ if (isFocus) caret.killFocus ();
+ return result;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Caret.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Caret.java
new file mode 100644
index 000000000..bc0f47033
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Caret.java
@@ -0,0 +1,635 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class provide an i-beam that is typically used
+ * as the insertion point for text.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Caret (Canvas parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ createWidget ();
+}
+
+void createWidget () {
+ isVisible = true;
+ if (parent.getCaret () == null) {
+ parent.setCaret (this);
+ }
+}
+
+long defaultFont () {
+ long hwnd = parent.handle;
+ long hwndIME = OS.ImmGetDefaultIMEWnd (hwnd);
+ long hFont = 0;
+ if (hwndIME != 0) {
+ hFont = OS.SendMessage (hwndIME, OS.WM_GETFONT, 0, 0);
+ }
+ if (hFont == 0) {
+ hFont = OS.SendMessage (hwnd, OS.WM_GETFONT, 0, 0);
+ }
+ if (hFont == 0) return parent.defaultFont ();
+ return hFont;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent (or its display if its parent is null).
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException
+ *
+ */
+public Rectangle getBounds () {
+ checkWidget();
+ return DPIUtil.autoScaleDown(getBoundsInPixels());
+}
+
+Rectangle getBoundsInPixels () {
+ if (image != null) {
+ Rectangle rect = image.getBoundsInPixels ();
+ return new Rectangle (x, y, rect.width, rect.height);
+ }
+ if (width == 0) {
+ int [] buffer = new int [1];
+ if (OS.SystemParametersInfo (OS.SPI_GETCARETWIDTH, 0, buffer, 0)) {
+ return new Rectangle (x, y, buffer [0], height);
+ }
+ }
+ return new Rectangle (x, y, width, height);
+}
+
+/**
+ * Returns the font that the receiver will use to paint textual information.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException
+ *
+ */
+public Font getFont () {
+ checkWidget();
+ if (font == null) {
+ long hFont = defaultFont ();
+ return Font.win32_new (display, hFont);
+ }
+ return font;
+}
+
+/**
+ * Returns the image that the receiver will use to paint the caret.
+ *
+ * @return the receiver's image
+ *
+ * @exception SWTException
+ *
+ */
+public Image getImage () {
+ checkWidget();
+ return image;
+}
+
+/**
+ * Returns a point describing the receiver's location relative
+ * to its parent (or its display if its parent is null).
+ *
+ * @return the receiver's location
+ *
+ * @exception SWTException
+ *
+ */
+public Point getLocation () {
+ checkWidget();
+ return DPIUtil.autoScaleDown(getLocationInPixels());
+}
+
+Point getLocationInPixels () {
+ return new Point (x, y);
+}
+
+/**
+ * Returns the receiver's parent, which must be a Canvas
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException
+ *
+ */
+public Canvas getParent () {
+ checkWidget();
+ return parent;
+}
+
+/**
+ * Returns a point describing the receiver's size.
+ *
+ * @return the receiver's size
+ *
+ * @exception SWTException
+ *
+ */
+public Point getSize () {
+ checkWidget();
+ return DPIUtil.autoScaleDown(getSizeInPixels());
+}
+
+Point getSizeInPixels () {
+ if (image != null) {
+ Rectangle rect = image.getBoundsInPixels ();
+ return new Point (rect.width, rect.height);
+ }
+ if (width == 0) {
+ int [] buffer = new int [1];
+ if (OS.SystemParametersInfo (OS.SPI_GETCARETWIDTH, 0, buffer, 0)) {
+ return new Point (buffer [0], height);
+ }
+ }
+ return new Point (width, height);
+}
+
+/**
+ * Returns true
if the receiver is visible, and
+ * false
otherwise.
+ *
+ *
+ */
+public boolean getVisible () {
+ checkWidget();
+ return isVisible;
+}
+
+boolean hasFocus () {
+ return parent.handle == OS.GetFocus ();
+}
+
+boolean isFocusCaret () {
+ return parent.caret == this && hasFocus ();
+}
+
+/**
+ * Returns true
if the receiver is visible and all
+ * of the receiver's ancestors are visible and false
+ * otherwise.
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getVisible
+ */
+public boolean isVisible () {
+ checkWidget();
+ return isVisible && parent.isVisible () && hasFocus ();
+}
+
+void killFocus () {
+ OS.DestroyCaret ();
+ restoreIMEFont ();
+}
+
+void move () {
+ moved = false;
+ if (!OS.SetCaretPos (x, y)) return;
+ resizeIME ();
+}
+
+void resizeIME () {
+ if (!OS.IsDBLocale) return;
+ POINT ptCurrentPos = new POINT ();
+ if (!OS.GetCaretPos (ptCurrentPos)) return;
+ long hwnd = parent.handle;
+ long hIMC = OS.ImmGetContext (hwnd);
+ IME ime = parent.getIME ();
+ if (ime != null && ime.isInlineEnabled ()) {
+ Point size = getSizeInPixels ();
+ CANDIDATEFORM lpCandidate = new CANDIDATEFORM ();
+ lpCandidate.dwStyle = OS.CFS_EXCLUDE;
+ lpCandidate.ptCurrentPos = ptCurrentPos;
+ lpCandidate.rcArea = new RECT ();
+ OS.SetRect (lpCandidate.rcArea, ptCurrentPos.x, ptCurrentPos.y, ptCurrentPos.x + size.x, ptCurrentPos.y + size.y);
+ OS.ImmSetCandidateWindow (hIMC, lpCandidate);
+ } else {
+ RECT rect = new RECT ();
+ OS.GetClientRect (hwnd, rect);
+ COMPOSITIONFORM lpCompForm = new COMPOSITIONFORM ();
+ lpCompForm.dwStyle = OS.CFS_RECT;
+ lpCompForm.x = ptCurrentPos.x;
+ lpCompForm.y = ptCurrentPos.y;
+ lpCompForm.left = rect.left;
+ lpCompForm.right = rect.right;
+ lpCompForm.top = rect.top;
+ lpCompForm.bottom = rect.bottom;
+ OS.ImmSetCompositionWindow (hIMC, lpCompForm);
+ }
+ OS.ImmReleaseContext (hwnd, hIMC);
+}
+
+@Override
+void releaseParent () {
+ super.releaseParent ();
+ if (parent != null && this == parent.caret) {
+ if (!parent.isDisposed()) parent.setCaret (null);
+ else parent.caret = null;
+ }
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ parent = null;
+ image = null;
+ font = null;
+ oldFont = null;
+}
+
+void resize () {
+ resized = false;
+ long hwnd = parent.handle;
+ OS.DestroyCaret ();
+ long hBitmap = image != null ? image.handle : 0;
+ int width = this.width;
+ if (image == null && width == 0) {
+ int [] buffer = new int [1];
+ if (OS.SystemParametersInfo (OS.SPI_GETCARETWIDTH, 0, buffer, 0)) {
+ width = buffer [0];
+ }
+ }
+ OS.CreateCaret (hwnd, hBitmap, width, height);
+ OS.SetCaretPos (x, y);
+ OS.ShowCaret (hwnd);
+ move ();
+}
+
+void restoreIMEFont () {
+ if (!OS.IsDBLocale) return;
+ if (oldFont == null) return;
+ long hwnd = parent.handle;
+ long hIMC = OS.ImmGetContext (hwnd);
+ OS.ImmSetCompositionFont (hIMC, oldFont);
+ OS.ImmReleaseContext (hwnd, hIMC);
+ oldFont = null;
+}
+
+/**
+ * Sets the receiver's size and location to the rectangular
+ * area specified by the arguments. The x
and
+ * y
arguments are relative to the receiver's
+ * parent (or its display if its parent is null).
+ *
+ * @param x the new x coordinate for the receiver
+ * @param y the new y coordinate for the receiver
+ * @param width the new width for the receiver
+ * @param height the new height for the receiver
+ *
+ * @exception SWTException
+ *
+ */
+public void setBounds (int x, int y, int width, int height) {
+ checkWidget();
+ setBoundsInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y), DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height));
+}
+
+void setBoundsInPixels (int x, int y, int width, int height) {
+ boolean samePosition = this.x == x && this.y == y;
+ boolean sameExtent = this.width == width && this.height == height;
+ if (samePosition && sameExtent) return;
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ if (sameExtent) {
+ moved = true;
+ if (isVisible && hasFocus ()) move ();
+ } else {
+ resized = true;
+ if (isVisible && hasFocus ()) resize ();
+ }
+}
+
+/**
+ * Sets the receiver's size and location to the rectangular
+ * area specified by the argument. The x
and
+ * y
fields of the rectangle are relative to
+ * the receiver's parent (or its display if its parent is null).
+ *
+ * @param rect the new bounds for the receiver
+ *
+ * @exception SWTException
+ *
+ */
+public void setBounds (Rectangle rect) {
+ if (rect == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setBoundsInPixels(DPIUtil.autoScaleUp(rect));
+}
+
+void setBoundsInPixels (Rectangle rect) {
+ setBoundsInPixels (rect.x, rect.y, rect.width, rect.height);
+}
+
+void setFocus () {
+ long hwnd = parent.handle;
+ long hBitmap = 0;
+ if (image != null) hBitmap = image.handle;
+ int width = this.width;
+ if (image == null && width == 0) {
+ int [] buffer = new int [1];
+ if (OS.SystemParametersInfo (OS.SPI_GETCARETWIDTH, 0, buffer, 0)) {
+ width = buffer [0];
+ }
+ }
+ OS.CreateCaret (hwnd, hBitmap, width, height);
+ move ();
+ setIMEFont ();
+ if (isVisible) OS.ShowCaret (hwnd);
+}
+
+/**
+ * Sets the font that the receiver will use to paint textual information
+ * to the font specified by the argument, or to the default font for that
+ * kind of control if the argument is null.
+ *
+ * @param font the new font (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setFont (Font font) {
+ checkWidget();
+ if (font != null && font.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.font = font;
+ if (hasFocus ()) setIMEFont ();
+}
+
+/**
+ * Sets the image that the receiver will use to paint the caret
+ * to the image specified by the argument, or to the default
+ * which is a filled rectangle if the argument is null
+ *
+ * @param image the new image (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setImage (Image image) {
+ checkWidget();
+ if (image != null && image.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.image = image;
+ if (isVisible && hasFocus ()) resize ();
+}
+
+void setIMEFont () {
+ if (!OS.IsDBLocale) return;
+ long hFont = 0;
+ if (font != null) hFont = font.handle;
+ if (hFont == 0) hFont = defaultFont ();
+ long hwnd = parent.handle;
+ long hIMC = OS.ImmGetContext (hwnd);
+ /* Save the current IME font */
+ if (oldFont == null) {
+ oldFont = new LOGFONT ();
+ if (!OS.ImmGetCompositionFont (hIMC, oldFont)) oldFont = null;
+ }
+ /* Set new IME font */
+ LOGFONT logFont = new LOGFONT ();
+ if (OS.GetObject (hFont, LOGFONT.sizeof, logFont) != 0) {
+ OS.ImmSetCompositionFont (hIMC, logFont);
+ }
+ OS.ImmReleaseContext (hwnd, hIMC);
+}
+
+/**
+ * Sets the receiver's location to the point specified by
+ * the arguments which are relative to the receiver's
+ * parent (or its display if its parent is null).
+ *
+ * @param x the new x coordinate for the receiver
+ * @param y the new y coordinate for the receiver
+ *
+ * @exception SWTException
+ *
+ */
+public void setLocation (int x, int y) {
+ checkWidget();
+ setLocationInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y));
+}
+
+void setLocationInPixels (int x, int y) {
+ if (this.x == x && this.y == y) return;
+ this.x = x; this.y = y;
+ moved = true;
+ if (isVisible && hasFocus ()) move ();
+}
+
+/**
+ * Sets the receiver's location to the point specified by
+ * the argument which is relative to the receiver's
+ * parent (or its display if its parent is null).
+ *
+ * @param location the new location for the receiver
+ *
+ * @exception SWTException
+ *
+ */
+public void setLocation (Point location) {
+ checkWidget();
+ if (location == null) error (SWT.ERROR_NULL_ARGUMENT);
+ location = DPIUtil.autoScaleUp(location);
+ setLocationInPixels(location.x, location.y);
+}
+
+/**
+ * Sets the receiver's size to the point specified by the arguments.
+ *
+ * @param width the new width for the receiver
+ * @param height the new height for the receiver
+ *
+ * @exception SWTException
+ *
+ */
+public void setSize (int width, int height) {
+ checkWidget();
+ setSizeInPixels(DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height));
+}
+
+void setSizeInPixels (int width, int height) {
+ if (this.width == width && this.height == height) return;
+ this.width = width; this.height = height;
+ resized = true;
+ if (isVisible && hasFocus ()) resize ();
+}
+
+/**
+ * Sets the receiver's size to the point specified by the argument.
+ *
+ * @param size the new extent for the receiver
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setSize (Point size) {
+ checkWidget();
+ if (size == null) error (SWT.ERROR_NULL_ARGUMENT);
+ size = DPIUtil.autoScaleUp(size);
+ setSizeInPixels(size.x, size.y);
+}
+
+/**
+ * Marks the receiver as visible if the argument is true
,
+ * and marks it invisible otherwise.
+ *
+ *
+ */
+public void setVisible (boolean visible) {
+ checkWidget();
+ if (visible == isVisible) return;
+ isVisible = visible;
+ long hwnd = parent.handle;
+ if (OS.GetFocus () != hwnd) return;
+ if (!isVisible) {
+ OS.HideCaret (hwnd);
+ } else {
+ if (resized) {
+ resize ();
+ } else {
+ if (moved) move ();
+ }
+ OS.ShowCaret (hwnd);
+ }
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ColorDialog.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ColorDialog.java
new file mode 100644
index 000000000..01f688219
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ColorDialog.java
@@ -0,0 +1,362 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class allow the user to select a color
+ * from a predefined set of available colors.
+ *
+ *
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ColorDialog (Shell parent) {
+ this (parent, SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ColorDialog (Shell parent, int style) {
+ super (parent, checkStyle (parent, style));
+ checkSubclass ();
+}
+
+long CCHookProc (long hdlg, long uiMsg, long lParam, long lpData) {
+ switch ((int)uiMsg) {
+ case OS.WM_INITDIALOG: {
+ RECT rect = new RECT ();
+ OS.GetWindowRect (hdlg, rect);
+ width = rect.right - rect.left;
+ height = rect.bottom - rect.top;
+ if (title != null && title.length () != 0) {
+ /* Use the character encoding for the default locale */
+ TCHAR buffer = new TCHAR (0, title, true);
+ OS.SetWindowText (hdlg, buffer);
+ }
+ break;
+ }
+ case OS.WM_DESTROY: {
+ RECT rect = new RECT ();
+ OS.GetWindowRect (hdlg, rect);
+ int newWidth = rect.right - rect.left;
+ int newHeight = rect.bottom - rect.top;
+ if (newWidth < width || newHeight < height) {
+ //display.fullOpen = false;
+ } else {
+ if (newWidth > width || newHeight > height) {
+ //display.fullOpen = true;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Returns the currently selected color in the receiver.
+ *
+ * @return the RGB value for the selected color, may be null
+ *
+ * @see PaletteData#getRGBs
+ */
+public RGB getRGB () {
+ return rgb;
+}
+
+/**
+ * Returns an array of RGB
s which are the list of
+ * custom colors selected by the user in the receiver, or null
+ * if no custom colors were selected.
+ *
+ * @return the array of RGBs, which may be null
+ *
+ * @since 3.8
+ */
+public RGB[] getRGBs() {
+ return rgbs;
+}
+
+/**
+ * Makes the receiver visible and brings it to the front
+ * of the display.
+ *
+ * @return the selected color, or null if the dialog was
+ * cancelled, no color was selected, or an error
+ * occurred
+ *
+ * @exception SWTException
+ *
+ */
+public RGB open () {
+
+ /* Get the owner HWND for the dialog */
+ long hwndOwner = parent.handle;
+ long hwndParent = parent.handle;
+
+ /*
+ * Feature in Windows. There is no API to set the orientation of a
+ * color dialog. It is always inherited from the parent. The fix is
+ * to create a hidden parent and set the orientation in the hidden
+ * parent for the dialog to inherit.
+ */
+ boolean enabled = false;
+ int dialogOrientation = style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+ int parentOrientation = parent.style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+ if (dialogOrientation != parentOrientation) {
+ int exStyle = OS.WS_EX_NOINHERITLAYOUT;
+ if (dialogOrientation == SWT.RIGHT_TO_LEFT) exStyle |= OS.WS_EX_LAYOUTRTL;
+ hwndOwner = OS.CreateWindowEx (
+ exStyle,
+ Shell.DialogClass,
+ null,
+ 0,
+ OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
+ hwndParent,
+ 0,
+ OS.GetModuleHandle (null),
+ null);
+ enabled = OS.IsWindowEnabled (hwndParent);
+ if (enabled) OS.EnableWindow (hwndParent, false);
+ }
+
+ /* Create the CCHookProc */
+ Callback callback = new Callback (this, "CCHookProc", 4); //$NON-NLS-1$
+ long lpfnHook = callback.getAddress ();
+ if (lpfnHook == 0) error(SWT.ERROR_NO_MORE_CALLBACKS);
+
+ /* Allocate the Custom Colors and initialize to white */
+ display = parent.display;
+ if (display.lpCustColors == 0) {
+ long hHeap = OS.GetProcessHeap ();
+ display.lpCustColors = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, CUSTOM_COLOR_COUNT * 4);
+ for (int i=0; i < CUSTOM_COLOR_COUNT; i++) {
+ colors[i] = 0x00FFFFFF;
+ }
+ OS.MoveMemory (display.lpCustColors, colors, CUSTOM_COLOR_COUNT * 4);
+ }
+
+ /* Set the Custom Colors (if any) into the dialog */
+ if (rgbs != null) {
+ int length = rgbs.length > CUSTOM_COLOR_COUNT ? CUSTOM_COLOR_COUNT : rgbs.length;
+ for (int i=0; iRGB
s, which may be null to let the platform select
+ * a default when open() is called.
+ *
+ * @param rgbs the array of RGBs, which may be null
+ *
+ * @exception IllegalArgumentException
+ *
+ *
+ * @since 3.8
+ */
+public void setRGBs(RGB[] rgbs) {
+ if (rgbs != null) {
+ for (int i=0; iCombo
s are used in the same place
+ * where a single selection List
widget could
+ * be used but space is limited. A Combo
takes
+ * less space than a List
widget and shows
+ * similar information.
+ * Combo
s can contain both a list
+ * and an editable text field, it is possible to confuse methods
+ * which access one versus the other (compare for example,
+ * clearSelection()
and deselectAll()
).
+ * The API documentation is careful to indicate either "the
+ * receiver's list" or the "the receiver's text field" to
+ * distinguish between the two cases.
+ * Composite
,
+ * it does not make sense to add children to it, or set a layout on it.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#DROP_DOWN
+ * @see SWT#READ_ONLY
+ * @see SWT#SIMPLE
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Combo (Composite parent, int style) {
+ super (parent, checkStyle (style));
+ /* This code is intentionally commented */
+ //if ((style & SWT.H_SCROLL) != 0) this.style |= SWT.H_SCROLL;
+ this.style |= SWT.H_SCROLL;
+}
+
+/**
+ * Adds the argument to the end of the receiver's list.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #add(String,int)
+ */
+public void add (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ int result = (int)OS.SendMessage (handle, OS.CB_ADDSTRING, 0, buffer);
+ if (result == OS.CB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
+ if (result == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer.chars, true);
+}
+
+/**
+ * Adds the argument to the receiver's list at the given
+ * zero-relative index.
+ * getItemCount()
as the
+ * index or use add(String)
.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #add(String)
+ */
+public void add (String string, int index) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ if (!(0 <= index && index <= count)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ int result = (int)OS.SendMessage (handle, OS.CB_INSERTSTRING, index, buffer);
+ if (result == OS.CB_ERRSPACE || result == OS.CB_ERR) {
+ error (SWT.ERROR_ITEM_NOT_ADDED);
+ }
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer.chars, true);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is modified, by sending
+ * it one of the messages defined in the ModifyListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ModifyListener
+ * @see #removeModifyListener
+ */
+public void addModifyListener (ModifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Modify, typedListener);
+}
+
+/**
+ * Adds a segment listener.
+ * SegmentEvent
is sent whenever text content is being modified or
+ * a segment listener is added or removed. You can
+ * customize the appearance of text by indicating certain characters to be inserted
+ * at certain text offsets. This may be used for bidi purposes, e.g. when
+ * adjacent segments of right-to-left text should not be reordered relative to
+ * each other.
+ * E.g., multiple Java string literals in a right-to-left language
+ * should generally remain in logical order to each other, that is, the
+ * way they are stored.
+ * SegmentEvent
s won't be sent on GTK and Cocoa.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SegmentEvent
+ * @see SegmentListener
+ * @see #removeSegmentListener
+ *
+ * @since 3.103
+ */
+public void addSegmentListener (SegmentListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ addListener (SWT.Segments, new TypedListener (listener));
+ int selection = OS.CB_ERR;
+ if (!noSelection) {
+ selection = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ }
+ clearSegments (true);
+ applyEditSegments ();
+ applyListSegments ();
+ if (selection != OS.CB_ERR) {
+ OS.SendMessage (handle, OS.CB_SETCURSEL, selection, 0);
+ }
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called when the user changes the combo's list selection.
+ * widgetDefaultSelected
is typically called when ENTER is pressed the combo's text area.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is verified, by sending
+ * it one of the messages defined in the VerifyListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see VerifyListener
+ * @see #removeVerifyListener
+ *
+ * @since 3.1
+ */
+public void addVerifyListener (VerifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Verify, typedListener);
+}
+
+void applyEditSegments () {
+ if (--clearSegmentsCount != 0) return;
+ if (!hooks (SWT.Segments) && !filters (SWT.Segments) && (state & HAS_AUTO_DIRECTION) == 0) return;
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ int length = OS.GetWindowTextLength (hwndText);
+ char [] buffer = new char [length + 1];
+ if (length > 0) OS.GetWindowText (hwndText, buffer, length + 1);
+ String string = new String (buffer, 0, length);
+ /* Get segments */
+ segments = null;
+ Event event = getSegments (string);
+ if (event == null || event.segments == null) return;
+ segments = event.segments;
+ int nSegments = segments.length;
+ if (nSegments == 0) return;
+ char [] segmentsChars = event.segmentsChars;
+ int limit = (int)OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0) & 0x7fffffff;
+ OS.SendMessage (hwndText, OS.EM_SETLIMITTEXT, limit + Math.min (nSegments, LIMIT - limit), 0);
+ length += nSegments;
+ char [] newChars = new char [length + 1];
+ int charCount = 0, segmentCount = 0;
+ char defaultSeparator = getOrientation () == SWT.RIGHT_TO_LEFT ? RTL_MARK : LTR_MARK;
+ while (charCount < length) {
+ if (segmentCount < nSegments && charCount - segmentCount == segments [segmentCount]) {
+ char separator = segmentsChars != null && segmentsChars.length > segmentCount ? segmentsChars [segmentCount] : defaultSeparator;
+ newChars [charCount++] = separator;
+ segmentCount++;
+ } else if (string != null) {
+ newChars [charCount] = string.charAt (charCount++ - segmentCount);
+ }
+ }
+ while (segmentCount < nSegments) {
+ segments [segmentCount] = charCount - segmentCount;
+ char separator = segmentsChars != null && segmentsChars.length > segmentCount ? segmentsChars [segmentCount] : defaultSeparator;
+ newChars [charCount++] = separator;
+ segmentCount++;
+ }
+ /* Get the current selection */
+ int [] start = new int [1], end = new int [1];
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ boolean oldIgnoreCharacter = ignoreCharacter, oldIgnoreModify = ignoreModify;
+ ignoreCharacter = ignoreModify = true;
+ /*
+ * SetWindowText empties the undo buffer and disables undo menu item.
+ * Sending OS.EM_REPLACESEL message instead.
+ */
+ newChars [length] = 0;
+ OS.SendMessage (hwndText, OS.EM_SETSEL, 0, -1);
+ long undo = OS.SendMessage (hwndText, OS.EM_CANUNDO, 0, 0);
+ OS.SendMessage (hwndText, OS.EM_REPLACESEL, undo, newChars);
+ /* Restore selection */
+ start [0] = translateOffset (start [0]);
+ end [0] = translateOffset (end [0]);
+ if (segmentsChars != null && segmentsChars.length > 0) {
+ /*
+ * In addition to enforcing the required direction by prepending a UCC (LRE
+ * or RLE), also set the direction through a Window style.
+ * This is to ensure correct caret movement, and makes sense even when the
+ * UCC was added by an authentic SegmentListener.
+ */
+ int auto = state & HAS_AUTO_DIRECTION;
+ if (segmentsChars[0] == RLE) {
+ super.updateTextDirection(SWT.RIGHT_TO_LEFT);
+ } else if (segmentsChars[0] == LRE) {
+ super.updateTextDirection(SWT.LEFT_TO_RIGHT);
+ }
+ state |= auto;
+ }
+ OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], end [0]);
+ ignoreCharacter = oldIgnoreCharacter;
+ ignoreModify = oldIgnoreModify;
+}
+
+void applyListSegments () {
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ if (count == OS.CB_ERR) return;
+ boolean add = items.length != count;
+ if (add) items = new String [count];
+ int index = items.length;
+ int selection = OS.CB_ERR;
+ int cp = getCodePage ();
+ String string;
+ TCHAR buffer;
+ if (!noSelection) {
+ selection = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ }
+ while (index-- > 0) {
+ buffer = null;
+ if (add) {
+ int length = (int)OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, index, 0);
+ if (length == OS.CB_ERR) error (SWT.ERROR);
+ buffer = new TCHAR (cp, length + 1);
+ if (OS.SendMessage (handle, OS.CB_GETLBTEXT, index, buffer) == OS.CB_ERR) return;
+ items [index] = string = buffer.toString (0, length);
+ } else {
+ string = items [index];
+ }
+ if (OS.SendMessage (handle, OS.CB_DELETESTRING, index, 0) == OS.CB_ERR) return;
+ if (buffer == null) buffer = new TCHAR (cp, string, true);
+ if (OS.SendMessage (handle, OS.CB_INSERTSTRING, index, buffer) == OS.CB_ERR) return;
+ }
+ if (selection != OS.CB_ERR) {
+ OS.SendMessage (handle, OS.CB_SETCURSEL, selection, 0);
+ }
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ if (hwnd == handle) {
+ switch (msg) {
+ case OS.WM_SIZE: {
+ ignoreResize = true;
+ boolean oldLockText = lockText;
+ if ((style & SWT.READ_ONLY) == 0) lockText = true;
+ long result = OS.CallWindowProc (ComboProc, hwnd, msg, wParam, lParam);
+ if ((style & SWT.READ_ONLY) == 0) lockText = oldLockText;
+ ignoreResize = false;
+ return result;
+ }
+ }
+ return OS.CallWindowProc (ComboProc, hwnd, msg, wParam, lParam);
+ }
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwnd == hwndText) {
+ if (lockText && msg == OS.WM_SETTEXT) {
+ long hHeap = OS.GetProcessHeap ();
+ int length = OS.GetWindowTextLength (handle);
+ char [] buffer = new char [length + 1];
+ OS.GetWindowText (handle, buffer, length + 1);
+ int byteCount = buffer.length * TCHAR.sizeof;
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory (pszText, buffer, byteCount);
+ long code = OS.CallWindowProc (EditProc, hwndText, msg, wParam, pszText);
+ OS.HeapFree (hHeap, 0, pszText);
+ return code;
+ }
+ return OS.CallWindowProc (EditProc, hwnd, msg, wParam, lParam);
+ }
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwnd == hwndList) {
+ return OS.CallWindowProc (ListProc, hwnd, msg, wParam, lParam);
+ }
+ return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+}
+
+long CBTProc (long nCode, long wParam, long lParam) {
+ if ((int)nCode == OS.HCBT_CREATEWND) {
+ char [] buffer = new char [128];
+ int length = OS.GetClassName (wParam, buffer, buffer.length);
+ String className = new String (buffer, 0, length);
+ if (className.equals ("Edit") || className.equals ("EDIT")) { //$NON-NLS-1$ //$NON-NLS-2$
+ int bits = OS.GetWindowLong (wParam, OS.GWL_STYLE);
+ OS.SetWindowLong (wParam, OS.GWL_STYLE, bits & ~OS.ES_NOHIDESEL);
+ }
+ }
+ return OS.CallNextHookEx (cbtHook, (int)nCode, wParam, lParam);
+}
+
+@Override
+boolean checkHandle (long hwnd) {
+ return hwnd == handle || hwnd == OS.GetDlgItem (handle, CBID_EDIT) || hwnd == OS.GetDlgItem (handle, CBID_LIST);
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+static int checkStyle (int style) {
+ /*
+ * Feature in Windows. It is not possible to create
+ * a combo box that has a border using Windows style
+ * bits. All combo boxes draw their own border and
+ * do not use the standard Windows border styles.
+ * Therefore, no matter what style bits are specified,
+ * clear the BORDER bits so that the SWT style will
+ * match the Windows widget.
+ *
+ * The Windows behavior is currently implemented on
+ * all platforms.
+ */
+ style &= ~SWT.BORDER;
+
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ style &= ~(SWT.H_SCROLL | SWT.V_SCROLL);
+ style = checkBits (style, SWT.DROP_DOWN, SWT.SIMPLE, 0, 0, 0, 0);
+ if ((style & SWT.SIMPLE) != 0) return style & ~SWT.READ_ONLY;
+ return style;
+}
+
+void clearSegments (boolean applyText) {
+ if (clearSegmentsCount++ != 0) return;
+ if (segments == null) return;
+ int nSegments = segments.length;
+ if (nSegments == 0) return;
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ int limit = (int)OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0) & 0x7fffffff;
+ if (limit < LIMIT) {
+ OS.SendMessage (hwndText, OS.EM_SETLIMITTEXT, Math.max (1, limit - nSegments), 0);
+ }
+ if (!applyText) {
+ segments = null;
+ return;
+ }
+ boolean oldIgnoreCharacter = ignoreCharacter, oldIgnoreModify = ignoreModify;
+ ignoreCharacter = ignoreModify = true;
+ int length = OS.GetWindowTextLength (hwndText);
+ int cp = getCodePage ();
+ TCHAR buffer = new TCHAR (cp, length + 1);
+ if (length > 0) OS.GetWindowText (hwndText, buffer, length + 1);
+ buffer = deprocessText (buffer, 0, -1, true);
+ /* Get the current selection */
+ int [] start = new int [1], end = new int [1];
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ start [0] = untranslateOffset (start [0]);
+ end [0] = untranslateOffset (end[0]);
+
+ segments = null;
+ /*
+ * SetWindowText empties the undo buffer and disables undo in the context
+ * menu. Sending OS.EM_REPLACESEL message instead.
+ */
+ OS.SendMessage (hwndText, OS.EM_SETSEL, 0, -1);
+ long undo = OS.SendMessage (hwndText, OS.EM_CANUNDO, 0, 0);
+ OS.SendMessage (hwndText, OS.EM_REPLACESEL, undo, buffer);
+ OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], end [0]);
+ ignoreCharacter = oldIgnoreCharacter;
+ ignoreModify = oldIgnoreModify;
+}
+
+/**
+ * Sets the selection in the receiver's text field to an empty
+ * selection starting just before the first character. If the
+ * text field is editable, this has the effect of placing the
+ * i-beam at the start of the text.
+ * deselectAll()
.
+ *
+ *
+ *
+ * @see #deselectAll
+ */
+public void clearSelection () {
+ checkWidget ();
+ OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, -1);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0;
+ if (wHint == SWT.DEFAULT) {
+ long newFont, oldFont = 0;
+ long hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ RECT rect = new RECT ();
+ int flags = OS.DT_CALCRECT | OS.DT_NOPREFIX;
+ if ((style & SWT.READ_ONLY) == 0) flags |= OS.DT_EDITCONTROL;
+ int length = OS.GetWindowTextLength (handle);
+ char [] buffer = new char [length + 1];
+ OS.GetWindowText (handle, buffer, length + 1);
+ OS.DrawText (hDC, buffer, length, rect, flags);
+ width = Math.max (width, rect.right - rect.left);
+ if ((style & SWT.H_SCROLL) != 0) {
+ width = Math.max (width, scrollWidth);
+ } else {
+ for (int i=0; i
+ *
+ *
+ * @since 2.1
+ */
+public void copy () {
+ checkWidget ();
+ OS.SendMessage (handle, OS.WM_COPY, 0, 0);
+}
+
+@Override
+void createHandle () {
+ /*
+ * Feature in Windows. When the selection changes in a combo box,
+ * Windows draws the selection, even when the combo box does not
+ * have focus. Strictly speaking, this is the correct Windows
+ * behavior because the combo box sets ES_NOHIDESEL on the text
+ * control that it creates. Despite this, it looks strange because
+ * Windows also clears the selection and selects all the text when
+ * the combo box gets focus. The fix is use the CBT hook to clear
+ * the ES_NOHIDESEL style bit when the text control is created.
+ */
+ if ((style & (SWT.READ_ONLY | SWT.SIMPLE)) != 0) {
+ super.createHandle ();
+ } else {
+ int threadId = OS.GetCurrentThreadId ();
+ Callback cbtCallback = new Callback (this, "CBTProc", 3); //$NON-NLS-1$
+ long cbtProc = cbtCallback.getAddress ();
+ if (cbtProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ cbtHook = OS.SetWindowsHookEx (OS.WH_CBT, cbtProc, 0, threadId);
+ super.createHandle ();
+ if (cbtHook != 0) OS.UnhookWindowsHookEx (cbtHook);
+ cbtHook = 0;
+ cbtCallback.dispose ();
+ }
+ state &= ~(CANVAS | THEME_BACKGROUND);
+
+ stateFlagsUsable = stateFlagsTest();
+
+ /* Get the text and list window procs */
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0 && EditProc == 0) {
+ EditProc = OS.GetWindowLongPtr (hwndText, OS.GWLP_WNDPROC);
+ }
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndList != 0 && ListProc == 0) {
+ ListProc = OS.GetWindowLongPtr (hwndList, OS.GWLP_WNDPROC);
+ }
+
+ /*
+ * Bug in Windows. If the combo box has the CBS_SIMPLE style,
+ * the list portion of the combo box is not drawn correctly the
+ * first time, causing pixel corruption. The fix is to ensure
+ * that the combo box has been resized more than once.
+ */
+ if ((style & SWT.SIMPLE) != 0) {
+ int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (handle, 0, 0, 0, 0x3FFF, 0x3FFF, flags);
+ OS.SetWindowPos (handle, 0, 0, 0, 0, 0, flags);
+ }
+}
+
+@Override
+void createWidget() {
+ super.createWidget();
+ visibleCount = VISIBLE_COUNT;
+ if ((style & SWT.SIMPLE) == 0) {
+ int itemHeight = (int)OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0);
+ if (itemHeight != OS.CB_ERR && itemHeight != 0) {
+ int maxHeight = 0;
+ long hmonitor = OS.MonitorFromWindow (handle, OS.MONITOR_DEFAULTTONEAREST);
+ MONITORINFO lpmi = new MONITORINFO ();
+ lpmi.cbSize = MONITORINFO.sizeof;
+ OS.GetMonitorInfo (hmonitor, lpmi);
+ maxHeight = (lpmi.rcWork_bottom - lpmi.rcWork_top) / 3;
+ visibleCount = Math.max(visibleCount, maxHeight / itemHeight);
+ }
+ }
+}
+
+/**
+ * Cuts the selected text.
+ *
+ *
+ *
+ * @since 2.1
+ */
+public void cut () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ OS.SendMessage (handle, OS.WM_CUT, 0, 0);
+}
+
+@Override
+int defaultBackground () {
+ return OS.GetSysColor (OS.COLOR_WINDOW);
+}
+
+TCHAR deprocessText (TCHAR text, int start, int end, boolean terminate) {
+ if (text == null || segments == null) return text;
+ int length = text.length();
+ if (length == 0) return text;
+ int nSegments = segments.length;
+ if (nSegments == 0) return text;
+ char [] chars;
+ if (start < 0) start = 0;
+ chars = text.chars;
+ if (text.chars [length - 1] == 0) length--;
+ if (end == -1) end = length;
+ if (end > segments [0] && start <= segments [nSegments - 1]) {
+ int nLeadSegments = 0;
+ while (start - nLeadSegments > segments [nLeadSegments]) nLeadSegments++;
+ int segmentCount = nLeadSegments;
+ for (int i = start; i < end; i++) {
+ if (segmentCount < nSegments && i - segmentCount == segments [segmentCount]) {
+ ++segmentCount;
+ } else {
+ chars [i - segmentCount + nLeadSegments] = chars [i];
+ }
+ }
+ length = end - start - segmentCount + nLeadSegments;
+ }
+ if (start != 0 || end != length) {
+ char [] newChars = new char [length];
+ System.arraycopy(chars, start, newChars, 0, length);
+ return new TCHAR (getCodePage (), newChars, terminate);
+ }
+ return text;
+}
+
+@Override
+void deregister () {
+ super.deregister ();
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0) display.removeControl (hwndText);
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndList != 0) display.removeControl (hwndList);
+}
+
+/**
+ * Deselects the item at the given zero-relative index in the receiver's
+ * list. If the item at the index was already deselected, it remains
+ * deselected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to deselect
+ *
+ * @exception SWTException
+ *
+ */
+public void deselect (int index) {
+ checkWidget ();
+ int selection = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ if (index != selection) return;
+ OS.SendMessage (handle, OS.CB_SETCURSEL, -1, 0);
+ sendEvent (SWT.Modify);
+ // widget could be disposed at this point
+ clearSegments (false);
+ clearSegmentsCount--;
+}
+
+/**
+ * Deselects all selected items in the receiver's list.
+ * clearSelection()
.
+ *
+ *
+ *
+ * @see #clearSelection
+ */
+public void deselectAll () {
+ checkWidget ();
+ OS.SendMessage (handle, OS.CB_SETCURSEL, -1, 0);
+ sendEvent (SWT.Modify);
+ // widget could be disposed at this point
+ clearSegments (false);
+ clearSegmentsCount--;
+}
+
+@Override
+boolean dragDetect (long hwnd, int x, int y, boolean filter, boolean [] detect, boolean [] consume) {
+ if (filter && (style & SWT.READ_ONLY) == 0) {
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0) {
+ int [] start = new int [1], end = new int [1];
+ OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end);
+ if (start [0] != end [0]) {
+ long lParam = OS.MAKELPARAM (x, y);
+ int position = OS.LOWORD (OS.SendMessage (hwndText, OS.EM_CHARFROMPOS, 0, lParam));
+ if (start [0] <= position && position < end [0]) {
+ if (super.dragDetect (hwnd, x, y, filter, detect, consume)) {
+ if (consume != null) consume [0] = true;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+ return super.dragDetect (hwnd, x, y, filter, detect, consume);
+}
+
+/**
+ * Returns a point describing the location of the caret relative
+ * to the receiver.
+ *
+ * @return a point, the location of the caret
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.8
+ */
+public Point getCaretLocation () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getCaretLocationInPixels());
+}
+
+Point getCaretLocationInPixels () {
+ /*
+ * Bug in Windows. For some reason, Windows is unable
+ * to return the pixel coordinates of the last character
+ * in the widget. The fix is to temporarily insert a
+ * space, query the coordinates and delete the space.
+ * The selection is always an i-beam in this case because
+ * this is the only time the start of the selection can
+ * be equal to the last character position in the widget.
+ * If EM_POSFROMCHAR fails for any other reason, return
+ * pixel coordinates (0,0).
+ */
+ int position = translateOffset (getCaretPosition ());
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ long caretPos = OS.SendMessage (hwndText, OS.EM_POSFROMCHAR, position, 0);
+ if (caretPos == -1) {
+ caretPos = 0;
+ if (position >= OS.GetWindowTextLength (hwndText)) {
+ int [] start = new int [1], end = new int [1];
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ OS.SendMessage (hwndText, OS.EM_SETSEL, position, position);
+ /*
+ * Feature in Windows. When an edit control with ES_MULTILINE
+ * style that does not have the WS_VSCROLL style is full (i.e.
+ * there is no space at the end to draw any more characters),
+ * EM_REPLACESEL sends a WM_CHAR with a backspace character
+ * to remove any further text that is added. This is an
+ * implementation detail of the edit control that is unexpected
+ * and can cause endless recursion when EM_REPLACESEL is sent
+ * from a WM_CHAR handler. The fix is to ignore calling the
+ * handler from WM_CHAR.
+ */
+ ignoreCharacter = ignoreModify = true;
+ OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, new char [] {' ', '\0'});
+ caretPos = OS.SendMessage (hwndText, OS.EM_POSFROMCHAR, position, 0);
+ OS.SendMessage (hwndText, OS.EM_SETSEL, position, position + 1);
+ OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, new char [1]);
+ ignoreCharacter = ignoreModify = false;
+ OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], start [0]);
+ OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], end [0]);
+ }
+ }
+ POINT point = new POINT ();
+ point.x = OS.GET_X_LPARAM (caretPos);
+ point.y = OS.GET_Y_LPARAM (caretPos);
+ OS.MapWindowPoints (hwndText, handle, point, 1);
+ return new Point (point.x, point.y);
+}
+
+/**
+ * Returns the character position of the caret.
+ *
+ *
+ *
+ * @since 3.8
+ */
+public int getCaretPosition () {
+ checkWidget ();
+ int [] start = new int [1], end = new int [1];
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ /*
+ * In Windows, there is no API to get the position of the caret
+ * when the selection is not an i-beam. The best that can be done
+ * is to query the pixel position of the current caret and compare
+ * it to the pixel position of the start and end of the selection.
+ *
+ * NOTE: This does not work when the i-beam belongs to another
+ * control. In this case, guess that the i-beam is at the start
+ * of the selection.
+ */
+ int caret = start [0];
+ if (start [0] != end [0]) {
+ int idThread = OS.GetWindowThreadProcessId (hwndText, null);
+ GUITHREADINFO lpgui = new GUITHREADINFO ();
+ lpgui.cbSize = GUITHREADINFO.sizeof;
+ if (OS.GetGUIThreadInfo (idThread, lpgui)) {
+ if (lpgui.hwndCaret == hwndText || lpgui.hwndCaret == 0) {
+ POINT ptCurrentPos = new POINT ();
+ if (OS.GetCaretPos (ptCurrentPos)) {
+ long endPos = OS.SendMessage (hwndText, OS.EM_POSFROMCHAR, end [0], 0);
+ if (endPos == -1) {
+ long startPos = OS.SendMessage (hwndText, OS.EM_POSFROMCHAR, start [0], 0);
+ int startX = OS.GET_X_LPARAM (startPos);
+ if (ptCurrentPos.x > startX) caret = end [0];
+ } else {
+ int endX = OS.GET_X_LPARAM (endPos);
+ if (ptCurrentPos.x >= endX) caret = end [0];
+ }
+ }
+ }
+ }
+ }
+ return untranslateOffset (caret);
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver's list. Throws an exception if the index is out
+ * of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public String getItem (int index) {
+ checkWidget ();
+ int length = (int)OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, index, 0);
+ if (length != OS.CB_ERR) {
+ if (hooks (SWT.Segments) || filters (SWT.Segments) || (state & HAS_AUTO_DIRECTION) != 0) return items [index];
+ char [] buffer = new char [length + 1];
+ int result = (int)OS.SendMessage (handle, OS.CB_GETLBTEXT, index, buffer);
+ if (result != OS.CB_ERR) return new String (buffer, 0, length);
+ }
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ if (0 <= index && index < count) error (SWT.ERROR_CANNOT_GET_ITEM);
+ error (SWT.ERROR_INVALID_RANGE);
+ return "";
+}
+
+/**
+ * Returns the number of items contained in the receiver's list.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemCount () {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ if (count == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
+ return count;
+}
+
+/**
+ * Returns the height of the area which would be used to
+ * display one of the items in the receiver's list.
+ *
+ * @return the height of one item
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemHeight () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getItemHeightInPixels());
+}
+
+int getItemHeightInPixels () {
+ int result = (int)OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0);
+ if (result == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
+ return result;
+}
+
+/**
+ * Returns a (possibly empty) array of String
s which are
+ * the items in the receiver's list.
+ *
+ *
+ */
+public String [] getItems () {
+ checkWidget ();
+ String [] result;
+ int count = getItemCount ();
+ result = new String [count];
+ for (int i=0; ifalse
otherwise.
+ *
+ *
+ *
+ * @since 3.4
+ */
+public boolean getListVisible () {
+ checkWidget ();
+ if ((style & SWT.DROP_DOWN) != 0) {
+ return OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0;
+ }
+ return true;
+}
+
+@Override
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Marks the receiver's list as visible if the argument is true
,
+ * and marks it invisible otherwise.
+ *
+ *
+ *
+ * @since 3.4
+ */
+public void setListVisible (boolean visible) {
+ checkWidget ();
+ OS.SendMessage (handle, OS.CB_SHOWDROPDOWN, visible ? 1 : 0, 0);
+}
+
+/**
+ * Returns the orientation of the receiver.
+ *
+ * @return the orientation style
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.1.2
+ */
+@Override
+public int getOrientation () {
+ return super.getOrientation ();
+}
+
+Event getSegments (String string) {
+ Event event = null;
+ if (hooks (SWT.Segments) || filters (SWT.Segments)) {
+ event = new Event ();
+ event.text = string;
+ sendEvent (SWT.Segments, event);
+ if (event != null && event.segments != null) {
+ for (int i = 1, segmentCount = event.segments.length, lineLength = string == null ? 0 : string.length(); i < segmentCount; i++) {
+ if (event.segments[i] < event.segments[i - 1] || event.segments[i] > lineLength) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ }
+ }
+ if ((state & HAS_AUTO_DIRECTION) != 0) {
+ int direction = BidiUtil.resolveTextDirection(string);
+ if (direction == SWT.NONE) {
+ /*
+ * Force adding a UCC even when no strong characters are found.
+ * Otherwise, the widget would keep the old direction, which might be
+ * inappropriate for the new text.
+ */
+ direction = (style & SWT.RIGHT_TO_LEFT) != 0 ? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT;
+ }
+ int [] oldSegments = null;
+ char [] oldSegmentsChars = null;
+ if (event == null) {
+ event = new Event ();
+ } else {
+ oldSegments = event.segments;
+ oldSegmentsChars = event.segmentsChars;
+ }
+ int nSegments = oldSegments == null ? 0 : oldSegments.length;
+ event.segments = new int [nSegments + 1];
+ event.segmentsChars = new char [nSegments + 1];
+ if (oldSegments != null) {
+ System.arraycopy(oldSegments, 0, event.segments, 1, nSegments);
+ }
+ if (oldSegmentsChars != null) {
+ System.arraycopy(oldSegmentsChars, 0, event.segmentsChars, 1, nSegments);
+ }
+ event.segments [0] = 0;
+ event.segmentsChars [0] = direction == SWT.RIGHT_TO_LEFT ? RLE : LRE;
+ }
+ return event;
+}
+
+String getSegmentsText (String text, Event event) {
+ if (text == null || event == null) return text;
+ int[] segments = event.segments;
+ if (segments == null) return text;
+ int nSegments = segments.length;
+ if (nSegments == 0) return text;
+ char[] segmentsChars = /*event == null ? this.segmentsChars : */event.segmentsChars;
+ int length = text.length();
+ char[] oldChars = new char[length];
+ text.getChars (0, length, oldChars, 0);
+ char[] newChars = new char[length + nSegments];
+ int charCount = 0, segmentCount = 0;
+ char defaultSeparator = getOrientation () == SWT.RIGHT_TO_LEFT ? RTL_MARK : LTR_MARK;
+ while (charCount < length) {
+ if (segmentCount < nSegments && charCount == segments[segmentCount]) {
+ char separator = segmentsChars != null && segmentsChars.length > segmentCount ? segmentsChars[segmentCount] : defaultSeparator;
+ newChars[charCount + segmentCount++] = separator;
+ } else {
+ newChars[charCount + segmentCount] = oldChars[charCount++];
+ }
+ }
+ while (segmentCount < nSegments) {
+ segments[segmentCount] = charCount;
+ char separator = segmentsChars != null && segmentsChars.length > segmentCount ? segmentsChars[segmentCount] : defaultSeparator;
+ newChars[charCount + segmentCount++] = separator;
+ }
+ return new String(newChars, 0, newChars.length);
+}
+
+/**
+ * Returns a Point
whose x coordinate is the
+ * character position representing the start of the selection
+ * in the receiver's text field, and whose y coordinate is the
+ * character position representing the end of the selection.
+ * An "empty" selection is indicated by the x and y coordinates
+ * having the same value.
+ *
+ *
+ */
+public Point getSelection () {
+ checkWidget ();
+ if ((style & SWT.DROP_DOWN) != 0 && (style & SWT.READ_ONLY) != 0) {
+ return new Point (0, OS.GetWindowTextLength (handle));
+ }
+ int [] start = new int [1], end = new int [1];
+ OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end);
+ return new Point (untranslateOffset (start [0]), untranslateOffset (end [0]));
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * selected in the receiver's list, or -1 if no item is selected.
+ *
+ * @return the index of the selected item
+ *
+ * @exception SWTException
+ *
+ */
+public int getSelectionIndex () {
+ checkWidget ();
+ if (noSelection) return -1;
+ return (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+}
+
+/**
+ * Returns a string containing a copy of the contents of the
+ * receiver's text field, or an empty string if there are no
+ * contents.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException
+ *
+ */
+public String getText () {
+ checkWidget ();
+ int length = OS.GetWindowTextLength (handle);
+ if (length == 0) return "";
+ TCHAR buffer = new TCHAR (getCodePage (), length + 1);
+ OS.GetWindowText (handle, buffer, length + 1);
+ if (segments != null) {
+ buffer = deprocessText (buffer, 0, -1, false);
+ return buffer.toString ();
+ }
+
+ return buffer.toString (0, length);
+}
+
+/**
+ * Returns the height of the receivers's text field.
+ *
+ * @return the text height
+ *
+ * @exception SWTException
+ *
+ */
+public int getTextHeight () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getTextHeightInPixels());
+}
+
+int getTextHeightInPixels () {
+ COMBOBOXINFO pcbi = new COMBOBOXINFO ();
+ pcbi.cbSize = COMBOBOXINFO.sizeof;
+ if (((style & SWT.SIMPLE) == 0) && OS.GetComboBoxInfo (handle, pcbi)) {
+ return (pcbi.buttonBottom - pcbi.buttonTop) + pcbi.buttonTop * 2;
+ }
+ int result = (int)OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, -1, 0);
+ if (result == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
+ return (style & SWT.DROP_DOWN) != 0 ? result + 6 : result + 10;
+}
+
+/**
+ * Returns the maximum number of characters that the receiver's
+ * text field is capable of holding. If this has not been changed
+ * by setTextLimit()
, it will be the constant
+ * Combo.LIMIT
.
+ *
+ * @return the text limit
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #LIMIT
+ */
+public int getTextLimit () {
+ checkWidget ();
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText == 0) return LIMIT;
+ int limit = (int)OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
+ if (segments != null && limit < LIMIT) limit = Math.max (1, limit - segments.length);
+ return limit;
+}
+
+/**
+ * Gets the number of items that are visible in the drop
+ * down portion of the receiver's list.
+ *
+ *
+ *
+ * @since 3.0
+ */
+public int getVisibleItemCount () {
+ checkWidget ();
+ return visibleCount;
+}
+
+@Override
+boolean hasFocus () {
+ long hwndFocus = OS.GetFocus ();
+ if (hwndFocus == handle) return true;
+ if (hwndFocus == 0) return false;
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndFocus == hwndText) return true;
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndFocus == hwndList) return true;
+ return false;
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param string the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public int indexOf (String string) {
+ return indexOf (string, 0);
+}
+
+/**
+ * Searches the receiver's list starting at the given,
+ * zero-relative index until an item is found that is equal
+ * to the argument, and returns the index of that item. If
+ * no item is found or the starting index is out of range,
+ * returns -1.
+ *
+ * @param string the search item
+ * @param start the zero-relative index at which to begin the search
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public int indexOf (String string, int start) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+
+ /*
+ * Bug in Windows. For some reason, CB_FINDSTRINGEXACT
+ * will not find empty strings even though it is legal
+ * to insert an empty string into a combo. The fix is
+ * to search the combo, an item at a time.
+ */
+ if (string.length () == 0) {
+ int count = getItemCount ();
+ for (int i=start; i
+ *
+ *
+ * @since 2.1
+ */
+public void paste () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ OS.SendMessage (handle, OS.WM_PASTE, 0, 0);
+}
+
+void stateFlagsAdd(int flags) {
+ final long tagCBoxPtr = OS.GetWindowLongPtr(handle, 0);
+ /*
+ * Bug 550423: When non-XP-theme COMMCTL32.DLL gets loaded, undocumented
+ * internal data is not there. We do not support that and in such case
+ * GetWindowLongPtr function fails and return zero.
+ */
+ if (tagCBoxPtr == 0) return;
+ final long stateFlagsPtr = tagCBoxPtr + stateFlagsOffset;
+
+ int stateFlags[] = new int[1];
+ OS.MoveMemory(stateFlags, stateFlagsPtr, 4);
+ stateFlags[0] |= flags;
+ OS.MoveMemory(stateFlagsPtr, stateFlags, 4);
+}
+
+/*
+ * Verify that undocumented internal data is in expected location.
+ * The test is performed at creation time, when the value of state flags is predictable.
+ * For simplicity, only SWT.READ_ONLY combos are handled.
+ */
+boolean stateFlagsTest() {
+ final long tagCBoxPtr = OS.GetWindowLongPtr(handle, 0);
+ /*
+ * Bug 550423: When non-XP-theme COMMCTL32.DLL gets loaded, undocumented
+ * internal data is not there. We do not support that and in such case
+ * GetWindowLongPtr function fails and return zero.
+ */
+ if (tagCBoxPtr == 0) return false;
+ final long stateFlagsPtr = tagCBoxPtr + stateFlagsOffset;
+
+ int stateFlags[] = new int[1];
+ OS.MoveMemory(stateFlags, stateFlagsPtr, 4);
+
+ /*
+ * 0x00000002 is unknown
+ * 0x00002000 is set in WM_NCCREATE
+ * 0x00004000 means CBS_DROPDOWNLIST (SWT.READ_ONLY)
+ * 0x02000000 is set in WM_NCCREATE and reset after first WM_PAINT
+ */
+ return (stateFlags[0] == 0x02006002);
+}
+
+@Override
+void register () {
+ super.register ();
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0) display.addControl (hwndText, this);
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndList != 0) display.addControl (hwndList, this);
+}
+
+/**
+ * Removes the item from the receiver's list at the given
+ * zero-relative index.
+ *
+ * @param index the index for the item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void remove (int index) {
+ checkWidget ();
+ remove (index, true);
+}
+
+void remove (int index, boolean notify) {
+ char [] buffer = null;
+ if ((style & SWT.H_SCROLL) != 0) {
+ int length = (int)OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, index, 0);
+ if (length == OS.CB_ERR) {
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ buffer = new char [length + 1];
+ int result = (int)OS.SendMessage (handle, OS.CB_GETLBTEXT, index, buffer);
+ if (result == OS.CB_ERR) {
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ }
+ int length = OS.GetWindowTextLength (handle);
+ int code = (int)OS.SendMessage (handle, OS.CB_DELETESTRING, index, 0);
+ if (code == OS.CB_ERR) {
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ else if (code == 0) {
+ /*
+ * Bug in Windows, when combo had exactly one item, that was
+ * currently selected & is removed, the combo box does not clear the
+ * text area. The fix is to reset contents of the Combo. Bug#440671
+ */
+ OS.SendMessage (handle, OS.CB_RESETCONTENT, 0, 0);
+ }
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
+ if (notify && length != OS.GetWindowTextLength (handle)) {
+ sendEvent (SWT.Modify);
+ if (isDisposed ()) return;
+ }
+}
+
+/**
+ * Removes the items from the receiver's list which are
+ * between the given zero-relative start and end
+ * indices (inclusive).
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void remove (int start, int end) {
+ checkWidget ();
+ if (start > end) return;
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ if (!(0 <= start && start <= end && end < count)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ int textLength = OS.GetWindowTextLength (handle);
+ RECT rect = null;
+ long hDC = 0, oldFont = 0, newFont = 0;
+ int newWidth = 0;
+ if ((style & SWT.H_SCROLL) != 0) {
+ rect = new RECT ();
+ hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ }
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
+ for (int i=start; i<=end; i++) {
+ char [] buffer = null;
+ if ((style & SWT.H_SCROLL) != 0) {
+ int length = (int)OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, start, 0);
+ if (length == OS.CB_ERR) break;
+ buffer = new char [length + 1];
+ int result = (int)OS.SendMessage (handle, OS.CB_GETLBTEXT, start, buffer);
+ if (result == OS.CB_ERR) break;
+ }
+ int result = (int)OS.SendMessage (handle, OS.CB_DELETESTRING, start, 0);
+ if (result == OS.CB_ERR) {
+ error (SWT.ERROR_ITEM_NOT_REMOVED);
+ }
+ else if (result == 0) {
+ /*
+ * Bug in Windows, when combo had exactly one item, that was
+ * currently selected & is removed, the combo box does not clear the
+ * text area. The fix is to reset contents of the Combo. Bug#440671
+ */
+ OS.SendMessage (handle, OS.CB_RESETCONTENT, 0, 0);
+ }
+ if ((style & SWT.H_SCROLL) != 0) {
+ OS.DrawText (hDC, buffer, -1, rect, flags);
+ newWidth = Math.max (newWidth, rect.right - rect.left);
+ }
+ }
+ if ((style & SWT.H_SCROLL) != 0) {
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ setScrollWidth (newWidth, false);
+ }
+ if (textLength != OS.GetWindowTextLength (handle)) {
+ sendEvent (SWT.Modify);
+ if (isDisposed ()) return;
+ }
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * until an item is found that is equal to the argument,
+ * and removes that item from the list.
+ *
+ * @param string the item to remove
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void remove (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int index = indexOf (string, 0);
+ if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT);
+ remove (index);
+}
+
+/**
+ * Removes all of the items from the receiver's list and clear the
+ * contents of receiver's text field.
+ * @exception SWTException
+ *
+ */
+public void removeAll () {
+ checkWidget ();
+ OS.SendMessage (handle, OS.CB_RESETCONTENT, 0, 0);
+ sendEvent (SWT.Modify);
+ if (isDisposed ()) return;
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth (0);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver's text is modified.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ModifyListener
+ * @see #addModifyListener
+ */
+public void removeModifyListener (ModifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Modify, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver's text is modified.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SegmentEvent
+ * @see SegmentListener
+ * @see #addSegmentListener
+ *
+ * @since 3.103
+ */
+public void removeSegmentListener (SegmentListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ eventTable.unhook (SWT.Segments, listener);
+ int selection = OS.CB_ERR;
+ if (!noSelection) {
+ selection = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ }
+ clearSegments (true);
+ applyEditSegments ();
+ applyListSegments ();
+ if (selection != OS.CB_ERR) {
+ OS.SendMessage (handle, OS.CB_SETCURSEL, selection, 0);
+ }
+}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is verified.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see VerifyListener
+ * @see #addVerifyListener
+ *
+ * @since 3.1
+ */
+public void removeVerifyListener (VerifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Verify, listener);
+}
+
+@Override
+boolean sendKeyEvent (int type, int msg, long wParam, long lParam, Event event) {
+ if (!super.sendKeyEvent (type, msg, wParam, lParam, event)) {
+ return false;
+ }
+ if ((style & SWT.READ_ONLY) != 0) return true;
+ if (type != SWT.KeyDown) return true;
+ if (msg != OS.WM_CHAR && msg != OS.WM_KEYDOWN && msg != OS.WM_IME_CHAR) {
+ return true;
+ }
+ if (event.character == 0) return true;
+ if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return true;
+ char key = event.character;
+ int stateMask = event.stateMask;
+
+ /*
+ * Disable all magic keys that could modify the text
+ * and don't send events when Alt, Shift or Ctrl is
+ * pressed.
+ */
+ switch (msg) {
+ case OS.WM_CHAR:
+ if (key != 0x08 && key != 0x7F && key != '\r' && key != '\t' && key != '\n') break;
+ // FALL THROUGH
+ case OS.WM_KEYDOWN:
+ if ((stateMask & (SWT.ALT | SWT.SHIFT | SWT.CONTROL)) != 0) return false;
+ break;
+ }
+
+ /*
+ * Feature in Windows. If the left button is down in
+ * the text widget, it refuses the character. The fix
+ * is to detect this case and avoid sending a verify
+ * event.
+ */
+ if (OS.GetKeyState (OS.VK_LBUTTON) < 0) {
+ if (OS.GetDlgItem (handle, CBID_EDIT) == OS.GetCapture()) return true;
+ }
+
+ /* Verify the character */
+ String oldText = "";
+ int [] start = new int [1], end = new int [1];
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText == 0) return true;
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ switch (key) {
+ case 0x08: /* Bs */
+ if (start [0] == end [0]) {
+ if (start [0] == 0) return true;
+ start [0] = start [0] - 1;
+ start [0] = Math.max (start [0], 0);
+ }
+ break;
+ case 0x7F: /* Del */
+ if (start [0] == end [0]) {
+ int length = OS.GetWindowTextLength (hwndText);
+ if (start [0] == length) return true;
+ end [0] = end [0] + 1;
+ end [0] = Math.min (end [0], length);
+ }
+ break;
+ case '\r': /* Return */
+ return true;
+ default: /* Tab and other characters */
+ if (key != '\t' && key < 0x20) return true;
+ oldText = new String (new char [] {key});
+ break;
+ }
+ String newText = verifyText (oldText, start [0], end [0], event);
+ if (newText == null) return false;
+ if (newText == oldText) return true;
+ TCHAR buffer = new TCHAR (getCodePage (), newText, true);
+ OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], end [0]);
+ OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, buffer);
+ return false;
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver's
+ * list. If the item at the index was already selected, it remains
+ * selected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException
+ *
+ */
+public void select (int index) {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ if (0 <= index && index < count) {
+ int selection = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ //corner case for single elements combo boxes for Bug 222752
+ if (OS.WIN32_VERSION < OS.VERSION (6, 2) && getListVisible() && (style & SWT.READ_ONLY) != 0 && count==1 && selection == OS.CB_ERR) {
+ OS.SendMessage (handle, OS.WM_KEYDOWN, OS.VK_DOWN, 0);
+ sendEvent (SWT.Modify);
+ return;
+ }
+ int code = (int)OS.SendMessage (handle, OS.CB_SETCURSEL, index, 0);
+ if (code != OS.CB_ERR && code != selection) {
+ //Workaround for Bug 222752
+ if (OS.WIN32_VERSION < OS.VERSION (6, 2) && getListVisible() && (style & SWT.READ_ONLY) != 0) {
+ int firstKey = OS.VK_UP;
+ int secondKey = OS.VK_DOWN;
+ if (index == 0) {
+ firstKey = OS.VK_DOWN;
+ secondKey = OS.VK_UP;
+ }
+ OS.SendMessage (handle, OS.WM_KEYDOWN, firstKey, 0);
+ OS.SendMessage (handle, OS.WM_KEYDOWN, secondKey, 0);
+ }
+ sendEvent (SWT.Modify);
+ // widget could be disposed at this point
+ }
+ }
+}
+
+@Override
+void setBackgroundImage (long hBitmap) {
+ super.setBackgroundImage (hBitmap);
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
+}
+
+@Override
+void setBackgroundPixel (int pixel) {
+ super.setBackgroundPixel (pixel);
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
+}
+
+@Override
+void setBoundsInPixels (int x, int y, int width, int height, int flags) {
+ /*
+ * Feature in Windows. If the combo box has the CBS_DROPDOWN
+ * or CBS_DROPDOWNLIST style, Windows uses the height that the
+ * programmer sets in SetWindowPos () to control height of the
+ * drop down list. When the width is non-zero, Windows remembers
+ * this value and sets the height to be the height of the text
+ * field part of the combo box. If the width is zero, Windows
+ * allows the height to have any value. Therefore, when the
+ * programmer sets and then queries the height, the values can
+ * be different depending on the width. The problem occurs when
+ * the programmer uses computeSize () to determine the preferred
+ * height (always the height of the text field) and then uses
+ * this value to set the height of the combo box. The result
+ * is a combo box with a zero size drop down list. The fix, is
+ * to always set the height to show a fixed number of combo box
+ * items and ignore the height value that the programmer supplies.
+ */
+ if ((style & SWT.DROP_DOWN) != 0) {
+ int visibleCount = getItemCount() == 0 ? VISIBLE_COUNT : this.visibleCount;
+ height = getTextHeightInPixels () + (getItemHeightInPixels () * visibleCount) + 2;
+ /*
+ * Feature in Windows. When a drop down combo box is resized,
+ * the combo box resizes the height of the text field and uses
+ * the height provided in SetWindowPos () to determine the height
+ * of the drop down list. For some reason, the combo box redraws
+ * the whole area, not just the text field. The fix is to set the
+ * SWP_NOSIZE bits when the height of text field and the drop down
+ * list is the same as the requested height.
+ *
+ * NOTE: Setting the width of a combo box to zero does not update
+ * the width of the drop down control rect. If the width of the
+ * combo box is zero, then do not set SWP_NOSIZE.
+ */
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ if (rect.right - rect.left != 0) {
+ if (OS.SendMessage (handle, OS.CB_GETDROPPEDCONTROLRECT, 0, rect) != 0) {
+ int oldWidth = rect.right - rect.left, oldHeight = rect.bottom - rect.top;
+ if (oldWidth == width && oldHeight == height) flags |= OS.SWP_NOSIZE;
+ }
+ }
+ OS.SetWindowPos (handle, 0, x, y, width, height, flags);
+ } else {
+ super.setBoundsInPixels (x, y, width, height, flags);
+ }
+}
+
+@Override
+public void setFont (Font font) {
+ checkWidget ();
+
+ /*
+ * Feature in Windows. For some reason, in a editable combo box,
+ * when WM_SETFONT is used to set the font of the control
+ * and the current text does not match an item in the
+ * list, Windows selects the item that most closely matches the
+ * contents of the combo. The fix is to lock the current text
+ * by ignoring all WM_SETTEXT messages during processing of
+ * WM_SETFONT.
+ */
+ boolean oldLockText = lockText;
+ if ((style & SWT.READ_ONLY) == 0) lockText = true;
+ super.setFont (font);
+ if ((style & SWT.READ_ONLY) == 0) lockText = oldLockText;
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth ();
+}
+
+@Override
+void setForegroundPixel (int pixel) {
+ super.setForegroundPixel (pixel);
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
+}
+
+/**
+ * Sets the text of the item in the receiver's list at the given
+ * zero-relative index to the string argument.
+ *
+ * @param index the index for the item
+ * @param string the new text for the item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setItem (int index, String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int selection = getSelectionIndex ();
+ remove (index, false);
+ if (isDisposed ()) return;
+ add (string, index);
+ if (selection != -1) select (selection);
+}
+
+/**
+ * Sets the receiver's list to be the given array of items.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setItems (String... items) {
+ checkWidget ();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; iSWT.RIGHT_TO_LEFT
.
+ *
+ *
+ *
+ * @since 2.1.2
+ */
+@Override
+public void setOrientation (int orientation) {
+ super.setOrientation (orientation);
+}
+
+void setScrollWidth () {
+ int newWidth = 0;
+ RECT rect = new RECT ();
+ long newFont, oldFont = 0;
+ long hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ int count = (int)OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
+ for (int i=0; i
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (Point selection) {
+ checkWidget ();
+ if (selection == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int start = translateOffset (selection.x), end = translateOffset (selection.y);
+ long bits = OS.MAKELPARAM (start, end);
+ OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, bits);
+}
+
+/**
+ * Sets the contents of the receiver's text field to the
+ * given string.
+ * Combo
is typically
+ * only capable of displaying a single line of text. Thus,
+ * setting the text to a string containing line breaks or
+ * other special characters will probably cause it to
+ * display incorrectly.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((style & SWT.READ_ONLY) != 0) {
+ int index = indexOf (string);
+ if (index != -1) select (index);
+ return;
+ }
+ clearSegments (false);
+ int limit = LIMIT;
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0) {
+ limit = (int)OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
+ }
+ if (string.length () > limit) string = string.substring (0, limit);
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ if (OS.SetWindowText (handle, buffer)) {
+ applyEditSegments ();
+ sendEvent (SWT.Modify);
+ // widget could be disposed at this point
+ }
+}
+
+/**
+ * Sets the maximum number of characters that the receiver's
+ * text field is capable of holding to be the argument.
+ * setTextLimit(Combo.LIMIT)
.
+ * Specifying a limit value larger than Combo.LIMIT
sets the
+ * receiver's limit to Combo.LIMIT
.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #LIMIT
+ */
+public void setTextLimit (int limit) {
+ checkWidget ();
+ if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO);
+ if (segments != null && limit > 0) {
+ OS.SendMessage (handle, OS.CB_LIMITTEXT, limit + Math.min (segments.length, LIMIT - limit), 0);
+ } else {
+ OS.SendMessage (handle, OS.CB_LIMITTEXT, limit, 0);
+ }
+}
+
+@Override
+void setToolTipText (Shell shell, String string) {
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndText != 0) shell.setToolTipText (hwndText, string);
+ if (hwndList != 0) shell.setToolTipText (hwndList, string);
+ shell.setToolTipText (handle, string);
+}
+
+/**
+ * Sets the number of items that are visible in the drop
+ * down portion of the receiver's list.
+ *
+ *
+ *
+ * @since 3.0
+ */
+public void setVisibleItemCount (int count) {
+ checkWidget ();
+ if (count < 0) return;
+ visibleCount = count;
+ updateDropDownHeight ();
+}
+
+@Override
+void subclass () {
+ super.subclass ();
+ long newProc = display.windowProc;
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0) {
+ OS.SetWindowLongPtr (hwndText, OS.GWLP_WNDPROC, newProc);
+ }
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndList != 0) {
+ OS.SetWindowLongPtr (hwndList, OS.GWLP_WNDPROC, newProc);
+ }
+}
+
+int translateOffset (int offset) {
+ if (segments == null) return offset;
+ for (int i = 0, nSegments = segments.length; i < nSegments && offset - i >= segments[i]; i++) {
+ offset++;
+ }
+ return offset;
+}
+
+@Override
+boolean translateTraversal (MSG msg) {
+ /*
+ * When the combo box is dropped down, allow return
+ * to select an item in the list and escape to close
+ * the combo box.
+ */
+ switch ((int)(msg.wParam)) {
+ case OS.VK_RETURN:
+ case OS.VK_ESCAPE:
+ if ((style & SWT.DROP_DOWN) != 0) {
+ if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
+ return false;
+ }
+ }
+ }
+ return super.translateTraversal (msg);
+}
+
+@Override
+boolean traverseEscape () {
+ if ((style & SWT.DROP_DOWN) != 0) {
+ if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
+ OS.SendMessage (handle, OS.CB_SHOWDROPDOWN, 0, 0);
+ return true;
+ }
+ }
+ return super.traverseEscape ();
+}
+
+@Override
+boolean traverseReturn () {
+ if ((style & SWT.DROP_DOWN) != 0) {
+ if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
+ OS.SendMessage (handle, OS.CB_SHOWDROPDOWN, 0, 0);
+ return true;
+ }
+ }
+ return super.traverseReturn ();
+}
+
+@Override
+void unsubclass () {
+ super.unsubclass ();
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ if (hwndText != 0 && EditProc != 0) {
+ OS.SetWindowLongPtr (hwndText, OS.GWLP_WNDPROC, EditProc);
+ }
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if (hwndList != 0 && ListProc != 0) {
+ OS.SetWindowLongPtr (hwndList, OS.GWLP_WNDPROC, ListProc);
+ }
+}
+
+int untranslateOffset (int offset) {
+ if (segments == null) return offset;
+ for (int i = 0, nSegments = segments.length; i < nSegments && offset > segments[i]; i++) {
+ offset--;
+ }
+ return offset;
+}
+
+void updateDropDownHeight () {
+ /*
+ * Feature in Windows. If the combo box has the CBS_DROPDOWN
+ * or CBS_DROPDOWNLIST style, Windows uses the height that the
+ * programmer sets in SetWindowPos () to control height of the
+ * drop down list. See #setBounds() for more details.
+ */
+ if ((style & SWT.DROP_DOWN) != 0) {
+ RECT rect = new RECT ();
+ OS.SendMessage (handle, OS.CB_GETDROPPEDCONTROLRECT, 0, rect);
+ int visibleCount = getItemCount() == 0 ? VISIBLE_COUNT : this.visibleCount;
+ int height = getTextHeightInPixels () + (getItemHeightInPixels () * visibleCount) + 2;
+ if (height != (rect.bottom - rect.top)) {
+ forceResize ();
+ OS.GetWindowRect (handle, rect);
+ int flags = OS.SWP_NOMOVE | OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (handle, 0, 0, 0, rect.right - rect.left, height, flags);
+ }
+ }
+}
+
+@Override
+boolean updateTextDirection(int textDirection) {
+ if (super.updateTextDirection(textDirection)) {
+ clearSegments (true);
+ applyEditSegments ();
+ applyListSegments ();
+ return true;
+ }
+ return false;
+}
+
+@Override
+void updateOrientation () {
+ int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ bits |= OS.WS_EX_LAYOUTRTL;
+ } else {
+ bits &= ~OS.WS_EX_LAYOUTRTL;
+ }
+ bits &= ~OS.WS_EX_RTLREADING;
+ OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
+ long hwndText = 0, hwndList = 0;
+ COMBOBOXINFO pcbi = new COMBOBOXINFO ();
+ pcbi.cbSize = COMBOBOXINFO.sizeof;
+ if (OS.GetComboBoxInfo (handle, pcbi)) {
+ hwndText = pcbi.hwndItem;
+ hwndList = pcbi.hwndList;
+ }
+ if (hwndText != 0) {
+ int bits1 = OS.GetWindowLong (hwndText, OS.GWL_EXSTYLE);
+ int bits2 = OS.GetWindowLong (hwndText, OS.GWL_STYLE);
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ bits1 |= OS.WS_EX_RIGHT | OS.WS_EX_RTLREADING;
+ bits2 |= OS.ES_RIGHT;
+ } else {
+ bits1 &= ~(OS.WS_EX_RIGHT | OS.WS_EX_RTLREADING);
+ bits2 &= ~OS.ES_RIGHT;
+ }
+ OS.SetWindowLong (hwndText, OS.GWL_EXSTYLE, bits1);
+ OS.SetWindowLong (hwndText, OS.GWL_STYLE, bits2);
+
+ /*
+ * Bug in Windows. For some reason, the single line text field
+ * portion of the combo box does not redraw to reflect the new
+ * style bits. The fix is to force the widget to be resized by
+ * temporarily shrinking and then growing the width and height.
+ */
+ RECT rect = new RECT ();
+ OS.GetWindowRect (hwndText, rect);
+ int width = rect.right - rect.left, height = rect.bottom - rect.top;
+ OS.GetWindowRect (handle, rect);
+ int widthCombo = rect.right - rect.left, heightCombo = rect.bottom - rect.top;
+ int uFlags = OS.SWP_NOMOVE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (hwndText, 0, 0, 0, width - 1, height - 1, uFlags);
+ OS.SetWindowPos (handle, 0, 0, 0, widthCombo - 1, heightCombo - 1, uFlags);
+ OS.SetWindowPos (hwndText, 0, 0, 0, width, height, uFlags);
+ OS.SetWindowPos (handle, 0, 0, 0, widthCombo, heightCombo, uFlags);
+ OS.InvalidateRect (handle, null, true);
+ }
+ if (hwndList != 0) {
+ int bits1 = OS.GetWindowLong (hwndList, OS.GWL_EXSTYLE);
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ bits1 |= OS.WS_EX_LAYOUTRTL;
+ } else {
+ bits1 &= ~OS.WS_EX_LAYOUTRTL;
+ }
+ OS.SetWindowLong (hwndList, OS.GWL_EXSTYLE, bits1);
+ }
+}
+
+String verifyText (String string, int start, int end, Event keyEvent) {
+ Event event = new Event ();
+ event.text = string;
+ event.start = start;
+ event.end = end;
+ if (keyEvent != null) {
+ event.character = keyEvent.character;
+ event.keyCode = keyEvent.keyCode;
+ event.stateMask = keyEvent.stateMask;
+ }
+ event.start = untranslateOffset (event.start);
+ event.end = untranslateOffset (event.end);
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the verify
+ * event. If this happens, answer null to cancel
+ * the operation.
+ */
+ sendEvent (SWT.Verify, event);
+ if (!event.doit || isDisposed ()) return null;
+ return event.text;
+}
+
+@Override
+int widgetExtStyle () {
+ return super.widgetExtStyle () & ~OS.WS_EX_NOINHERITLAYOUT;
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle () | OS.CBS_AUTOHSCROLL | OS.CBS_NOINTEGRALHEIGHT | OS.WS_HSCROLL |OS.WS_VSCROLL;
+ if ((style & SWT.SIMPLE) != 0) return bits | OS.CBS_SIMPLE;
+ if ((style & SWT.READ_ONLY) != 0) return bits | OS.CBS_DROPDOWNLIST;
+ return bits | OS.CBS_DROPDOWN;
+}
+
+@Override
+TCHAR windowClass () {
+ return ComboClass;
+}
+
+@Override
+long windowProc () {
+ return ComboProc;
+}
+
+@Override
+long windowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ if (hwnd != handle) {
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ long hwndList = OS.GetDlgItem (handle, CBID_LIST);
+ if ((hwndText != 0 && hwnd == hwndText) || (hwndList != 0 && hwnd == hwndList)) {
+ LRESULT result = null;
+ boolean processSegments = false, redraw = false;
+ switch (msg) {
+ /* Keyboard messages */
+ case OS.WM_CHAR:
+ processSegments = (hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0)) && !ignoreCharacter && OS.GetKeyState (OS.VK_CONTROL) >= 0 && OS.GetKeyState (OS.VK_MENU) >= 0;
+ result = wmChar (hwnd, wParam, lParam);
+ break;
+ case OS.WM_IME_CHAR: result = wmIMEChar (hwnd, wParam, lParam); break;
+ case OS.WM_KEYDOWN:
+ processSegments = wParam == OS.VK_DELETE && (hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0));
+ result = wmKeyDown (hwnd, wParam, lParam);
+ break;
+ case OS.WM_KEYUP: result = wmKeyUp (hwnd, wParam, lParam); break;
+ case OS.WM_SYSCHAR: result = wmSysChar (hwnd, wParam, lParam); break;
+ case OS.WM_SYSKEYDOWN: result = wmSysKeyDown (hwnd, wParam, lParam); break;
+ case OS.WM_SYSKEYUP: result = wmSysKeyUp (hwnd, wParam, lParam); break;
+
+ /* Mouse Messages */
+ case OS.WM_CAPTURECHANGED: result = wmCaptureChanged (hwnd, wParam, lParam); break;
+ case OS.WM_LBUTTONDBLCLK: result = wmLButtonDblClk (hwnd, wParam, lParam); break;
+ case OS.WM_LBUTTONDOWN: result = wmLButtonDown (hwnd, wParam, lParam); break;
+ case OS.WM_LBUTTONUP: result = wmLButtonUp (hwnd, wParam, lParam); break;
+ case OS.WM_MBUTTONDBLCLK: result = wmMButtonDblClk (hwnd, wParam, lParam); break;
+ case OS.WM_MBUTTONDOWN: result = wmMButtonDown (hwnd, wParam, lParam); break;
+ case OS.WM_MBUTTONUP: result = wmMButtonUp (hwnd, wParam, lParam); break;
+ case OS.WM_MOUSEHOVER: result = wmMouseHover (hwnd, wParam, lParam); break;
+ case OS.WM_MOUSELEAVE: result = wmMouseLeave (hwnd, wParam, lParam); break;
+ case OS.WM_MOUSEMOVE: result = wmMouseMove (hwnd, wParam, lParam); break;
+// case OS.WM_MOUSEWHEEL: result = wmMouseWheel (hwnd, wParam, lParam); break;
+ case OS.WM_RBUTTONDBLCLK: result = wmRButtonDblClk (hwnd, wParam, lParam); break;
+ case OS.WM_RBUTTONDOWN: result = wmRButtonDown (hwnd, wParam, lParam); break;
+ case OS.WM_RBUTTONUP: result = wmRButtonUp (hwnd, wParam, lParam); break;
+ case OS.WM_XBUTTONDBLCLK: result = wmXButtonDblClk (hwnd, wParam, lParam); break;
+ case OS.WM_XBUTTONDOWN: result = wmXButtonDown (hwnd, wParam, lParam); break;
+ case OS.WM_XBUTTONUP: result = wmXButtonUp (hwnd, wParam, lParam); break;
+
+ /* Paint messages */
+ case OS.WM_PAINT: result = wmPaint (hwnd, wParam, lParam); break;
+
+ /* Menu messages */
+ case OS.WM_CONTEXTMENU: result = wmContextMenu (hwnd, wParam, lParam); break;
+
+ /* Clipboard messages */
+ case OS.EM_CANUNDO:
+ if (hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0)) return 0;
+ break;
+ case OS.WM_UNDO:
+ case OS.EM_UNDO:
+ if (hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0)) return 0;
+ case OS.WM_COPY:
+ case OS.WM_CLEAR:
+ case OS.WM_CUT:
+ case OS.WM_PASTE:
+ processSegments = hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0);
+ case OS.WM_SETTEXT:
+ if (hwnd == hwndText) {
+ result = wmClipboard (hwnd, msg, wParam, lParam);
+ }
+ break;
+ }
+ if (result != null) return result.value;
+
+ if (processSegments) {
+ if (getDrawing () && OS.IsWindowVisible (hwndText)) {
+ redraw = true;
+ OS.DefWindowProc (hwndText, OS.WM_SETREDRAW, 0, 0);
+ }
+ clearSegments (true);
+ long code = callWindowProc (hwnd, msg, wParam, lParam);
+ applyEditSegments ();
+ if (redraw) {
+ OS.DefWindowProc (hwndText, OS.WM_SETREDRAW, 1, 0);
+ OS.InvalidateRect (hwndText, null, true);
+ }
+ return code;
+ }
+ return callWindowProc (hwnd, msg, wParam, lParam);
+ }
+ }
+ switch (msg) {
+ case OS.CB_SETCURSEL: {
+ long code = OS.CB_ERR;
+ int index = (int) wParam;
+ if ((style & SWT.READ_ONLY) != 0) {
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ String oldText = getText (), newText = null;
+ if (wParam == -1) {
+ newText = "";
+ } else {
+ if (0 <= wParam && wParam < getItemCount ()) {
+ newText = getItem ((int)wParam);
+ }
+ }
+ if (newText != null && !newText.equals (oldText)) {
+ int length = OS.GetWindowTextLength (handle);
+ oldText = newText;
+ newText = verifyText (newText, 0, length, null);
+ if (newText == null) return 0;
+ if (!newText.equals (oldText)) {
+ index = indexOf (newText);
+ if (index != -1 && index != wParam) {
+ return callWindowProc (handle, OS.CB_SETCURSEL, index, lParam);
+ }
+ }
+ }
+ }
+ }
+ if (hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0)) {
+ code = super.windowProc (hwnd, msg, wParam, lParam);
+ if (!(code == OS.CB_ERR || code == OS.CB_ERRSPACE)) {
+ Event event = getSegments (items [index]);
+ segments = event != null ? event.segments : null;
+ if (event.segmentsChars != null) {
+ int auto = state & HAS_AUTO_DIRECTION;
+ if (event.segmentsChars[0] == RLE) {
+ super.updateTextDirection(SWT.RIGHT_TO_LEFT);
+ } else if (event.segmentsChars[0] == LRE) {
+ super.updateTextDirection(SWT.LEFT_TO_RIGHT);
+ }
+ state |= auto;
+ }
+ return code;
+ }
+ }
+ break;
+ }
+ case OS.CB_ADDSTRING:
+ case OS.CB_INSERTSTRING:
+ case OS.CB_FINDSTRINGEXACT:
+ if (lParam != 0 && (hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0))) {
+ long code = OS.CB_ERR;
+ int length = OS.wcslen (lParam);
+ TCHAR buffer = new TCHAR (getCodePage (), length);
+ OS.MoveMemory (buffer, lParam, buffer.length () * TCHAR.sizeof);
+ String string = buffer.toString (0, length);
+ Event event = getSegments (string);
+ if (event != null && event.segments != null) {
+ buffer = new TCHAR (getCodePage (), getSegmentsText (string, event), true);
+ long hHeap = OS.GetProcessHeap ();
+ length = buffer.length() * TCHAR.sizeof;
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, length);
+ OS.MoveMemory (pszText, buffer, length);
+ code = super.windowProc (hwnd, msg, wParam, pszText);
+ OS.HeapFree (hHeap, 0, pszText);
+ }
+ if (msg == OS.CB_ADDSTRING || msg == OS.CB_INSERTSTRING) {
+ int index = msg == OS.CB_ADDSTRING ? items.length : (int) wParam;
+ String [] newItems = new String [items.length + 1];
+ System.arraycopy (items, 0, newItems, 0, index);
+ newItems [index] = string;
+ System.arraycopy (items, index, newItems, index + 1, items.length - index);
+ items = newItems;
+ }
+ if (code != OS.CB_ERR && code != OS.CB_ERRSPACE) return code;
+ }
+ break;
+ case OS.CB_DELETESTRING: {
+ if (hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0)) {
+ long code = super.windowProc (hwnd, msg, wParam, lParam);
+ if (code != OS.CB_ERR && code != OS.CB_ERRSPACE) {
+ int index = (int) wParam;
+ if (items.length == 1) {
+ items = new String[0];
+ } else if (items.length > 1) {
+ String [] newItems = new String [items.length - 1];
+ System.arraycopy (items, 0, newItems, 0, index);
+ System.arraycopy (items, index + 1, newItems, index, items.length - index - 1);
+ items = newItems;
+ }
+ if (!noSelection) {
+ index = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ if (index == wParam) {
+ clearSegments (false);
+ applyEditSegments ();
+ }
+ }
+ }
+ return code;
+ }
+ break;
+ }
+ case OS.CB_RESETCONTENT: {
+ if (hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0)) {
+ if (items.length > 0) items = new String [0];
+ clearSegments (false);
+ applyEditSegments ();
+ }
+ break;
+ }
+ }
+ return super.windowProc (hwnd, msg, wParam, lParam);
+}
+
+@Override
+LRESULT wmColorChild (long wParam, long lParam) {
+ LRESULT result = super.wmColorChild(wParam, lParam);
+
+ /*
+ * CBS_DROPDOWNLIST (SWT.READ_ONLY) comboboxes ignore results of WM_CTLCOLORxxx.
+ * This prevents SWT from setting custom background / text color.
+ * In Windows function 'comctl32!ComboBox_InternalUpdateEditWindow' there are two main branches:
+ * 'DrawThemeText' branch
+ * Ignores any SetTextColor / SetBkColor.
+ * Ignores brush returned from WM_CTLCOLORxxx.
+ * Keeps any background that was painted during WM_CTLCOLORxxx.
+ * 'ExtTextOut' branch
+ * Uses pre-selected SetTextColor / SetBkColor.
+ * Ignores brush returned from WM_CTLCOLORxxx.
+ * Overwrites background with color in SetBkColor.
+ * This undocumented hack forces combobox to use 'ExtTextOut' branch.
+ * The flag is reset after every WM_PAINT, so it's set in every WM_CTLCOLORxxx.
+ * Since 'ExtTextOut' always paints background, hack is not activated if not needed
+ * to avoid changes in visual appearance of comboboxes with default colors.
+ */
+ final boolean isReadonly = ((style & SWT.READ_ONLY) != 0);
+ final boolean isCustomColors = (result != null);
+ if (isReadonly && isCustomColors && stateFlagsUsable) {
+ stateFlagsAdd(stateFlagsFirstPaint);
+ }
+
+ return result;
+}
+
+@Override
+LRESULT WM_CTLCOLOR (long wParam, long lParam) {
+ return wmColorChild (wParam, lParam);
+}
+
+@Override
+LRESULT WM_GETDLGCODE (long wParam, long lParam) {
+ long code = callWindowProc (handle, OS.WM_GETDLGCODE, wParam, lParam);
+ return new LRESULT (code | OS.DLGC_WANTARROWS);
+}
+
+@Override
+LRESULT WM_KILLFOCUS (long wParam, long lParam) {
+ /*
+ * Bug in Windows. When a combo box that is read only
+ * is disposed in CBN_KILLFOCUS, Windows segment faults.
+ * The fix is to send focus from WM_KILLFOCUS instead
+ * of CBN_KILLFOCUS.
+ *
+ * NOTE: In version 6 of COMCTL32.DLL, the bug is fixed.
+ */
+ if ((style & SWT.READ_ONLY) != 0) {
+ return super.WM_KILLFOCUS (wParam, lParam);
+ }
+
+ /*
+ * Return NULL - Focus notification is
+ * done in WM_COMMAND by CBN_KILLFOCUS.
+ */
+ return null;
+}
+
+@Override
+LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
+ /*
+ * Feature in Windows. When an editable combo box is dropped
+ * down and the text in the entry field partially matches an
+ * item in the list, Windows selects the item but doesn't send
+ * WM_COMMAND with CBN_SELCHANGE. The fix is to detect that
+ * the selection has changed and issue the notification.
+ */
+ int oldSelection = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
+ if (result == LRESULT.ZERO) return result;
+ if ((style & SWT.READ_ONLY) == 0) {
+ int newSelection = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ if (oldSelection != newSelection) {
+ sendEvent (SWT.Modify);
+ if (isDisposed ()) return LRESULT.ZERO;
+ sendSelectionEvent (SWT.Selection, null, true);
+ if (isDisposed ()) return LRESULT.ZERO;
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_SETFOCUS (long wParam, long lParam) {
+ /*
+ * Return NULL - Focus notification is
+ * done by WM_COMMAND with CBN_SETFOCUS.
+ */
+ return null;
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ /*
+ * Feature in Windows. When a combo box is resized,
+ * the size of the drop down rectangle is specified
+ * using the height and then the combo box resizes
+ * to be the height of the text field. This causes
+ * two WM_SIZE messages to be sent and two SWT.Resize
+ * events to be issued. The fix is to ignore the
+ * second resize.
+ */
+ if (ignoreResize) return null;
+ /*
+ * Bug in Windows. If the combo box has the CBS_SIMPLE style,
+ * the list portion of the combo box is not redrawn when the
+ * combo box is resized. The fix is to force a redraw when
+ * the size has changed.
+ */
+ if ((style & SWT.SIMPLE) != 0) {
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ if (OS.IsWindowVisible (handle)) {
+ int uFlags = OS.RDW_ERASE | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (handle, null, 0, uFlags);
+ }
+ return result;
+ }
+
+ /*
+ * Feature in Windows. When an editable drop down combo box
+ * contains text that does not correspond to an item in the
+ * list, when the widget is resized, it selects the closest
+ * match from the list. The fix is to lock the current text
+ * by ignoring all WM_SETTEXT messages during processing of
+ * WM_SIZE.
+ */
+ boolean oldLockText = lockText;
+ if ((style & SWT.READ_ONLY) == 0) lockText = true;
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ if ((style & SWT.READ_ONLY) == 0) lockText = oldLockText;
+ /*
+ * Feature in Windows. When CB_SETDROPPEDWIDTH is called with
+ * a width that is smaller than the current size of the combo
+ * box, it is ignored. This the fix is to set the width after
+ * the combo box has been resized.
+ */
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth (scrollWidth);
+
+ /*
+ * When setting selection, Combo automatically scrolls selection's end into view.
+ * We force it to do such scrolling after every resize to achieve multiple goals:
+ * 1) Text is no longer partially shown when there's free space after resizing
+ * Without workaround, this happens when all of these are true:
+ * a) Combo has focus
+ * b) Combo can't fit all text
+ * c) Caret is not at position 0
+ * d) Combo is resized bigger.
+ * 2) Text is no longer partially shown after .setSelection() before its size was calculated
+ * This is just another form of problem 1.
+ * 3) Caret no longer goes out of view when shrinking control.
+ */
+ if ((style & SWT.READ_ONLY) == 0) {
+ Point oldSelection = this.getSelection();
+ Point tmpSelection = new Point(0, 0);
+ if (!oldSelection.equals(tmpSelection)) {
+ this.setSelection(tmpSelection);
+ this.setSelection(oldSelection);
+ }
+ }
+
+ return result;
+}
+
+@Override
+LRESULT WM_UPDATEUISTATE (long wParam, long lParam) {
+ LRESULT result = super.WM_UPDATEUISTATE (wParam, lParam);
+ if (result != null) return result;
+ OS.InvalidateRect (handle, null, true);
+ return result;
+}
+
+@Override
+LRESULT WM_WINDOWPOSCHANGING (long wParam, long lParam) {
+ LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. When a combo box is resized,
+ * the size of the drop down rectangle is specified
+ * using the height and then the combo box resizes
+ * to be the height of the text field. This causes
+ * sibling windows that intersect with the original
+ * bounds to redrawn. The fix is to stop the redraw
+ * using SWP_NOREDRAW and then damage the combo box
+ * text field and the area in the parent where the
+ * combo box used to be.
+ */
+ if (!getDrawing ()) return result;
+ if (!OS.IsWindowVisible (handle)) return result;
+ if (ignoreResize) {
+ WINDOWPOS lpwp = new WINDOWPOS ();
+ OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
+ if ((lpwp.flags & OS.SWP_NOSIZE) == 0) {
+ lpwp.flags |= OS.SWP_NOREDRAW;
+ OS.MoveMemory (lParam, lpwp, WINDOWPOS.sizeof);
+ OS.InvalidateRect (handle, null, true);
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ if (width != 0 && height != 0) {
+ long hwndParent = parent.handle;
+ long hwndChild = OS.GetWindow (hwndParent, OS.GW_CHILD);
+ OS.MapWindowPoints (0, hwndParent, rect, 2);
+ long rgn1 = OS.CreateRectRgn (rect.left, rect.top, rect.right, rect.bottom);
+ while (hwndChild != 0) {
+ if (hwndChild != handle) {
+ OS.GetWindowRect (hwndChild, rect);
+ OS.MapWindowPoints (0, hwndParent, rect, 2);
+ long rgn2 = OS.CreateRectRgn (rect.left, rect.top, rect.right, rect.bottom);
+ OS.CombineRgn (rgn1, rgn1, rgn2, OS.RGN_DIFF);
+ OS.DeleteObject (rgn2);
+ }
+ hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
+ }
+ int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
+ OS.RedrawWindow (hwndParent, null, rgn1, flags);
+ OS.DeleteObject (rgn1);
+ }
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT wmChar (long hwnd, long wParam, long lParam) {
+ if (ignoreCharacter) return null;
+ LRESULT result = super.wmChar (hwnd, wParam, lParam);
+ if (result != null) return result;
+ switch ((int)wParam) {
+ /*
+ * Feature in Windows. For some reason, when the
+ * widget is a single line text widget, when the
+ * user presses tab, return or escape, Windows beeps.
+ * The fix is to look for these keys and not call
+ * the window proc.
+ *
+ * NOTE: This only happens when the drop down list
+ * is not visible.
+ */
+ case SWT.TAB: return LRESULT.ZERO;
+ case SWT.CR:
+ if (!ignoreDefaultSelection) sendSelectionEvent (SWT.DefaultSelection);
+ ignoreDefaultSelection = false;
+ // when no value is selected in the dropdown
+ if (getSelectionIndex() == -1) {
+ if ((style & SWT.DROP_DOWN) != 0 && (style & SWT.READ_ONLY) == 0) {
+ // close the dropdown if open
+ if (OS.SendMessage(handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
+ OS.SendMessage(handle, OS.CB_SHOWDROPDOWN, 0, 0);
+ }
+ return LRESULT.ZERO;
+ }
+ }
+ case SWT.ESC:
+ if ((style & SWT.DROP_DOWN) != 0) {
+ if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) == 0) {
+ return LRESULT.ZERO;
+ }
+ }
+ /*
+ * Bug in Windows. When the user types CTRL and BS
+ * in a combo control, a DEL character (0x08) is generated.
+ * Rather than deleting the text, the DEL character
+ * is inserted into the control. The fix is to detect
+ * this case and not call the window proc.
+ */
+ case SWT.DEL:
+ if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
+ if ((style & SWT.READ_ONLY) != 0) return LRESULT.ZERO;
+ Point selection = getSelection ();
+ long hwndText = OS.GetDlgItem (handle, CBID_EDIT);
+ int x = selection.x;
+ int y = selection.y;
+ if (x == y) {
+ String actText = getText ().substring (0, x);
+ java.util.regex.Matcher m = CTRL_BS_PATTERN.matcher (actText);
+ if (m.find ()) {
+ x = m.start ();
+ y = m.end ();
+ OS.SendMessage (hwndText, OS.EM_SETSEL, x, y);
+ }
+ }
+ if (x < y) {
+ /*
+ * Instead of setting the new text directly we send the replace selection event to
+ * guarantee that the action is pushed to the undo buffer.
+ */
+ OS.SendMessage (hwndText, OS.EM_REPLACESEL, 1, 0);
+ }
+ return LRESULT.ZERO;
+ }
+ }
+ return result;
+}
+
+LRESULT wmClipboard (long hwndText, int msg, long wParam, long lParam) {
+ if ((style & SWT.READ_ONLY) != 0) return null;
+ if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return null;
+ boolean call = false;
+ int [] start = new int [1], end = new int [1];
+ String newText = null;
+ switch (msg) {
+ case OS.WM_CLEAR:
+ case OS.WM_CUT:
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ if (untranslateOffset (start [0]) != untranslateOffset (end [0])) {
+ newText = "";
+ call = true;
+ }
+ break;
+ case OS.WM_PASTE:
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ newText = getClipboardText ();
+ break;
+ case OS.EM_UNDO:
+ case OS.WM_UNDO:
+ if (OS.SendMessage (hwndText, OS.EM_CANUNDO, 0, 0) != 0) {
+ ignoreModify = true;
+ OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
+ int length = OS.GetWindowTextLength (hwndText);
+ int [] newStart = new int [1], newEnd = new int [1];
+ OS.SendMessage (hwndText, OS.EM_GETSEL, newStart, newEnd);
+ if (length != 0 && newStart [0] != newEnd [0]) {
+ char [] buffer = new char [length + 1];
+ OS.GetWindowText (hwndText, buffer, length + 1);
+ newText = new String (buffer, newStart [0], newEnd [0] - newStart [0]);
+ } else {
+ newText = "";
+ }
+ OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ ignoreModify = false;
+ }
+ break;
+ case OS.WM_SETTEXT:
+ if (lockText) return null;
+ end [0] = OS.GetWindowTextLength (hwndText);
+ int length = OS.wcslen (lParam);
+ TCHAR buffer = new TCHAR (getCodePage (), length);
+ int byteCount = buffer.length () * TCHAR.sizeof;
+ OS.MoveMemory (buffer, lParam, byteCount);
+ newText = buffer.toString (0, length);
+ break;
+ }
+ if (newText != null) {
+ String oldText = newText;
+ newText = verifyText (newText, start [0], end [0], null);
+ if (newText == null) return LRESULT.ZERO;
+ if (!newText.equals (oldText)) {
+ if (call) {
+ OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
+ }
+ TCHAR buffer = new TCHAR (getCodePage (), newText, true);
+ if (msg == OS.WM_SETTEXT) {
+ long hHeap = OS.GetProcessHeap ();
+ int byteCount = buffer.length () * TCHAR.sizeof;
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory (pszText, buffer, byteCount);
+ long code = OS.CallWindowProc (EditProc, hwndText, msg, wParam, pszText);
+ OS.HeapFree (hHeap, 0, pszText);
+ return new LRESULT (code);
+ } else {
+ OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, buffer);
+ return LRESULT.ZERO;
+ }
+ }
+ }
+ return null;
+}
+
+@Override
+LRESULT wmCommandChild (long wParam, long lParam) {
+ int code = OS.HIWORD (wParam);
+ switch (code) {
+ case OS.CBN_EDITCHANGE:
+ if (ignoreModify) break;
+ /*
+ * Feature in Windows. If the combo box list selection is
+ * queried using CB_GETCURSEL before the WM_COMMAND (with
+ * CBN_EDITCHANGE) returns, CB_GETCURSEL returns the previous
+ * selection in the list. It seems that the combo box sends
+ * the WM_COMMAND before it makes the selection in the list box
+ * match the entry field. The fix is remember that no selection
+ * in the list should exist in this case.
+ */
+ noSelection = true;
+ sendEvent (SWT.Modify);
+ if (isDisposed ()) return LRESULT.ZERO;
+ noSelection = false;
+ break;
+ case OS.CBN_SELCHANGE:
+ /*
+ * Feature in Windows. If the text in an editable combo box
+ * is queried using GetWindowText () before the WM_COMMAND
+ * (with CBN_SELCHANGE) returns, GetWindowText () returns is
+ * the previous text in the combo box. It seems that the combo
+ * box sends the WM_COMMAND before it updates the text field to
+ * match the list selection. The fix is to force the text field
+ * to match the list selection by re-selecting the list item.
+ */
+ int index = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ if (index != OS.CB_ERR) {
+ OS.SendMessage (handle, OS.CB_SETCURSEL, index, 0);
+ }
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the modify
+ * event. If this happens, end the processing of the
+ * Windows message by returning zero as the result of
+ * the window proc.
+ */
+ sendEvent (SWT.Modify);
+ if (isDisposed ()) return LRESULT.ZERO;
+ sendSelectionEvent (SWT.Selection);
+ break;
+ case OS.CBN_SETFOCUS:
+ sendFocusEvent (SWT.FocusIn);
+ if (isDisposed ()) return LRESULT.ZERO;
+ break;
+ case OS.CBN_DROPDOWN:
+ setCursor ();
+ updateDropDownHeight ();
+ break;
+ case OS.CBN_KILLFOCUS:
+ /*
+ * Bug in Windows. When a combo box that is read only
+ * is disposed in CBN_KILLFOCUS, Windows segment faults.
+ * The fix is to send focus from WM_KILLFOCUS instead
+ * of CBN_KILLFOCUS.
+ *
+ * NOTE: In version 6 of COMCTL32.DLL, the bug is fixed.
+ */
+ if ((style & SWT.READ_ONLY) != 0) break;
+ sendFocusEvent (SWT.FocusOut);
+ if (isDisposed ()) return LRESULT.ZERO;
+ break;
+ case OS.EN_ALIGN_LTR_EC:
+ case OS.EN_ALIGN_RTL_EC:
+ Event event = new Event ();
+ event.doit = true;
+ sendEvent (SWT.OrientationChange, event);
+ if (!event.doit) {
+ long hwnd = lParam;
+ int bits1 = OS.GetWindowLong (hwnd, OS.GWL_EXSTYLE);
+ int bits2 = OS.GetWindowLong (hwnd, OS.GWL_STYLE);
+ if (code == OS.EN_ALIGN_LTR_EC) {
+ bits1 |= (OS.WS_EX_RTLREADING | OS.WS_EX_RIGHT);
+ bits2 |= OS.ES_RIGHT;
+ } else {
+ bits1 &= ~(OS.WS_EX_RTLREADING | OS.WS_EX_RIGHT);
+ bits2 &= ~OS.ES_RIGHT;
+ }
+ OS.SetWindowLong (hwnd, OS.GWL_EXSTYLE, bits1);
+ OS.SetWindowLong (hwnd, OS.GWL_STYLE, bits2);
+ }
+ if (hooks (SWT.Segments) || filters (SWT.Segments) || ((state & HAS_AUTO_DIRECTION) != 0)) {
+ clearSegments(true);
+ /*
+ * Explicit LTR or RTL direction was set, so auto direction
+ * should be deactivated.
+ */
+ state &= ~HAS_AUTO_DIRECTION;
+ applyEditSegments();
+ }
+ break;
+ }
+ return super.wmCommandChild (wParam, lParam);
+}
+
+@Override
+LRESULT wmIMEChar (long hwnd, long wParam, long lParam) {
+
+ /* Process a DBCS character */
+ Display display = this.display;
+ display.lastKey = 0;
+ display.lastAscii = (int)wParam;
+ display.lastVirtual = display.lastNull = display.lastDead = false;
+ if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
+ return LRESULT.ZERO;
+ }
+
+ /*
+ * Feature in Windows. The Windows text widget uses
+ * two 2 WM_CHAR's to process a DBCS key instead of
+ * using WM_IME_CHAR. The fix is to allow the text
+ * widget to get the WM_CHAR's but ignore sending
+ * them to the application.
+ */
+ ignoreCharacter = true;
+ long result = callWindowProc (hwnd, OS.WM_IME_CHAR, wParam, lParam);
+ MSG msg = new MSG ();
+ int flags = OS.PM_REMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
+ while (OS.PeekMessage (msg, hwnd, OS.WM_CHAR, OS.WM_CHAR, flags)) {
+ OS.TranslateMessage (msg);
+ OS.DispatchMessage (msg);
+ }
+ ignoreCharacter = false;
+
+ sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
+ // widget could be disposed at this point
+ display.lastKey = display.lastAscii = 0;
+ return new LRESULT (result);
+}
+
+@Override
+LRESULT wmKeyDown (long hwnd, long wParam, long lParam) {
+ if (ignoreCharacter) return null;
+ LRESULT result = super.wmKeyDown (hwnd, wParam, lParam);
+ if (result != null) return result;
+ ignoreDefaultSelection = false;
+ switch ((int)wParam) {
+ case OS.VK_LEFT:
+ case OS.VK_UP:
+ case OS.VK_RIGHT:
+ case OS.VK_DOWN:
+ if (segments != null) {
+ long code = 0;
+ int [] start = new int [1], end = new int [1], newStart = new int [1], newEnd = new int [1];
+ OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end);
+ while (true) {
+ code = callWindowProc (hwnd, OS.WM_KEYDOWN, wParam, lParam);
+ OS.SendMessage (handle, OS.CB_GETEDITSEL, newStart, newEnd);
+ if (newStart [0] != start [0]) {
+ if (untranslateOffset (newStart [0]) != untranslateOffset (start [0])) break;
+ } else if (newEnd [0] != end [0]) {
+ if (untranslateOffset (newEnd [0]) != untranslateOffset (end [0])) break;
+ } else {
+ break;
+ }
+ start [0] = newStart [0];
+ end [0] = newEnd [0];
+ }
+ result = code == 0 ? LRESULT.ZERO : new LRESULT (code);
+ }
+ break;
+ case OS.VK_RETURN:
+ if ((style & SWT.DROP_DOWN) != 0) {
+ if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
+ ignoreDefaultSelection = true;
+ }
+ }
+ break;
+ }
+ return result;
+}
+
+@Override
+LRESULT wmSysKeyDown (long hwnd, long wParam, long lParam) {
+ /*
+ * Feature in Windows. When an editable combo box is dropped
+ * down using Alt+Down and the text in the entry field partially
+ * matches an item in the list, Windows selects the item but doesn't
+ * send WM_COMMAND with CBN_SELCHANGE. The fix is to detect that
+ * the selection has changed and issue the notification.
+ */
+ int oldSelection = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ LRESULT result = super.wmSysKeyDown (hwnd, wParam, lParam);
+ if (result != null) return result;
+ if ((style & SWT.READ_ONLY) == 0) {
+ if (wParam == OS.VK_DOWN) {
+ long code = callWindowProc (hwnd, OS.WM_SYSKEYDOWN, wParam, lParam);
+ int newSelection = (int)OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
+ if (oldSelection != newSelection) {
+ sendEvent (SWT.Modify);
+ if (isDisposed ()) return LRESULT.ZERO;
+ sendSelectionEvent (SWT.Selection, null, true);
+ if (isDisposed ()) return LRESULT.ZERO;
+ }
+ return new LRESULT (code);
+ }
+ }
+ return result;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Composite.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Composite.java
new file mode 100644
index 000000000..8289d4348
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Composite.java
@@ -0,0 +1,1991 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class are controls which are capable
+ * of containing other controls.
+ *
+ *
+ * NO_BACKGROUND
, NO_FOCUS
, NO_MERGE_PAINTS
,
+ * and NO_REDRAW_RESIZE
styles are intended for use with Canvas
.
+ * They can be used with Composite
if you are drawing your own, but their
+ * behavior is undefined if they are used with subclasses of Composite
other
+ * than Canvas
.
+ * CENTER
style, although undefined for composites, has the
+ * same value as EMBEDDED
which is used to embed widgets from other
+ * widget toolkits into SWT. On some operating systems (GTK), this may cause
+ * the children of this composite to be obscured.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#NO_BACKGROUND
+ * @see SWT#NO_FOCUS
+ * @see SWT#NO_MERGE_PAINTS
+ * @see SWT#NO_REDRAW_RESIZE
+ * @see SWT#NO_RADIO_GROUP
+ * @see SWT#EMBEDDED
+ * @see SWT#DOUBLE_BUFFERED
+ * @see Widget#getStyle
+ */
+public Composite (Composite parent, int style) {
+ super (parent, style);
+}
+
+Control [] _getChildren () {
+ int count = 0;
+ long hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
+ if (hwndChild == 0) return new Control [0];
+ while (hwndChild != 0) {
+ count++;
+ hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
+ }
+ Control [] children = new Control [count];
+ int index = 0;
+ hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
+ while (hwndChild != 0) {
+ Control control = display.getControl (hwndChild);
+ if (control != null && control != this) {
+ children [index++] = control;
+ }
+ hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
+ }
+ if (count == index) return children;
+ Control [] newChildren = new Control [index];
+ System.arraycopy (children, 0, newChildren, 0, index);
+ return newChildren;
+}
+
+Control [] _getTabList () {
+ if (tabList == null) return tabList;
+ int count = 0;
+ for (int i=0; i
+ *
+ *
+ * @deprecated use {@link Composite#layout(Control[], int)} instead
+ * @since 3.1
+ */
+@Deprecated
+public void changed (Control[] changed) {
+ layout(changed, SWT.DEFER);
+}
+
+@Override
+void checkBuffered () {
+ if ((state & CANVAS) == 0) {
+ super.checkBuffered ();
+ }
+}
+
+@Override
+void checkComposited () {
+ if ((state & CANVAS) != 0) {
+ if ((style & SWT.TRANSPARENT) != 0) {
+ long hwndParent = parent.handle;
+ int bits = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
+ bits |= OS.WS_EX_COMPOSITED;
+ OS.SetWindowLong (hwndParent, OS.GWL_EXSTYLE, bits);
+ }
+ }
+}
+
+@Override
+protected void checkSubclass () {
+ /* Do nothing - Subclassing is allowed */
+}
+
+@Override
+Widget [] computeTabList () {
+ Widget result [] = super.computeTabList ();
+ if (result.length == 0) return result;
+ Control [] list = tabList != null ? _getTabList () : _getChildren ();
+ for (int i=0; i
+ *
+ */
+/*public*/ void copyArea (GC gc, int x, int y, int width, int height) {
+ checkWidget ();
+ if (gc == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+
+ //XP only, no GDI+
+ //#define PW_CLIENTONLY 0x00000001
+ //DCOrg() wrong
+ //topHandle wrong for Tree?
+ long hDC = gc.handle;
+ int nSavedDC = OS.SaveDC (hDC);
+ OS.IntersectClipRect (hDC, 0, 0, width, height);
+
+ //WRONG PARENT
+ POINT lpPoint = new POINT ();
+ long hwndParent = OS.GetParent (handle);
+ OS.MapWindowPoints (handle, hwndParent, lpPoint, 1);
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ POINT lpPoint1 = new POINT (), lpPoint2 = new POINT ();
+ x = x + (lpPoint.x - rect.left);
+ y = y + (lpPoint.y - rect.top);
+ OS.SetWindowOrgEx (hDC, x, y, lpPoint1);
+ OS.SetBrushOrgEx (hDC, x, y, lpPoint2);
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.WS_VISIBLE) == 0) {
+ OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
+ }
+ //NECESSARY?
+ OS.RedrawWindow (handle, null, 0, OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN);
+ OS.PrintWindow (handle, hDC, 0);//0x00000001);
+ if ((bits & OS.WS_VISIBLE) == 0) {
+ OS.DefWindowProc(handle, OS.WM_SETREDRAW, 0, 0);
+ }
+ OS.RestoreDC (hDC, nSavedDC);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state |= CANVAS;
+ if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0 || findThemeControl () == parent) {
+ state |= THEME_BACKGROUND;
+ }
+ if ((style & SWT.TRANSPARENT) != 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ bits |= OS.WS_EX_TRANSPARENT;
+ OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
+ }
+}
+
+@Override
+int applyThemeBackground () {
+ /*
+ * Composite with scrollbars would not inherit the theme because it was
+ * probably being used to implement a control similar to a Text, List,
+ * Table, or Tree, and those controls do not inherit the background theme.
+ * We assume that a Composite that did not have scrollbars was probably just
+ * being used to group some other controls, therefore it should inherit.
+ *
+ * But when Composite background is set to COLOR_TRANSPARENT (i.e.
+ * backgroundAlpha as '0') which means parent theme should be inherited, so
+ * enable the THEME_BACKGROUND in 'state' to support background transparent.
+ * Refer bug 463127 & related bug 234649.
+ */
+ return (backgroundAlpha == 0 || (style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0 || findThemeControl () == parent) ? 1 : 0;
+}
+
+/**
+ * Fills the interior of the rectangle specified by the arguments,
+ * with the receiver's background.
+ *
+ * offsetX
and offsetY
are used to map from
+ * the gc
origin to the origin of the parent image background. This is useful
+ * to ensure proper alignment of the image background.
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.6
+ */
+public void drawBackground (GC gc, int x, int y, int width, int height, int offsetX, int offsetY) {
+ checkWidget ();
+ x = DPIUtil.autoScaleUp(x);
+ y = DPIUtil.autoScaleUp(y);
+ width = DPIUtil.autoScaleUp(width);
+ height = DPIUtil.autoScaleUp(height);
+ offsetX = DPIUtil.autoScaleUp(offsetX);
+ offsetY = DPIUtil.autoScaleUp(offsetY);
+ drawBackgroundInPixels(gc, x, y, width, height, offsetX, offsetY);
+}
+
+void drawBackgroundInPixels(GC gc, int x, int y, int width, int height, int offsetX, int offsetY) {
+ if (gc == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ RECT rect = new RECT ();
+ OS.SetRect (rect, x, y, x + width, y + height);
+ long hDC = gc.handle;
+ int pixel = background == -1 ? gc.getBackground ().handle : -1;
+ drawBackground (hDC, rect, pixel, offsetX, offsetY);
+}
+
+Composite findDeferredControl () {
+ return layoutCount > 0 ? this : parent.findDeferredControl ();
+}
+
+@Override
+Menu [] findMenus (Control control) {
+ if (control == this) return new Menu [0];
+ Menu result [] = super.findMenus (control);
+ Control [] children = _getChildren ();
+ for (int i=0; iINHERIT_NONE
, INHERIT_DEFAULT
,
+ * INHERIT_FORCE
.
+ *
+ * @return the background mode
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ *
+ * @since 3.2
+ */
+public int getBackgroundMode () {
+ checkWidget ();
+ return backgroundMode;
+}
+
+/**
+ * Returns a (possibly empty) array containing the receiver's children.
+ * Children are returned in the order that they are drawn. The topmost
+ * control appears at the beginning of the array. Subsequent controls
+ * draw beneath this control and appear later in the array.
+ *
+ *
+ */
+public Control [] getChildren () {
+ checkWidget ();
+ return _getChildren ();
+}
+
+int getChildrenCount () {
+ /*
+ * NOTE: The current implementation will count
+ * non-registered children.
+ */
+ int count = 0;
+ long hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
+ while (hwndChild != 0) {
+ count++;
+ hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
+ }
+ return count;
+}
+
+/**
+ * Returns layout which is associated with the receiver, or
+ * null if one has not been set.
+ *
+ * @return the receiver's layout or null
+ *
+ * @exception SWTException
+ *
+ */
+public Layout getLayout () {
+ checkWidget ();
+ return layout;
+}
+
+/**
+ * Gets the (possibly empty) tabbing order for the control.
+ *
+ * @return tabList the ordered list of controls representing the tab order
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #setTabList
+ */
+public Control [] getTabList () {
+ checkWidget ();
+ Control [] tabList = _getTabList ();
+ if (tabList == null) {
+ int count = 0;
+ Control [] list =_getChildren ();
+ for (int i=0; ifalse
otherwise.
+ *
+ * @return the receiver's deferred layout state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #setLayoutDeferred(boolean)
+ * @see #isLayoutDeferred()
+ *
+ * @since 3.1
+ */
+public boolean getLayoutDeferred () {
+ checkWidget ();
+ return layoutCount > 0 ;
+}
+
+/**
+ * Returns true
if the receiver or any ancestor
+ * up to and including the receiver's nearest ancestor shell
+ * has deferred the performing of layouts. Otherwise, false
+ * is returned.
+ *
+ * @return the receiver's deferred layout state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #setLayoutDeferred(boolean)
+ * @see #getLayoutDeferred()
+ *
+ * @since 3.1
+ */
+public boolean isLayoutDeferred () {
+ checkWidget ();
+ return findDeferredControl () != null;
+}
+
+/**
+ * If the receiver has a layout, asks the layout to lay out
+ * (that is, set the size and location of) the receiver's children.
+ * If the receiver does not have a layout, do nothing.
+ * layout(true)
+ * discards all cached layout information, even from controls which
+ * have not changed. It is much more efficient to invoke
+ * {@link Control#requestLayout()} on every control which has changed
+ * in the layout than it is to invoke this method on the layout itself.
+ * layout(true)
.
+ *
+ *
+ */
+public void layout () {
+ checkWidget ();
+ layout (true);
+}
+
+/**
+ * If the receiver has a layout, asks the layout to lay out
+ * (that is, set the size and location of) the receiver's children.
+ * If the argument is true
the layout must not rely
+ * on any information it has cached about the immediate children. If it
+ * is false
the layout may (potentially) optimize the
+ * work it is doing by assuming that none of the receiver's
+ * children has changed state since the last layout.
+ * If the receiver does not have a layout, do nothing.
+ * layout(false)
).
+ * true
if the layout must flush its caches, and false
otherwise
+ *
+ * @exception SWTException
+ *
+ */
+public void layout (boolean changed) {
+ checkWidget ();
+ if (layout == null) return;
+ layout (changed, false);
+}
+
+/**
+ * If the receiver has a layout, asks the layout to lay out
+ * (that is, set the size and location of) the receiver's children.
+ * If the changed argument is true
the layout must not rely
+ * on any information it has cached about its children. If it
+ * is false
the layout may (potentially) optimize the
+ * work it is doing by assuming that none of the receiver's
+ * children has changed state since the last layout.
+ * If the all argument is true
the layout will cascade down
+ * through all child widgets in the receiver's widget tree, regardless of
+ * whether the child has changed size. The changed argument is applied to
+ * all layouts. If the all argument is false
, the layout will
+ * not cascade down through all child widgets in the receiver's widget
+ * tree. However, if a child is resized as a result of a call to layout, the
+ * resize event will invoke the layout of the child. Note that
+ * a layout due to a resize will not flush any cached information
+ * (same as layout(false)
).
+ * true
if the layout must flush its caches, and false
otherwise
+ * @param all true
if all children in the receiver's widget tree should be laid out, and false
otherwise
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.1
+ */
+public void layout (boolean changed, boolean all) {
+ checkWidget ();
+ if (layout == null && !all) return;
+ markLayout (changed, all);
+ updateLayout (all);
+}
+
+/**
+ * Forces a lay out (that is, sets the size and location) of all widgets that
+ * are in the parent hierarchy of the changed control up to and including the
+ * receiver. The layouts in the hierarchy must not rely on any information
+ * cached about the changed control or any of its ancestors. The layout may
+ * (potentially) optimize the work it is doing by assuming that none of the
+ * peers of the changed control have changed state since the last layout.
+ * If an ancestor does not have a layout, skip it.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.1
+ */
+public void layout (Control [] changed) {
+ checkWidget ();
+ if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT);
+ layout (changed, SWT.NONE);
+}
+
+/**
+ * Forces a lay out (that is, sets the size and location) of all widgets that
+ * are in the parent hierarchy of the changed control up to and including the
+ * receiver.
+ * flags
may be a combination of:
+ *
+ *
+ * changed
array is specified, the flags SWT.ALL
+ * and SWT.CHANGED
have no effect. In this case, the layouts in the
+ * hierarchy must not rely on any information cached about the changed control or
+ * any of its ancestors. The layout may (potentially) optimize the
+ * work it is doing by assuming that none of the peers of the changed
+ * control have changed state since the last layout.
+ * If an ancestor does not have a layout, skip it.
+ * changed
array is not specified, the flag SWT.ALL
+ * indicates that the whole widget tree should be laid out. And the flag
+ * SWT.CHANGED
indicates that the layouts should flush any cached
+ * information for all controls that are laid out.
+ * SWT.DEFER
flag always causes the layout to be deferred by
+ * calling Composite.setLayoutDeferred(true)
and scheduling a call
+ * to Composite.setLayoutDeferred(false)
, which will happen when
+ * appropriate (usually before the next event is handled). When this flag is set,
+ * the application should not call Composite.setLayoutDeferred(boolean)
.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.6
+ */
+public void layout (Control [] changed, int flags) {
+ checkWidget ();
+ if (changed != null) {
+ for (int i=0; iSWT
:
+ * INHERIT_NONE
, INHERIT_DEFAULT
,
+ * INHERIT_FORCE
.
+ *
+ * @param mode the new background mode
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ *
+ * @since 3.2
+ */
+public void setBackgroundMode (int mode) {
+ checkWidget ();
+ backgroundMode = mode;
+ Control [] children = _getChildren ();
+ for (int i = 0; i < children.length; i++) {
+ children [i].updateBackgroundMode ();
+ }
+}
+
+@Override
+void setBoundsInPixels (int x, int y, int width, int height, int flags, boolean defer) {
+ if (display.resizeCount > Display.RESIZE_LIMIT) {
+ defer = false;
+ }
+ if (!defer && (state & CANVAS) != 0) {
+ state &= ~(RESIZE_OCCURRED | MOVE_OCCURRED);
+ state |= RESIZE_DEFERRED | MOVE_DEFERRED;
+ }
+ super.setBoundsInPixels (x, y, width, height, flags, defer);
+ if (!defer && (state & CANVAS) != 0) {
+ boolean wasMoved = (state & MOVE_OCCURRED) != 0;
+ boolean wasResized = (state & RESIZE_OCCURRED) != 0;
+ state &= ~(RESIZE_DEFERRED | MOVE_DEFERRED);
+ if (wasMoved && !isDisposed ()) sendMove ();
+ if (wasResized && !isDisposed ()) sendResize ();
+ }
+}
+
+@Override
+public boolean setFocus () {
+ checkWidget ();
+ Control [] children = _getChildren ();
+ for (int i=0; itrue
, causes subsequent layout
+ * operations in the receiver or any of its children to be ignored.
+ * No layout of any kind can occur in the receiver or any of its
+ * children until the flag is set to false.
+ * Layout operations that occurred while the flag was
+ * true
are remembered and when the flag is set to
+ * false
, the layout operations are performed in an
+ * optimized manner. Nested calls to this method are stacked.
+ *
+ * @param defer the new defer state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #layout(boolean)
+ * @see #layout(Control[])
+ *
+ * @since 3.1
+ */
+public void setLayoutDeferred (boolean defer) {
+ checkWidget();
+ if (!defer) {
+ if (--layoutCount == 0) {
+ if ((state & LAYOUT_CHILD) != 0 || (state & LAYOUT_NEEDED) != 0) {
+ updateLayout (true);
+ }
+ }
+ } else {
+ layoutCount++;
+ }
+}
+/**
+ * Sets the tabbing order for the specified controls to
+ * match the order that they occur in the argument list.
+ *
+ * @param tabList the ordered list of controls representing the tab order or null
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setTabList (Control [] tabList) {
+ checkWidget ();
+ if (tabList != null) {
+ for (int i=0; i
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#BORDER
+ * @see SWT#LEFT_TO_RIGHT
+ * @see SWT#RIGHT_TO_LEFT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Control (Composite parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ createWidget ();
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the control is moved or resized, by sending
+ * it one of the messages defined in the ControlListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ControlListener
+ * @see #removeControlListener
+ */
+public void addControlListener(ControlListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Resize,typedListener);
+ addListener (SWT.Move,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when a drag gesture occurs, by sending it
+ * one of the messages defined in the DragDetectListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DragDetectListener
+ * @see #removeDragDetectListener
+ *
+ * @since 3.3
+ */
+public void addDragDetectListener (DragDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.DragDetect,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the control gains or loses focus, by sending
+ * it one of the messages defined in the FocusListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see FocusListener
+ * @see #removeFocusListener
+ */
+public void addFocusListener (FocusListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.FocusIn,typedListener);
+ addListener (SWT.FocusOut,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when gesture events are generated for the control,
+ * by sending it one of the messages defined in the
+ * GestureListener
interface.
+ * setTouchEnabled(true)
has previously been
+ * invoked on the receiver then setTouchEnabled(false)
+ * must be invoked on it to specify that gesture events should be
+ * sent instead of touch events.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see GestureListener
+ * @see #removeGestureListener
+ * @see #setTouchEnabled
+ *
+ * @since 3.7
+ */
+public void addGestureListener (GestureListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Gesture, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when help events are generated for the control,
+ * by sending it one of the messages defined in the
+ * HelpListener
interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see HelpListener
+ * @see #removeHelpListener
+ */
+public void addHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Help, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard, by sending
+ * it one of the messages defined in the KeyListener
+ * interface.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see KeyListener
+ * @see #removeKeyListener
+ */
+public void addKeyListener (KeyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.KeyUp,typedListener);
+ addListener (SWT.KeyDown,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the platform-specific context menu trigger
+ * has occurred, by sending it one of the messages defined in
+ * the MenuDetectListener
interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MenuDetectListener
+ * @see #removeMenuDetectListener
+ *
+ * @since 3.3
+ */
+public void addMenuDetectListener (MenuDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.MenuDetect, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when mouse buttons are pressed and released, by sending
+ * it one of the messages defined in the MouseListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MouseListener
+ * @see #removeMouseListener
+ */
+public void addMouseListener (MouseListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.MouseDown,typedListener);
+ addListener (SWT.MouseUp,typedListener);
+ addListener (SWT.MouseDoubleClick,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the mouse passes or hovers over controls, by sending
+ * it one of the messages defined in the MouseTrackListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MouseTrackListener
+ * @see #removeMouseTrackListener
+ */
+public void addMouseTrackListener (MouseTrackListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.MouseEnter,typedListener);
+ addListener (SWT.MouseExit,typedListener);
+ addListener (SWT.MouseHover,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the mouse moves, by sending it one of the
+ * messages defined in the MouseMoveListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MouseMoveListener
+ * @see #removeMouseMoveListener
+ */
+public void addMouseMoveListener (MouseMoveListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.MouseMove,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the mouse wheel is scrolled, by sending
+ * it one of the messages defined in the
+ * MouseWheelListener
interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MouseWheelListener
+ * @see #removeMouseWheelListener
+ *
+ * @since 3.3
+ */
+public void addMouseWheelListener (MouseWheelListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.MouseWheel, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver needs to be painted, by sending it
+ * one of the messages defined in the PaintListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see PaintListener
+ * @see #removePaintListener
+ */
+public void addPaintListener (PaintListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Paint,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when touch events occur, by sending it
+ * one of the messages defined in the TouchListener
+ * interface.
+ * setTouchEnabled(true)
to
+ * specify that touch events should be sent, which will cause gesture
+ * events to not be sent.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see TouchListener
+ * @see #removeTouchListener
+ * @see #setTouchEnabled
+ *
+ * @since 3.7
+ */
+public void addTouchListener (TouchListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Touch,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when traversal events occur, by sending it
+ * one of the messages defined in the TraverseListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see TraverseListener
+ * @see #removeTraverseListener
+ */
+public void addTraverseListener (TraverseListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Traverse,typedListener);
+}
+
+int binarySearch (int [] indices, int start, int end, int index) {
+ int low = start, high = end - 1;
+ while (low <= high) {
+ int mid = (low + high) >>> 1;
+ if (indices [mid] == index) return mid;
+ if (indices [mid] < index) {
+ low = mid + 1;
+ } else {
+ high = mid - 1;
+ }
+ }
+ return -low - 1;
+}
+
+long borderHandle () {
+ return handle;
+}
+
+void checkBackground () {
+ Shell shell = getShell ();
+ if (this == shell) return;
+ state &= ~PARENT_BACKGROUND;
+ Composite composite = parent;
+ do {
+ int mode = composite.backgroundMode;
+ if (mode != 0 || backgroundAlpha == 0) {
+ if (mode == SWT.INHERIT_DEFAULT || backgroundAlpha == 0) {
+ Control control = this;
+ do {
+ if ((control.state & THEME_BACKGROUND) == 0) {
+ return;
+ }
+ control = control.parent;
+ } while (control != composite);
+ }
+ state |= PARENT_BACKGROUND;
+ return;
+ }
+ if (composite == shell) break;
+ composite = composite.parent;
+ } while (true);
+}
+
+void checkBorder () {
+ if (getBorderWidthInPixels () == 0) style &= ~SWT.BORDER;
+}
+
+void checkBuffered () {
+ style &= ~SWT.DOUBLE_BUFFERED;
+}
+
+void checkComposited () {
+ /* Do nothing */
+}
+
+boolean checkHandle (long hwnd) {
+ return hwnd == handle;
+}
+
+void checkMirrored () {
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ if ((bits & OS.WS_EX_LAYOUTRTL) != 0) style |= SWT.MIRRORED;
+ }
+}
+
+/**
+ * Returns the preferred size (in points) of the receiver.
+ * SWT.DEFAULT
is passed for the hint.
+ * SWT.DEFAULT
)
+ * @param hHint the height hint (can be SWT.DEFAULT
)
+ * @return the preferred size of the control
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Layout
+ * @see #getBorderWidth
+ * @see #getBounds
+ * @see #getSize
+ * @see #pack(boolean)
+ * @see "computeTrim, getClientArea for controls that implement them"
+ */
+public Point computeSize (int wHint, int hHint) {
+ return computeSize(wHint, hHint, true);
+}
+
+/**
+ * Returns the preferred size (in points) of the receiver.
+ * SWT.DEFAULT
is passed for the hint.
+ * true
, it indicates that the receiver's
+ * contents have changed, therefore any caches that a layout manager
+ * containing the control may have been keeping need to be flushed. When the
+ * control is resized, the changed flag will be false
, so layout
+ * manager caches can be retained.
+ * SWT.DEFAULT
)
+ * @param hHint the height hint (can be SWT.DEFAULT
)
+ * @param changed true
if the control's contents have changed, and false
otherwise
+ * @return the preferred size of the control.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Layout
+ * @see #getBorderWidth
+ * @see #getBounds
+ * @see #getSize
+ * @see #pack(boolean)
+ * @see "computeTrim, getClientArea for controls that implement them"
+ */
+public Point computeSize (int wHint, int hHint, boolean changed){
+ checkWidget ();
+ wHint = (wHint != SWT.DEFAULT ? DPIUtil.autoScaleUp(wHint) : wHint);
+ hHint = (hHint != SWT.DEFAULT ? DPIUtil.autoScaleUp(hHint) : hHint);
+ return DPIUtil.autoScaleDown(computeSizeInPixels(wHint, hHint, changed));
+}
+
+Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ int width = DEFAULT_WIDTH;
+ int height = DEFAULT_HEIGHT;
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ int border = getBorderWidthInPixels ();
+ width += border * 2;
+ height += border * 2;
+ return new Point (width, height);
+}
+
+Widget computeTabGroup () {
+ if (isTabGroup ()) return this;
+ return parent.computeTabGroup ();
+}
+
+Control computeTabRoot () {
+ Control [] tabList = parent._getTabList ();
+ if (tabList != null) {
+ int index = 0;
+ while (index < tabList.length) {
+ if (tabList [index] == this) break;
+ index++;
+ }
+ if (index == tabList.length) {
+ if (isTabGroup ()) return this;
+ }
+ }
+ return parent.computeTabRoot ();
+}
+
+Widget [] computeTabList () {
+ if (isTabGroup ()) {
+ if (getVisible () && getEnabled ()) {
+ return new Widget [] {this};
+ }
+ }
+ return new Widget [0];
+}
+
+void createHandle () {
+ long hwndParent = widgetParent ();
+ handle = OS.CreateWindowEx (
+ widgetExtStyle (),
+ windowClass (),
+ null,
+ widgetStyle (),
+ OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
+ hwndParent,
+ 0,
+ OS.GetModuleHandle (null),
+ widgetCreateStruct ());
+ if (handle == 0) error (SWT.ERROR_NO_HANDLES);
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.WS_CHILD) != 0) {
+ OS.SetWindowLongPtr (handle, OS.GWLP_ID, handle);
+ }
+ if (OS.IsDBLocale && hwndParent != 0) {
+ long hIMC = OS.ImmGetContext (hwndParent);
+ OS.ImmAssociateContext (handle, hIMC);
+ OS.ImmReleaseContext (hwndParent, hIMC);
+ }
+
+}
+
+void checkGesture () {
+ if (OS.WIN32_VERSION >= OS.VERSION (6, 1)) {
+ int value = OS.GetSystemMetrics (OS.SM_DIGITIZER);
+ if ((value & (OS.NID_READY | OS.NID_MULTI_INPUT)) != 0) {
+ /*
+ * Feature in Windows 7: All gestures are enabled by default except GID_ROTATE.
+ * Enable it explicitly by calling SetGestureConfig.
+ */
+ long hHeap = OS.GetProcessHeap ();
+ long pConfigs = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, GESTURECONFIG.sizeof);
+ if (pConfigs != 0) {
+ GESTURECONFIG config = new GESTURECONFIG();
+ config.dwID = OS.GID_ROTATE;
+ config.dwWant = 1;
+ config.dwBlock = 0;
+ OS.MoveMemory (pConfigs, config, GESTURECONFIG.sizeof);
+ OS.SetGestureConfig (handle, 0, 1, pConfigs, GESTURECONFIG.sizeof);
+ OS.HeapFree (hHeap, 0, pConfigs);
+ }
+ }
+ }
+}
+
+void createWidget () {
+ state |= DRAG_DETECT;
+ foreground = background = -1;
+ checkOrientation (parent);
+ createHandle ();
+ checkBackground ();
+ checkBuffered ();
+ checkComposited ();
+ register ();
+ subclass ();
+ setDefaultFont ();
+ checkMirrored ();
+ checkBorder ();
+ checkGesture ();
+ if ((state & PARENT_BACKGROUND) != 0) {
+ setBackground ();
+ }
+}
+
+int defaultBackground () {
+ return OS.GetSysColor (OS.COLOR_BTNFACE);
+}
+
+long defaultFont () {
+ return display.getSystemFont ().handle;
+}
+
+int defaultForeground () {
+ return OS.GetSysColor (OS.COLOR_WINDOWTEXT);
+}
+
+void deregister () {
+ display.removeControl (handle);
+}
+
+@Override
+void destroyWidget () {
+ long hwnd = topHandle ();
+ releaseHandle ();
+ if (hwnd != 0) {
+ OS.DestroyWindow (hwnd);
+ }
+}
+
+/**
+ * Detects a drag and drop gesture. This method is used
+ * to detect a drag gesture when called from within a mouse
+ * down listener.
+ *
+ * setDragDetect
+ * to disable the default detection, listen for mouse down,
+ * and then call dragDetect()
from within the
+ * listener to conditionally detect a drag.
+ * true
if the gesture occurred, and false
otherwise.
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DragDetectListener
+ * @see #addDragDetectListener
+ *
+ * @see #getDragDetect
+ * @see #setDragDetect
+ *
+ * @since 3.3
+ */
+public boolean dragDetect (Event event) {
+ checkWidget ();
+ if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
+ Point loc = event.getLocationInPixels();
+ return dragDetect (event.button, event.count, event.stateMask, loc.x, loc.y);
+}
+
+/**
+ * Detects a drag and drop gesture. This method is used
+ * to detect a drag gesture when called from within a mouse
+ * down listener.
+ *
+ * setDragDetect
+ * to disable the default detection, listen for mouse down,
+ * and then call dragDetect()
from within the
+ * listener to conditionally detect a drag.
+ * true
if the gesture occurred, and false
otherwise.
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DragDetectListener
+ * @see #addDragDetectListener
+ *
+ * @see #getDragDetect
+ * @see #setDragDetect
+ *
+ * @since 3.3
+ */
+public boolean dragDetect (MouseEvent event) {
+ checkWidget ();
+ if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return dragDetect (event.button, event.count, event.stateMask, DPIUtil.autoScaleUp(event.x), DPIUtil.autoScaleUp(event.y)); // To Pixels
+}
+
+boolean dragDetect (int button, int count, int stateMask, int x, int y) {
+ if (button != 1 || count != 1) return false;
+ boolean dragging = dragDetect (handle, x, y, false, null, null);
+ if (OS.GetKeyState (OS.VK_LBUTTON) < 0) {
+ if (OS.GetCapture () != handle) OS.SetCapture (handle);
+ }
+ if (!dragging) {
+ /*
+ * Feature in Windows. DragDetect() captures the mouse
+ * and tracks its movement until the user releases the
+ * left mouse button, presses the ESC key, or moves the
+ * mouse outside the drag rectangle. If the user moves
+ * the mouse outside of the drag rectangle, DragDetect()
+ * returns true and a drag and drop operation can be
+ * started. When the left mouse button is released or
+ * the ESC key is pressed, these events are consumed by
+ * DragDetect() so that application code that matches
+ * mouse down/up pairs or looks for the ESC key will not
+ * function properly. The fix is to send the missing
+ * events when the drag has not started.
+ *
+ * NOTE: For now, don't send a fake WM_KEYDOWN/WM_KEYUP
+ * events for the ESC key. This would require computing
+ * wParam (the key) and lParam (the repeat count, scan code,
+ * extended-key flag, context code, previous key-state flag,
+ * and transition-state flag) which is non-trivial.
+ */
+ if (button == 1 && OS.GetKeyState (OS.VK_ESCAPE) >= 0) {
+ int wParam = 0;
+ if ((stateMask & SWT.CTRL) != 0) wParam |= OS.MK_CONTROL;
+ if ((stateMask & SWT.SHIFT) != 0) wParam |= OS.MK_SHIFT;
+ if ((stateMask & SWT.ALT) != 0) wParam |= OS.MK_ALT;
+ if ((stateMask & SWT.BUTTON1) != 0) wParam |= OS.MK_LBUTTON;
+ if ((stateMask & SWT.BUTTON2) != 0) wParam |= OS.MK_MBUTTON;
+ if ((stateMask & SWT.BUTTON3) != 0) wParam |= OS.MK_RBUTTON;
+ if ((stateMask & SWT.BUTTON4) != 0) wParam |= OS.MK_XBUTTON1;
+ if ((stateMask & SWT.BUTTON5) != 0) wParam |= OS.MK_XBUTTON2;
+ long lParam = OS.MAKELPARAM (x, y);
+ OS.SendMessage (handle, OS.WM_LBUTTONUP, wParam, lParam);
+ }
+ return false;
+ }
+ return sendDragEvent (button, stateMask, x, y);
+}
+
+void drawBackground (long hDC) {
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ drawBackground (hDC, rect);
+}
+
+void drawBackground (long hDC, RECT rect) {
+ drawBackground (hDC, rect, -1, 0, 0);
+}
+
+void drawBackground (long hDC, RECT rect, int pixel, int tx, int ty) {
+ Control control = findBackgroundControl ();
+ if (control != null) {
+ if (control.backgroundImage != null) {
+ fillImageBackground (hDC, control, rect, tx, ty);
+ return;
+ }
+ pixel = control.getBackgroundPixel ();
+ }
+ if (pixel == -1) {
+ if ((state & THEME_BACKGROUND) != 0) {
+ if (OS.IsAppThemed ()) {
+ control = findThemeControl ();
+ if (control != null) {
+ fillThemeBackground (hDC, control, rect);
+ return;
+ }
+ }
+ }
+ }
+ if (pixel == -1) pixel = getBackgroundPixel ();
+ fillBackground (hDC, pixel, rect);
+}
+
+void drawImageBackground (long hDC, long hwnd, long hBitmap, RECT rect, int tx, int ty) {
+ RECT rect2 = new RECT ();
+ OS.GetClientRect (hwnd, rect2);
+ OS.MapWindowPoints (hwnd, handle, rect2, 2);
+ long hBrush = findBrush (hBitmap, OS.BS_PATTERN);
+ POINT lpPoint = new POINT ();
+ OS.GetWindowOrgEx (hDC, lpPoint);
+ OS.SetBrushOrgEx (hDC, -rect2.left - lpPoint.x - tx, -rect2.top - lpPoint.y - ty, lpPoint);
+ long hOldBrush = OS.SelectObject (hDC, hBrush);
+ OS.PatBlt (hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY);
+ OS.SetBrushOrgEx (hDC, lpPoint.x, lpPoint.y, null);
+ OS.SelectObject (hDC, hOldBrush);
+}
+
+void drawThemeBackground (long hDC, long hwnd, RECT rect) {
+ /* Do nothing */
+}
+
+void enableDrag (boolean enabled) {
+ /* Do nothing */
+}
+
+void enableWidget (boolean enabled) {
+ OS.EnableWindow (handle, enabled);
+}
+
+void fillBackground (long hDC, int pixel, RECT rect) {
+ if (rect.left > rect.right || rect.top > rect.bottom) return;
+ OS.FillRect (hDC, rect, findBrush (pixel, OS.BS_SOLID));
+}
+
+void fillImageBackground (long hDC, Control control, RECT rect, int tx, int ty) {
+ if (rect.left > rect.right || rect.top > rect.bottom) return;
+ if (control != null) {
+ Image image = control.backgroundImage;
+ if (image != null) {
+ control.drawImageBackground (hDC, handle, image.handle, rect, tx, ty);
+ }
+ }
+}
+
+void fillThemeBackground (long hDC, Control control, RECT rect) {
+ if (rect.left > rect.right || rect.top > rect.bottom) return;
+ if (control != null) {
+ control.drawThemeBackground (hDC, handle, rect);
+ }
+}
+
+Control findBackgroundControl () {
+ if ((background != -1 || backgroundImage != null) && backgroundAlpha > 0) return this;
+ return (parent != null && (state & PARENT_BACKGROUND) != 0) ? parent.findBackgroundControl () : null;
+}
+
+long findBrush (long value, int lbStyle) {
+ return parent.findBrush (value, lbStyle);
+}
+
+Cursor findCursor () {
+ if (cursor != null) return cursor;
+ return parent.findCursor ();
+}
+
+Control findImageControl () {
+ Control control = findBackgroundControl ();
+ return control != null && control.backgroundImage != null ? control : null;
+}
+
+Control findThemeControl () {
+ return background == -1 && backgroundImage == null ? parent.findThemeControl () : null;
+}
+
+Menu [] findMenus (Control control) {
+ if (menu != null && this != control) return new Menu [] {menu};
+ return new Menu [0];
+}
+
+char findMnemonic (String string) {
+ int index = 0;
+ int length = string.length ();
+ do {
+ while (index < length && string.charAt (index) != '&') index++;
+ if (++index >= length) return '\0';
+ if (string.charAt (index) != '&') return string.charAt (index);
+ index++;
+ } while (index < length);
+ return '\0';
+}
+
+void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, Menu [] menus) {
+ oldShell.fixShell (newShell, this);
+ oldDecorations.fixDecorations (newDecorations, this, menus);
+}
+
+void fixFocus (Control focusControl) {
+ Shell shell = getShell ();
+ Control control = this;
+ Display display = this.display;
+ boolean oldFixFocus = display.fixFocus;
+ display.fixFocus = true;
+ try {
+ while (control != shell && (control = control.parent) != null) {
+ if (control.setFocus ()) return;
+ }
+ } finally {
+ display.fixFocus = oldFixFocus;
+ }
+ shell.setSavedFocus (focusControl);
+ OS.SetFocus (0);
+}
+
+/**
+ * Forces the receiver to have the keyboard focus, causing
+ * all keyboard events to be delivered to it.
+ *
+ * @return true
if the control got focus, and false
if it was unable to.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #setFocus
+ */
+public boolean forceFocus () {
+ checkWidget ();
+ if (display.focusEvent == SWT.FocusOut) return false;
+ Decorations shell = menuShell ();
+ shell.setSavedFocus (this);
+ if (!isEnabled () || !isVisible () || !isActive ()) return false;
+ if (isFocusControl ()) return true;
+ shell.setSavedFocus (null);
+ /*
+ * This code is intentionally commented.
+ *
+ * When setting focus to a control, it is
+ * possible that application code can set
+ * the focus to another control inside of
+ * WM_SETFOCUS. In this case, the original
+ * control will no longer have the focus
+ * and the call to setFocus() will return
+ * false indicating failure.
+ *
+ * We are still working on a solution at
+ * this time.
+ */
+// if (OS.GetFocus () != OS.SetFocus (handle)) return false;
+ OS.SetFocus (handle);
+ if (isDisposed ()) return false;
+ shell.setSavedFocus (this);
+ return isFocusControl ();
+}
+
+void forceResize () {
+ if (parent == null) return;
+ WINDOWPOS [] lpwp = parent.lpwp;
+ if (lpwp == null) return;
+ for (int i=0; i
+ *
+ *
+ * @see Accessible#addAccessibleListener
+ * @see Accessible#addAccessibleControlListener
+ *
+ * @since 2.0
+ */
+public Accessible getAccessible () {
+ checkWidget ();
+ if (accessible == null) accessible = new_Accessible (this);
+ return accessible;
+}
+
+/**
+ * Returns the receiver's background color.
+ *
+ *
+ */
+public Color getBackground () {
+ checkWidget ();
+ if (backgroundAlpha == 0) {
+ Color color = Color.win32_new (display, background, 0);
+ return color;
+ }
+ else {
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ return Color.win32_new (display, control.getBackgroundPixel (), backgroundAlpha);
+ }
+}
+
+/**
+ * Returns the receiver's background image.
+ *
+ * @return the background image
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.2
+ */
+public Image getBackgroundImage () {
+ checkWidget ();
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ return control.backgroundImage;
+}
+
+int getBackgroundPixel () {
+ return background != -1 ? background : defaultBackground ();
+}
+
+/**
+ * Returns the receiver's border width in points.
+ *
+ * @return the border width
+ *
+ * @exception SWTException
+ *
+ */
+public int getBorderWidth () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getBorderWidthInPixels ());
+}
+
+int getBorderWidthInPixels () {
+ long borderHandle = borderHandle ();
+ int bits1 = OS.GetWindowLong (borderHandle, OS.GWL_EXSTYLE);
+ if ((bits1 & OS.WS_EX_CLIENTEDGE) != 0) return OS.GetSystemMetrics (OS.SM_CXEDGE);
+ if ((bits1 & OS.WS_EX_STATICEDGE) != 0) return OS.GetSystemMetrics (OS.SM_CXBORDER);
+ int bits2 = OS.GetWindowLong (borderHandle, OS.GWL_STYLE);
+ if ((bits2 & OS.WS_BORDER) != 0) return OS.GetSystemMetrics (OS.SM_CXBORDER);
+ return 0;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location in points
+ * relative to its parent (or its display if its parent is null),
+ * unless the receiver is a shell. In this case, the location is
+ * relative to the display.
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException
+ *
+ */
+public Rectangle getBounds (){
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getBoundsInPixels ());
+}
+
+Rectangle getBoundsInPixels () {
+ forceResize ();
+ RECT rect = new RECT ();
+ OS.GetWindowRect (topHandle (), rect);
+ long hwndParent = parent == null ? 0 : parent.handle;
+ OS.MapWindowPoints (0, hwndParent, rect, 2);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ return new Rectangle (rect.left, rect.top, width, height);
+}
+
+int getCodePage () {
+ return OS.CP_ACP;
+}
+
+String getClipboardText () {
+ String string = "";
+ if (OS.OpenClipboard (0)) {
+ long hMem = OS.GetClipboardData (OS.CF_UNICODETEXT);
+ if (hMem != 0) {
+ /* Ensure byteCount is a multiple of 2 bytes on UNICODE platforms */
+ int byteCount = OS.GlobalSize (hMem) / TCHAR.sizeof * TCHAR.sizeof;
+ long ptr = OS.GlobalLock (hMem);
+ if (ptr != 0) {
+ /* Use the character encoding for the default locale */
+ TCHAR buffer = new TCHAR (0, byteCount / TCHAR.sizeof);
+ OS.MoveMemory (buffer, ptr, byteCount);
+ string = buffer.toString (0, buffer.strlen ());
+ OS.GlobalUnlock (hMem);
+ }
+ }
+ OS.CloseClipboard ();
+ }
+ return string;
+}
+
+/**
+ * Returns the receiver's cursor, or null if it has not been set.
+ * null
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.3
+ */
+public Cursor getCursor () {
+ checkWidget ();
+ return cursor;
+}
+
+/**
+ * Returns true
if the receiver is detecting
+ * drag gestures, and false
otherwise.
+ *
+ * @return the receiver's drag detect state
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.3
+ */
+public boolean getDragDetect () {
+ checkWidget ();
+ return (state & DRAG_DETECT) != 0;
+}
+
+boolean getDrawing () {
+ return drawCount <= 0;
+}
+
+/**
+ * Returns true
if the receiver is enabled, and
+ * false
otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #isEnabled
+ */
+public boolean getEnabled () {
+ checkWidget ();
+ return OS.IsWindowEnabled (handle);
+}
+
+/**
+ * Returns the font that the receiver will use to paint textual information.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException
+ *
+ */
+public Font getFont () {
+ checkWidget ();
+ if (font != null) return font;
+ long hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (hFont == 0) hFont = defaultFont ();
+ return Font.win32_new (display, hFont);
+}
+
+/**
+ * Returns the foreground color that the receiver will use to draw.
+ *
+ * @return the receiver's foreground color
+ *
+ * @exception SWTException
+ *
+ */
+public Color getForeground () {
+ checkWidget ();
+ return Color.win32_new (display, getForegroundPixel ());
+}
+
+int getForegroundPixel () {
+ return foreground != -1 ? foreground : defaultForeground ();
+}
+
+/**
+ * Returns layout data which is associated with the receiver.
+ *
+ * @return the receiver's layout data
+ *
+ * @exception SWTException
+ *
+ */
+public Object getLayoutData () {
+ checkWidget ();
+ return layoutData;
+}
+
+/**
+ * Returns a point describing the receiver's location relative
+ * to its parent in points (or its display if its parent is null), unless
+ * the receiver is a shell. In this case, the point is
+ * relative to the display.
+ *
+ * @return the receiver's location
+ *
+ * @exception SWTException
+ *
+ */
+public Point getLocation () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getLocationInPixels());
+}
+
+Point getLocationInPixels () {
+ forceResize ();
+ RECT rect = new RECT ();
+ OS.GetWindowRect (topHandle (), rect);
+ long hwndParent = parent == null ? 0 : parent.handle;
+ OS.MapWindowPoints (0, hwndParent, rect, 2);
+ return new Point (rect.left, rect.top);
+}
+
+/**
+ * Returns the receiver's pop up menu if it has one, or null
+ * if it does not. All controls may optionally have a pop up
+ * menu that is displayed when the user requests one for
+ * the control. The sequence of key strokes, button presses
+ * and/or button releases that are used to request a pop up
+ * menu is platform specific.
+ *
+ * @return the receiver's menu
+ *
+ * @exception SWTException
+ *
+ */
+@Override
+public Menu getMenu () {
+ checkWidget ();
+ return menu;
+}
+
+/**
+ * Returns the receiver's monitor.
+ *
+ * @return the receiver's monitor
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.0
+ */
+public Monitor getMonitor () {
+ checkWidget ();
+ long hmonitor = OS.MonitorFromWindow (handle, OS.MONITOR_DEFAULTTONEAREST);
+ return display.getMonitor (hmonitor);
+}
+
+/**
+ * Returns the orientation of the receiver, which will be one of the
+ * constants SWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
+ *
+ * @return the orientation style
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.7
+ */
+public int getOrientation () {
+ checkWidget ();
+ return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+}
+
+/**
+ * Returns the receiver's parent, which must be a Composite
+ * or null when the receiver is a shell that was created with null or
+ * a display for a parent.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException
+ *
+ */
+public Composite getParent () {
+ checkWidget ();
+ return parent;
+}
+
+Control [] getPath () {
+ int count = 0;
+ Shell shell = getShell ();
+ Control control = this;
+ while (control != shell) {
+ count++;
+ control = control.parent;
+ }
+ control = this;
+ Control [] result = new Control [count];
+ while (control != shell) {
+ result [--count] = control;
+ control = control.parent;
+ }
+ return result;
+}
+
+/**
+ * Returns the region that defines the shape of the control,
+ * or null if the control has the default shape.
+ *
+ * @return the region that defines the shape of the shell (or null)
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public Region getRegion () {
+ checkWidget ();
+ return region;
+}
+
+/**
+ * Returns the receiver's shell. For all controls other than
+ * shells, this simply returns the control's nearest ancestor
+ * shell. Shells return themselves, even if they are children
+ * of other shells.
+ *
+ * @return the receiver's shell
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getParent
+ */
+public Shell getShell () {
+ checkWidget ();
+ return parent.getShell ();
+}
+
+/**
+ * Returns a point describing the receiver's size in points. The
+ * x coordinate of the result is the width of the receiver.
+ * The y coordinate of the result is the height of the
+ * receiver.
+ *
+ * @return the receiver's size
+ *
+ * @exception SWTException
+ *
+ */
+public Point getSize (){
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getSizeInPixels ());
+}
+
+Point getSizeInPixels () {
+ forceResize ();
+ RECT rect = new RECT ();
+ OS.GetWindowRect (topHandle (), rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ return new Point (width, height);
+}
+
+/**
+ * Calculates a slightly different color, e.g. for the hot state of a button.
+ * @param pixel the color to start with
+ */
+int getSlightlyDifferentColor(int pixel) {
+ return getDifferentColor(pixel, 0.1);
+}
+
+/**
+ * Calculates a different color, e.g. for the checked state of a toggle button
+ * or to highlight a selected button.
+ * @param pixel the color to start with
+ */
+int getDifferentColor(int pixel) {
+ return getDifferentColor(pixel, 0.2);
+}
+
+/**
+ * @param factor must be between [0..1]. The bounds are not checked
+ */
+int getDifferentColor(int pixel, double factor) {
+ int red = pixel & 0xFF;
+ int green = (pixel & 0xFF00) >> 8;
+ int blue = (pixel & 0xFF0000) >> 16;
+ red += calcDiff(red, factor);
+ green += calcDiff(green, factor);
+ blue += calcDiff(blue, factor);
+ return (red & 0xFF) | ((green & 0xFF) << 8) | ((blue & 0xFF) << 16);
+}
+
+long /* int */ calcDiff(int component, double factor) {
+ if (component > 127) {
+ return Math.round(component * -1 * factor);
+ } else {
+ return Math.round((255 - component) * factor);
+ }
+}
+
+/**
+ * Calculates a slightly different background color, e.g. for highlighting the sort column
+ * in a table or tree. This method produces less contrast that {@link #getSlightlyDifferentColor(int)}.
+ * @param pixel the color to start with
+ */
+int getSlightlyDifferentBackgroundColor(int pixel) {
+ int offset = 8;
+ int red = pixel & 0xFF;
+ int green = (pixel & 0xFF00) >> 8;
+ int blue = (pixel & 0xFF0000) >> 16;
+ red = red > 127 ? red-offset : red+offset;
+ green = green > 127 ? green-offset : green+offset;
+ blue = blue > 127 ? blue-offset : blue+offset;
+ return (red & 0xFF) | ((green & 0xFF) << 8) | ((blue & 0xFF) << 16);
+}
+
+/**
+ * Returns the text direction of the receiver, which will be one of the
+ * constants SWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
+ *
+ * @return the text direction style
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.102
+ */
+public int getTextDirection() {
+ checkWidget ();
+ int flags = OS.WS_EX_LAYOUTRTL | OS.WS_EX_RTLREADING;
+ int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE) & flags;
+ return bits == 0 || bits == flags ? SWT.LEFT_TO_RIGHT : SWT.RIGHT_TO_LEFT;
+}
+
+/**
+ * Returns the receiver's tool tip text, or null if it has
+ * not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception SWTException
+ *
+ */
+public String getToolTipText () {
+ checkWidget ();
+ return toolTipText;
+}
+
+/**
+ * Returns true
if this control is set to send touch events, or
+ * false
if it is set to send gesture events instead. This method
+ * also returns false
if a touch-based input device is not detected
+ * (this can be determined with Display#getTouchEnabled()
). Use
+ * {@link #setTouchEnabled(boolean)} to switch the events that a control sends
+ * between touch events and gesture events.
+ *
+ * @return true
if the control is set to send touch events, or false
otherwise
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #setTouchEnabled
+ * @see Display#getTouchEnabled
+ *
+ * @since 3.7
+ */
+public boolean getTouchEnabled () {
+ checkWidget ();
+ return OS.IsTouchWindow (handle, null);
+}
+
+/**
+ * Returns true
if the receiver is visible, and
+ * false
otherwise.
+ *
+ *
+ */
+public boolean getVisible () {
+ checkWidget ();
+ if (!getDrawing()) return (state & HIDDEN) == 0;
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ return (bits & OS.WS_VISIBLE) != 0;
+}
+
+boolean hasCursor () {
+ RECT rect = new RECT ();
+ if (!OS.GetClientRect (handle, rect)) return false;
+ OS.MapWindowPoints (handle, 0, rect, 2);
+ POINT pt = new POINT ();
+ return OS.GetCursorPos (pt) && OS.PtInRect (rect, pt);
+}
+
+boolean hasCustomBackground() {
+ return background != -1;
+}
+
+boolean hasCustomForeground() {
+ return foreground != -1;
+}
+
+boolean hasFocus () {
+ /*
+ * If a non-SWT child of the control has focus,
+ * then this control is considered to have focus
+ * even though it does not have focus in Windows.
+ */
+ long hwndFocus = OS.GetFocus ();
+ while (hwndFocus != 0) {
+ if (hwndFocus == handle) return true;
+ if (display.getControl (hwndFocus) != null) {
+ return false;
+ }
+ hwndFocus = OS.GetParent (hwndFocus);
+ }
+ return false;
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * Control
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * Control
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * true
if the receiver is enabled and all
+ * ancestors up to and including the receiver's nearest ancestor
+ * shell are enabled. Otherwise, false
is returned.
+ * A disabled control is typically not selectable from the user
+ * interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getEnabled
+ */
+public boolean isEnabled () {
+ checkWidget ();
+ return getEnabled () && parent.isEnabled ();
+}
+
+/**
+ * Returns true
if the receiver has the user-interface
+ * focus, and false
otherwise.
+ *
+ * @return the receiver's focus state
+ *
+ * @exception SWTException
+ *
+ */
+public boolean isFocusControl () {
+ checkWidget ();
+ Control focusControl = display.focusControl;
+ if (focusControl != null && !focusControl.isDisposed ()) {
+ return this == focusControl;
+ }
+ return hasFocus ();
+}
+
+boolean isFocusAncestor (Control control) {
+ while (control != null && control != this && !(control instanceof Shell)) {
+ control = control.parent;
+ }
+ return control == this;
+}
+
+/**
+ * Returns true
if the underlying operating
+ * system supports this reparenting, otherwise false
+ *
+ * @return true
if the widget can be reparented, otherwise false
+ *
+ * @exception SWTException
+ *
+ */
+public boolean isReparentable () {
+ checkWidget ();
+ return true;
+}
+
+boolean isShowing () {
+ /*
+ * This is not complete. Need to check if the
+ * widget is obscured by a parent or sibling.
+ */
+ if (!isVisible ()) return false;
+ Control control = this;
+ while (control != null) {
+ Point size = control.getSizeInPixels ();
+ if (size.x == 0 || size.y == 0) {
+ return false;
+ }
+ control = control.parent;
+ }
+ return true;
+ /*
+ * Check to see if current damage is included.
+ */
+// if (!OS.IsWindowVisible (handle)) return false;
+// int flags = OS.DCX_CACHE | OS.DCX_CLIPCHILDREN | OS.DCX_CLIPSIBLINGS;
+// long hDC = OS.GetDCEx (handle, 0, flags);
+// int result = OS.GetClipBox (hDC, new RECT ());
+// OS.ReleaseDC (handle, hDC);
+// return result != OS.NULLREGION;
+}
+
+boolean isTabGroup () {
+ Control [] tabList = parent._getTabList ();
+ if (tabList != null) {
+ for (int i=0; ifalse
is returned.
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getVisible
+ */
+public boolean isVisible () {
+ checkWidget ();
+ if (OS.IsWindowVisible (handle)) return true;
+ return getVisible () && parent.isVisible ();
+}
+
+@Override
+void mapEvent (long hwnd, Event event) {
+ if (hwnd != handle) {
+ POINT point = new POINT ();
+ Point loc = event.getLocationInPixels();
+ point.x = loc.x;
+ point.y = loc.y;
+ OS.MapWindowPoints (hwnd, handle, point, 1);
+ event.setLocationInPixels(point.x, point.y);
+ }
+}
+
+void markLayout (boolean changed, boolean all) {
+ /* Do nothing */
+}
+
+Decorations menuShell () {
+ return parent.menuShell ();
+}
+
+boolean mnemonicHit (char key) {
+ return false;
+}
+
+boolean mnemonicMatch (char key) {
+ return false;
+}
+
+/**
+ * Moves the receiver above the specified control in the
+ * drawing order. If the argument is null, then the receiver
+ * is moved to the top of the drawing order. The control at
+ * the top of the drawing order will not be covered by other
+ * controls even if they occupy intersecting areas.
+ *
+ * @param control the sibling control (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Control#moveBelow
+ * @see Composite#getChildren
+ */
+public void moveAbove (Control control) {
+ checkWidget ();
+ long topHandle = topHandle (), hwndAbove = OS.HWND_TOP;
+ if (control != null) {
+ if (control.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if (parent != control.parent) return;
+ long hwnd = control.topHandle ();
+ if (hwnd == 0 || hwnd == topHandle) return;
+ hwndAbove = OS.GetWindow (hwnd, OS.GW_HWNDPREV);
+ /*
+ * Bug in Windows. For some reason, when GetWindow ()
+ * with GW_HWNDPREV is used to query the previous window
+ * in the z-order with the first child, Windows returns
+ * the first child instead of NULL. The fix is to detect
+ * this case and move the control to the top.
+ */
+ if (hwndAbove == 0 || hwndAbove == hwnd) {
+ hwndAbove = OS.HWND_TOP;
+ }
+ }
+ int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (topHandle, hwndAbove, 0, 0, 0, 0, flags);
+}
+
+/**
+ * Moves the receiver below the specified control in the
+ * drawing order. If the argument is null, then the receiver
+ * is moved to the bottom of the drawing order. The control at
+ * the bottom of the drawing order will be covered by all other
+ * controls which occupy intersecting areas.
+ *
+ * @param control the sibling control (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Control#moveAbove
+ * @see Composite#getChildren
+ */
+public void moveBelow (Control control) {
+ checkWidget ();
+ long topHandle = topHandle (), hwndAbove = OS.HWND_BOTTOM;
+ if (control != null) {
+ if (control.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if (parent != control.parent) return;
+ hwndAbove = control.topHandle ();
+ } else {
+ /*
+ * Bug in Windows. When SetWindowPos() is called
+ * with HWND_BOTTOM on a dialog shell, the dialog
+ * and the parent are moved to the bottom of the
+ * desktop stack. The fix is to move the dialog
+ * to the bottom of the dialog window stack by
+ * moving behind the first dialog child.
+ */
+ Shell shell = getShell ();
+ if (this == shell && parent != null) {
+ /*
+ * Bug in Windows. For some reason, when GetWindow ()
+ * with GW_HWNDPREV is used to query the previous window
+ * in the z-order with the first child, Windows returns
+ * the first child instead of NULL. The fix is to detect
+ * this case and do nothing because the control is already
+ * at the bottom.
+ */
+ long hwndParent = parent.handle, hwnd = hwndParent;
+ hwndAbove = OS.GetWindow (hwnd, OS.GW_HWNDPREV);
+ while (hwndAbove != 0 && hwndAbove != hwnd) {
+ if (OS.GetWindow (hwndAbove, OS.GW_OWNER) == hwndParent) break;
+ hwndAbove = OS.GetWindow (hwnd = hwndAbove, OS.GW_HWNDPREV);
+ }
+ if (hwndAbove == hwnd) return;
+ }
+ }
+ if (hwndAbove == 0 || hwndAbove == topHandle) return;
+ int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (topHandle, hwndAbove, 0, 0, 0, 0, flags);
+}
+
+Accessible new_Accessible (Control control) {
+ return Accessible.internal_new_Accessible (this);
+}
+
+@Override
+GC new_GC (GCData data) {
+ return GC.win32_new (this, data);
+}
+
+/**
+ * Causes the receiver to be resized to its preferred size.
+ * For a composite, this involves computing the preferred size
+ * from its layout, if there is one.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #computeSize(int, int, boolean)
+ */
+public void pack () {
+ checkWidget ();
+ pack (true);
+}
+
+/**
+ * Causes the receiver to be resized to its preferred size.
+ * For a composite, this involves computing the preferred size
+ * from its layout, if there is one.
+ * true
, it indicates that the receiver's
+ * contents have changed, therefore any caches that a layout manager
+ * containing the control may have been keeping need to be flushed. When the
+ * control is resized, the changed flag will be false
, so layout
+ * manager caches can be retained.
+ *
+ *
+ *
+ * @see #computeSize(int, int, boolean)
+ */
+public void pack (boolean changed) {
+ checkWidget ();
+ /*
+ * Since computeSize is overridden by Custom classes like CCombo
+ * etc... hence we cannot call computeSizeInPixels directly.
+ */
+ setSize (computeSize (SWT.DEFAULT, SWT.DEFAULT, changed));
+}
+
+/**
+ * Prints the receiver and all children.
+ *
+ * @param gc the gc where the drawing occurs
+ * @return true
if the operation was successful and false
otherwise
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public boolean print (GC gc) {
+ checkWidget ();
+ if (gc == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ long topHandle = topHandle ();
+ long hdc = gc.handle;
+ int state = 0;
+ long gdipGraphics = gc.getGCData().gdipGraphics;
+ if (gdipGraphics != 0) {
+ long clipRgn = 0;
+ Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone);
+ long rgn = Gdip.Region_new();
+ if (rgn == 0) error(SWT.ERROR_NO_HANDLES);
+ Gdip.Graphics_GetClip(gdipGraphics, rgn);
+ if (!Gdip.Region_IsInfinite(rgn, gdipGraphics)) {
+ clipRgn = Gdip.Region_GetHRGN(rgn, gdipGraphics);
+ }
+ Gdip.Region_delete(rgn);
+ Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf);
+ float[] lpXform = null;
+ long matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
+ if (matrix == 0) error(SWT.ERROR_NO_HANDLES);
+ Gdip.Graphics_GetTransform(gdipGraphics, matrix);
+ if (!Gdip.Matrix_IsIdentity(matrix)) {
+ lpXform = new float[6];
+ Gdip.Matrix_GetElements(matrix, lpXform);
+ }
+ Gdip.Matrix_delete(matrix);
+ hdc = Gdip.Graphics_GetHDC(gdipGraphics);
+ state = OS.SaveDC(hdc);
+ if (lpXform != null) {
+ OS.SetGraphicsMode(hdc, OS.GM_ADVANCED);
+ OS.SetWorldTransform(hdc, lpXform);
+ }
+ if (clipRgn != 0) {
+ OS.SelectClipRgn(hdc, clipRgn);
+ OS.DeleteObject(clipRgn);
+ }
+ }
+ int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (topHandle, null, 0, flags);
+ printWidget (topHandle, hdc, gc);
+ if (gdipGraphics != 0) {
+ OS.RestoreDC(hdc, state);
+ Gdip.Graphics_ReleaseHDC(gdipGraphics, hdc);
+ }
+ return true;
+}
+
+void printWidget (long hwnd, long hdc, GC gc) {
+ /*
+ * Bug in Windows. For some reason, PrintWindow()
+ * returns success but does nothing when it is called
+ * on a printer. The fix is to just go directly to
+ * WM_PRINT in this case.
+ */
+ boolean success = false;
+ if (!(OS.GetDeviceCaps(gc.handle, OS.TECHNOLOGY) == OS.DT_RASPRINTER)) {
+ /*
+ * Bug in Windows. When PrintWindow() will only draw that
+ * portion of a control that is not obscured by the shell.
+ * The fix is temporarily reparent the window to the desktop,
+ * call PrintWindow() then reparent the window back.
+ */
+ long hwndParent = OS.GetParent (hwnd);
+ long hwndShell = hwndParent;
+ while (OS.GetParent (hwndShell) != 0) {
+ if (OS.GetWindow (hwndShell, OS.GW_OWNER) != 0) break;
+ hwndShell = OS.GetParent (hwndShell);
+ }
+ RECT rect1 = new RECT ();
+ OS.GetWindowRect (hwnd, rect1);
+ boolean fixPrintWindow = !OS.IsWindowVisible(hwnd);
+ if (!fixPrintWindow) {
+ RECT rect2 = new RECT ();
+ OS.GetWindowRect (hwndShell, rect2);
+ OS.IntersectRect (rect2, rect1, rect2);
+ fixPrintWindow = !OS.EqualRect (rect2, rect1);
+ }
+ /*
+ * Bug in Windows. PrintWindow() does not print portions
+ * of the receiver that are clipped out using SetWindowRgn()
+ * in a parent. The fix is temporarily reparent the window
+ * to the desktop, call PrintWindow() then reparent the window
+ * back.
+ */
+ if (!fixPrintWindow) {
+ long rgn = OS.CreateRectRgn(0, 0, 0, 0);
+ long parent = OS.GetParent(hwnd);
+ while (parent != hwndShell && !fixPrintWindow) {
+ if (OS.GetWindowRgn(parent, rgn) != 0) {
+ fixPrintWindow = true;
+ }
+ parent = OS.GetParent(parent);
+ }
+ OS.DeleteObject(rgn);
+ }
+ int bits1 = OS.GetWindowLong (hwnd, OS.GWL_STYLE);
+ int bits2 = OS.GetWindowLong (hwnd, OS.GWL_EXSTYLE);
+ long hwndInsertAfter = OS.GetWindow (hwnd, OS.GW_HWNDPREV);
+ /*
+ * Bug in Windows. For some reason, when GetWindow ()
+ * with GW_HWNDPREV is used to query the previous window
+ * in the z-order with the first child, Windows returns
+ * the first child instead of NULL. The fix is to detect
+ * this case and move the control to the top.
+ */
+ if (hwndInsertAfter == 0 || hwndInsertAfter == hwnd) {
+ hwndInsertAfter = OS.HWND_TOP;
+ }
+ if (fixPrintWindow) {
+ int x = OS.GetSystemMetrics (OS.SM_XVIRTUALSCREEN);
+ int y = OS.GetSystemMetrics (OS.SM_YVIRTUALSCREEN);
+ int width = OS.GetSystemMetrics (OS.SM_CXVIRTUALSCREEN);
+ int height = OS.GetSystemMetrics (OS.SM_CYVIRTUALSCREEN);
+ int flags = OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE | OS.SWP_DRAWFRAME;
+ if ((bits1 & OS.WS_VISIBLE) != 0) {
+ OS.DefWindowProc (hwnd, OS.WM_SETREDRAW, 0, 0);
+ }
+ OS.SetWindowPos (hwnd, 0, x + width, y + height, 0, 0, flags);
+ OS.SetWindowLong (hwnd, OS.GWL_STYLE, (bits1 & ~OS.WS_CHILD) | OS.WS_POPUP);
+ OS.SetWindowLong (hwnd, OS.GWL_EXSTYLE, bits2 | OS.WS_EX_TOOLWINDOW);
+ Shell shell = getShell ();
+ Control savedFocus = shell.savedFocus;
+ OS.SetParent (hwnd, 0);
+ shell.setSavedFocus (savedFocus);
+ if ((bits1 & OS.WS_VISIBLE) != 0) {
+ OS.DefWindowProc (hwnd, OS.WM_SETREDRAW, 1, 0);
+ }
+ }
+ if ((bits1 & OS.WS_VISIBLE) == 0) {
+ OS.ShowWindow (hwnd, OS.SW_SHOW);
+ }
+ success = OS.PrintWindow (hwnd, hdc, 0);
+ if ((bits1 & OS.WS_VISIBLE) == 0) {
+ OS.ShowWindow (hwnd, OS.SW_HIDE);
+ }
+ if (fixPrintWindow) {
+ if ((bits1 & OS.WS_VISIBLE) != 0) {
+ OS.DefWindowProc (hwnd, OS.WM_SETREDRAW, 0, 0);
+ }
+ OS.SetWindowLong (hwnd, OS.GWL_STYLE, bits1);
+ OS.SetWindowLong (hwnd, OS.GWL_EXSTYLE, bits2);
+ OS.SetParent (hwnd, hwndParent);
+ OS.MapWindowPoints (0, hwndParent, rect1, 2);
+ int flags = OS.SWP_NOSIZE | OS.SWP_NOACTIVATE | OS.SWP_DRAWFRAME;
+ OS.SetWindowPos (hwnd, hwndInsertAfter, rect1.left, rect1.top, rect1.right - rect1.left, rect1.bottom - rect1.top, flags);
+ if ((bits1 & OS.WS_VISIBLE) != 0) {
+ OS.DefWindowProc (hwnd, OS.WM_SETREDRAW, 1, 0);
+ }
+ }
+ }
+
+ /*
+ * Bug in Windows. For some reason, PrintWindow() fails
+ * when it is called on a push button. The fix is to
+ * detect the failure and use WM_PRINT instead. Note
+ * that WM_PRINT cannot be used all the time because it
+ * fails for browser controls when the browser has focus.
+ */
+ if (!success) {
+ int flags = OS.PRF_CLIENT | OS.PRF_NONCLIENT | OS.PRF_ERASEBKGND | OS.PRF_CHILDREN;
+ OS.SendMessage (hwnd, OS.WM_PRINT, hdc, flags);
+ }
+}
+
+/**
+ * Requests that this control and all of its ancestors be repositioned by
+ * their layouts at the earliest opportunity. This should be invoked after
+ * modifying the control in order to inform any dependent layouts of
+ * the change.
+ *
+ *
+ *
+ * @see #update()
+ * @see PaintListener
+ * @see SWT#Paint
+ * @see SWT#NO_BACKGROUND
+ * @see SWT#NO_REDRAW_RESIZE
+ * @see SWT#NO_MERGE_PAINTS
+ * @see SWT#DOUBLE_BUFFERED
+ */
+public void redraw () {
+ checkWidget ();
+ redraw (false);
+}
+
+void redraw (boolean all) {
+// checkWidget ();
+ if (!OS.IsWindowVisible (handle)) return;
+ int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
+ if (all) flags |= OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (handle, null, 0, flags);
+}
+/**
+ * Causes the rectangular area of the receiver specified by
+ * the arguments to be marked as needing to be redrawn.
+ * The next time a paint request is processed, that area of
+ * the receiver will be painted, including the background.
+ * If the all
flag is true
, any
+ * children of the receiver which intersect with the specified
+ * area will also paint their intersecting areas. If the
+ * all
flag is false
, the children
+ * will not be painted.
+ * true
if children should redraw, and false
otherwise
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #update()
+ * @see PaintListener
+ * @see SWT#Paint
+ * @see SWT#NO_BACKGROUND
+ * @see SWT#NO_REDRAW_RESIZE
+ * @see SWT#NO_MERGE_PAINTS
+ * @see SWT#DOUBLE_BUFFERED
+ */
+public void redraw (int x, int y, int width, int height, boolean all) {
+ checkWidget ();
+ x = DPIUtil.autoScaleUp(x);
+ y = DPIUtil.autoScaleUp(y);
+ width = DPIUtil.autoScaleUp(width);
+ height = DPIUtil.autoScaleUp(height);
+ redrawInPixels(x, y, width, height, all);
+}
+
+void redrawInPixels (int x, int y, int width, int height, boolean all) {
+ if (width <= 0 || height <= 0) return;
+ if (!OS.IsWindowVisible (handle)) return;
+ RECT rect = new RECT ();
+ OS.SetRect (rect, x, y, x + width, y + height);
+ int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
+ if (all) flags |= OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (handle, rect, 0, flags);
+}
+
+boolean redrawChildren () {
+ if (!OS.IsWindowVisible (handle)) return false;
+ Control control = findBackgroundControl ();
+ if (control == null) {
+ if ((state & THEME_BACKGROUND) != 0) {
+ if (OS.IsAppThemed ()) {
+ OS.InvalidateRect (handle, null, true);
+ return true;
+ }
+ }
+ } else {
+ if (control.backgroundImage != null) {
+ OS.InvalidateRect (handle, null, true);
+ return true;
+ }
+ }
+ return false;
+}
+
+void register () {
+ display.addControl (handle, this);
+}
+
+@Override
+void releaseHandle () {
+ super.releaseHandle ();
+ handle = 0;
+ parent = null;
+}
+
+@Override
+void releaseParent () {
+ parent.removeControl (this);
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ if (OS.IsDBLocale) {
+ OS.ImmAssociateContext (handle, 0);
+ }
+ if (toolTipText != null) {
+ setToolTipText (getShell (), null);
+ }
+ toolTipText = null;
+ if (menu != null && !menu.isDisposed ()) {
+ menu.dispose ();
+ }
+ backgroundImage = null;
+ menu = null;
+ cursor = null;
+ unsubclass ();
+ deregister ();
+ layoutData = null;
+ if (accessible != null) {
+ accessible.internal_dispose_Accessible ();
+ }
+ accessible = null;
+ region = null;
+ font = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is moved or resized.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ControlListener
+ * @see #addControlListener
+ */
+public void removeControlListener (ControlListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Move, listener);
+ eventTable.unhook (SWT.Resize, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a drag gesture occurs.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see DragDetectListener
+ * @see #addDragDetectListener
+ *
+ * @since 3.3
+ */
+public void removeDragDetectListener(DragDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.DragDetect, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control gains or loses focus.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see FocusListener
+ * @see #addFocusListener
+ */
+public void removeFocusListener(FocusListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.FocusIn, listener);
+ eventTable.unhook (SWT.FocusOut, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when gesture events are generated for the control.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see GestureListener
+ * @see #addGestureListener
+ *
+ * @since 3.7
+ */
+public void removeGestureListener (GestureListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Gesture, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the help events are generated for the control.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see HelpListener
+ * @see #addHelpListener
+ */
+public void removeHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Help, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see KeyListener
+ * @see #addKeyListener
+ */
+public void removeKeyListener(KeyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.KeyUp, listener);
+ eventTable.unhook (SWT.KeyDown, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the platform-specific context menu trigger has
+ * occurred.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MenuDetectListener
+ * @see #addMenuDetectListener
+ *
+ * @since 3.3
+ */
+public void removeMenuDetectListener (MenuDetectListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.MenuDetect, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the mouse passes or hovers over controls.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MouseTrackListener
+ * @see #addMouseTrackListener
+ */
+public void removeMouseTrackListener(MouseTrackListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.MouseEnter, listener);
+ eventTable.unhook (SWT.MouseExit, listener);
+ eventTable.unhook (SWT.MouseHover, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when mouse buttons are pressed and released.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MouseListener
+ * @see #addMouseListener
+ */
+public void removeMouseListener (MouseListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.MouseDown, listener);
+ eventTable.unhook (SWT.MouseUp, listener);
+ eventTable.unhook (SWT.MouseDoubleClick, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the mouse moves.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MouseMoveListener
+ * @see #addMouseMoveListener
+ */
+public void removeMouseMoveListener(MouseMoveListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.MouseMove, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the mouse wheel is scrolled.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MouseWheelListener
+ * @see #addMouseWheelListener
+ *
+ * @since 3.3
+ */
+public void removeMouseWheelListener (MouseWheelListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.MouseWheel, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver needs to be painted.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see PaintListener
+ * @see #addPaintListener
+ */
+public void removePaintListener(PaintListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.Paint, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when touch events occur.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see TouchListener
+ * @see #addTouchListener
+ *
+ * @since 3.7
+ */
+public void removeTouchListener(TouchListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Touch, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when traversal events occur.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see TraverseListener
+ * @see #addTraverseListener
+ */
+public void removeTraverseListener(TraverseListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Traverse, listener);
+}
+
+int resolveTextDirection() {
+ /*
+ * For generic Controls do nothing here. Text-enabled Controls will resolve
+ * AUTO text direction according to their text content.
+ */
+ return SWT.NONE;
+}
+
+void showWidget (boolean visible) {
+ long topHandle = topHandle ();
+ OS.ShowWindow (topHandle, visible ? OS.SW_SHOW : OS.SW_HIDE);
+ if (handle != topHandle) OS.ShowWindow (handle, visible ? OS.SW_SHOW : OS.SW_HIDE);
+}
+
+@Override
+boolean sendFocusEvent (int type) {
+ Shell shell = getShell ();
+
+ /*
+ * Feature in Windows. During the processing of WM_KILLFOCUS,
+ * when the focus window is queried using GetFocus(), it has
+ * already been assigned to the new window. The fix is to
+ * remember the control that is losing or gaining focus and
+ * answer it during WM_KILLFOCUS. If a WM_SETFOCUS occurs
+ * during WM_KILLFOCUS, the focus control needs to be updated
+ * to the current control. At any other time, the focus
+ * control matches Windows.
+ */
+ Display display = this.display;
+ display.focusEvent = type;
+ display.focusControl = this;
+ sendEvent (type);
+ // widget could be disposed at this point
+ display.focusEvent = SWT.None;
+ display.focusControl = null;
+
+ /*
+ * It is possible that the shell may be
+ * disposed at this point. If this happens
+ * don't send the activate and deactivate
+ * events.
+ */
+ if (!shell.isDisposed ()) {
+ switch (type) {
+ case SWT.FocusIn:
+ shell.setActiveControl (this);
+ break;
+ case SWT.FocusOut:
+ if (shell != display.getActiveShell ()) {
+ shell.setActiveControl (null);
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+boolean sendGestureEvent (GESTUREINFO gi) {
+ /**
+ * Feature in Windows 7. GID_BEGIN and GID_END events bubble up through the window
+ * hierarchy for legacy support. Ignore events not targeted for this control.
+ */
+ if (gi.hwndTarget != handle) return true;
+ Event event = new Event ();
+ int type = 0;
+ Point globalPt = new Point(gi.x, gi.y);
+ Point point = toControlInPixels(globalPt.x, globalPt.y);
+ event.setLocationInPixels(point.x, point.y);
+ switch (gi.dwID) {
+ case OS.GID_ZOOM:
+ type = SWT.Gesture;
+ event.detail = SWT.GESTURE_MAGNIFY;
+ int fingerDistance = OS.LODWORD (gi.ullArguments);
+ if ((gi.dwFlags & OS.GF_BEGIN) != 0) {
+ event.detail = SWT.GESTURE_BEGIN;
+ display.magStartDistance = display.lastDistance = fingerDistance;
+ } else if ((gi.dwFlags & OS.GF_END) != 0) {
+ event.detail = SWT.GESTURE_END;
+ }
+
+ /*
+ * The gi.ullArguments is the distance between the fingers.
+ * Scale factor is relative to that original value.
+ */
+ if (fingerDistance == display.lastDistance && event.detail == SWT.GESTURE_MAGNIFY) return true;
+ if (fingerDistance != 0) event.magnification = fingerDistance / display.magStartDistance;
+ display.lastDistance = fingerDistance;
+ break;
+ case OS.GID_PAN:
+ type = SWT.Gesture;
+ event.detail = SWT.GESTURE_PAN;
+ if ((gi.dwFlags & OS.GF_BEGIN) != 0) {
+ event.detail = SWT.GESTURE_BEGIN;
+ display.lastX = point.x;
+ display.lastY = point.y;
+ } else if ((gi.dwFlags & OS.GF_END) != 0) {
+ event.detail = SWT.GESTURE_END;
+ }
+ if (display.lastX == point.x && display.lastY == point.y && event.detail == SWT.GESTURE_PAN) return true;
+ event.xDirection = point.x - display.lastX;
+ event.yDirection = point.y - display.lastY;
+ display.lastX = point.x;
+ display.lastY = point.y;
+ break;
+ case OS.GID_ROTATE:
+ type = SWT.Gesture;
+ event.detail = SWT.GESTURE_ROTATE;
+ double rotationInRadians = OS.GID_ROTATE_ANGLE_FROM_ARGUMENT (OS.LODWORD (gi.ullArguments));
+ if ((gi.dwFlags & OS.GF_BEGIN) != 0) {
+ event.detail = SWT.GESTURE_BEGIN;
+ display.rotationAngle = rotationInRadians;
+ } else if ((gi.dwFlags & OS.GF_END) != 0) {
+ event.detail = SWT.GESTURE_END;
+ }
+
+ /*
+ * Feature in Win32. Rotation events are sent even when the fingers are at rest.
+ * If the current rotation is the same as the last one received don't send the event.
+ */
+ if (display.rotationAngle == rotationInRadians && event.detail == SWT.GESTURE_ROTATE) return true;
+ event.rotation = rotationInRadians * 180.0 / Math.PI;
+ display.rotationAngle = rotationInRadians;
+ break;
+ default:
+ // Unknown gesture -- ignore.
+ break;
+ }
+
+ if (type == 0) return true;
+ setInputState (event, type);
+ sendEvent (type, event);
+ return event.doit;
+}
+
+void sendMove () {
+ sendEvent (SWT.Move);
+}
+
+void sendResize () {
+ sendEvent (SWT.Resize);
+}
+
+void sendTouchEvent (TOUCHINPUT touchInput []) {
+ Event event = new Event ();
+ POINT pt = new POINT ();
+ OS.GetCursorPos (pt);
+ OS.ScreenToClient (handle, pt);
+ event.setLocationInPixels(pt.x, pt.y);
+ Touch [] touches = new Touch [touchInput.length];
+ Monitor monitor = getMonitor ();
+ for (int i = 0; i < touchInput.length; i++) {
+ TOUCHINPUT ti = touchInput [i];
+ TouchSource inputSource = display.findTouchSource (ti.hSource, monitor);
+ int state = 0;
+ if ((ti.dwFlags & OS.TOUCHEVENTF_DOWN) != 0) state = SWT.TOUCHSTATE_DOWN;
+ if ((ti.dwFlags & OS.TOUCHEVENTF_UP) != 0) state = SWT.TOUCHSTATE_UP;
+ if ((ti.dwFlags & OS.TOUCHEVENTF_MOVE) != 0) state = SWT.TOUCHSTATE_MOVE;
+ boolean primary = (ti.dwFlags & OS.TOUCHEVENTF_PRIMARY) != 0;
+ int x = (int)OS.TOUCH_COORD_TO_PIXEL (ti.x);
+ int y = (int)OS.TOUCH_COORD_TO_PIXEL (ti.y);
+ touches [i] = new Touch (ti.dwID, inputSource, state, primary, x, y);
+ }
+ event.touches = touches;
+ setInputState (event, SWT.Touch);
+ postEvent (SWT.Touch, event);
+}
+
+void setBackground () {
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ if (control.backgroundImage != null) {
+ Shell shell = getShell ();
+ shell.releaseBrushes ();
+ setBackgroundImage (control.backgroundImage.handle);
+ } else {
+ setBackgroundPixel (control.background == -1 ? control.defaultBackground() : control.background);
+ }
+}
+
+/**
+ * Sets the receiver's background color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setBackground (Color color) {
+ checkWidget ();
+ _setBackground (color);
+ if (color != null) {
+ this.updateBackgroundMode ();
+ }
+}
+
+private void _setBackground (Color color) {
+ int pixel = -1;
+ int alpha = 255;
+ if (color != null) {
+ if (color.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ pixel = color.handle;
+ alpha = color.getAlpha();
+ }
+ if (pixel == background && alpha == backgroundAlpha) return;
+ background = pixel;
+ backgroundAlpha = alpha;
+ updateBackgroundColor ();
+}
+
+
+/**
+ * Sets the receiver's background image to the image specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null. The background image is tiled to fill
+ * the available space.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.2
+ */
+public void setBackgroundImage (Image image) {
+ checkWidget ();
+ if (image != null) {
+ if (image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (image.type != SWT.BITMAP) error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (backgroundImage == image && backgroundAlpha > 0) return;
+ backgroundAlpha = 255;
+ backgroundImage = image;
+ Shell shell = getShell ();
+ shell.releaseBrushes ();
+ updateBackgroundImage ();
+}
+
+void setBackgroundImage (long hBitmap) {
+ int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
+ OS.RedrawWindow (handle, null, 0, flags);
+}
+
+void setBackgroundPixel (int pixel) {
+ int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
+ OS.RedrawWindow (handle, null, 0, flags);
+}
+
+/**
+ * Sets the receiver's size and location in points to the rectangular
+ * area specified by the arguments. The x
and
+ * y
arguments are relative to the receiver's
+ * parent (or its display if its parent is null), unless
+ * the receiver is a shell. In this case, the x
+ * and y
arguments are relative to the display.
+ *
+ *
+ */
+public void setBounds(int x, int y, int width, int height) {
+ checkWidget ();
+ x = DPIUtil.autoScaleUp(x);
+ y = DPIUtil.autoScaleUp(y);
+ width = DPIUtil.autoScaleUp(width);
+ height = DPIUtil.autoScaleUp(height);
+ setBoundsInPixels(x, y, width, height);
+}
+
+void setBoundsInPixels (int x, int y, int width, int height) {
+ int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
+ setBoundsInPixels (x, y, Math.max (0, width), Math.max (0, height), flags);
+}
+
+void setBoundsInPixels (int x, int y, int width, int height, int flags) {
+ setBoundsInPixels (x, y, width, height, flags, true);
+}
+
+void setBoundsInPixels (int x, int y, int width, int height, int flags, boolean defer) {
+ if (findImageControl () != null) {
+ if (backgroundImage == null) flags |= OS.SWP_NOCOPYBITS;
+ } else {
+ if (OS.GetWindow (handle, OS.GW_CHILD) == 0) {
+ if (OS.IsAppThemed ()) {
+ if (findThemeControl () != null) flags |= OS.SWP_NOCOPYBITS;
+ }
+ }
+ }
+ long topHandle = topHandle ();
+ if (defer && parent != null) {
+ forceResize ();
+ if (parent.lpwp != null) {
+ int index = 0;
+ WINDOWPOS [] lpwp = parent.lpwp;
+ while (index < lpwp.length) {
+ if (lpwp [index] == null) break;
+ index ++;
+ }
+ if (index == lpwp.length) {
+ WINDOWPOS [] newLpwp = new WINDOWPOS [lpwp.length + 4];
+ System.arraycopy (lpwp, 0, newLpwp, 0, lpwp.length);
+ parent.lpwp = lpwp = newLpwp;
+ }
+ WINDOWPOS wp = new WINDOWPOS ();
+ wp.hwnd = topHandle;
+ wp.x = x;
+ wp.y = y;
+ wp.cx = width;
+ wp.cy = height;
+ wp.flags = flags;
+ lpwp [index] = wp;
+ return;
+ }
+ }
+ OS.SetWindowPos (topHandle, 0, x, y, width, height, flags);
+}
+
+/**
+ * Sets the receiver's size and location in points to the rectangular
+ * area specified by the argument. The x
and
+ * y
fields of the rectangle are relative to
+ * the receiver's parent (or its display if its parent is null).
+ *
+ *
+ */
+public void setBounds (Rectangle rect) {
+ checkWidget ();
+ if (rect == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setBoundsInPixels(DPIUtil.autoScaleUp(rect));
+}
+
+void setBoundsInPixels (Rectangle rect) {
+ setBoundsInPixels (rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * If the argument is true
, causes the receiver to have
+ * all mouse events delivered to it until the method is called with
+ * false
as the argument. Note that on some platforms,
+ * a mouse button must currently be down for capture to be assigned.
+ *
+ * @param capture true
to capture the mouse, and false
to release it
+ *
+ * @exception SWTException
+ *
+ */
+public void setCapture (boolean capture) {
+ checkWidget ();
+ if (capture) {
+ OS.SetCapture (handle);
+ } else {
+ if (OS.GetCapture () == handle) {
+ OS.ReleaseCapture ();
+ }
+ }
+}
+
+void setCursor () {
+ long lParam = OS.MAKELPARAM (OS.HTCLIENT, OS.WM_MOUSEMOVE);
+ OS.SendMessage (handle, OS.WM_SETCURSOR, handle, lParam);
+}
+
+/**
+ * Sets the receiver's cursor to the cursor specified by the
+ * argument, or to the default cursor for that kind of control
+ * if the argument is null.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setCursor (Cursor cursor) {
+ checkWidget ();
+ if (cursor != null && cursor.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ this.cursor = cursor;
+ long hwndCursor = OS.GetCapture ();
+ if (hwndCursor == 0) {
+ POINT pt = new POINT ();
+ if (!OS.GetCursorPos (pt)) return;
+ long hwnd = hwndCursor = OS.WindowFromPoint (pt);
+ while (hwnd != 0 && hwnd != handle) {
+ hwnd = OS.GetParent (hwnd);
+ }
+ if (hwnd == 0) return;
+ }
+ Control control = display.getControl (hwndCursor);
+ if (control == null) control = this;
+ control.setCursor ();
+}
+
+void setDefaultFont () {
+ long hFont = display.getSystemFont ().handle;
+ OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
+}
+
+/**
+ * Sets the receiver's drag detect state. If the argument is
+ * true
, the receiver will detect drag gestures,
+ * otherwise these gestures will be ignored.
+ *
+ * @param dragDetect the new drag detect state
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.3
+ */
+public void setDragDetect (boolean dragDetect) {
+ checkWidget ();
+ if (dragDetect) {
+ state |= DRAG_DETECT;
+ } else {
+ state &= ~DRAG_DETECT;
+ }
+ enableDrag (dragDetect);
+}
+
+/**
+ * Enables the receiver if the argument is true
,
+ * and disables it otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException
+ *
+ */
+public void setEnabled (boolean enabled) {
+ checkWidget ();
+ /*
+ * Feature in Windows. If the receiver has focus, disabling
+ * the receiver causes no window to have focus. The fix is
+ * to assign focus to the first ancestor window that takes
+ * focus. If no window will take focus, set focus to the
+ * desktop.
+ */
+ Control control = null;
+ boolean fixFocus = false;
+ if (!enabled) {
+ if (display.focusEvent != SWT.FocusOut) {
+ control = display.getFocusControl ();
+ fixFocus = isFocusAncestor (control);
+ }
+ }
+ enableWidget (enabled);
+ if (fixFocus) fixFocus (control);
+}
+
+/**
+ * Causes the receiver to have the keyboard focus,
+ * such that all keyboard events will be delivered to it. Focus
+ * reassignment will respect applicable platform constraints.
+ *
+ * @return true
if the control got focus, and false
if it was unable to.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #forceFocus
+ */
+public boolean setFocus () {
+ checkWidget ();
+ if ((style & SWT.NO_FOCUS) != 0) return false;
+ return forceFocus ();
+}
+
+/**
+ * Sets the font that the receiver will use to paint textual information
+ * to the font specified by the argument, or to the default font for that
+ * kind of control if the argument is null.
+ *
+ * @param font the new font (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setFont (Font font) {
+ checkWidget ();
+ long hFont = 0;
+ if (font != null) {
+ if (font.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ hFont = font.handle;
+ }
+ this.font = font;
+ if (hFont == 0) hFont = defaultFont ();
+ OS.SendMessage (handle, OS.WM_SETFONT, hFont, 1);
+}
+
+/**
+ * Sets the receiver's foreground color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setForeground (Color color) {
+ checkWidget ();
+ int pixel = -1;
+ if (color != null) {
+ if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ pixel = color.handle;
+ }
+ if (pixel == foreground) return;
+ foreground = pixel;
+ setForegroundPixel (pixel);
+}
+
+void setForegroundPixel (int pixel) {
+ OS.InvalidateRect (handle, null, true);
+}
+
+/**
+ * Sets the layout data associated with the receiver to the argument.
+ *
+ * @param layoutData the new layout data for the receiver.
+ *
+ * @exception SWTException
+ *
+ */
+public void setLayoutData (Object layoutData) {
+ checkWidget ();
+ this.layoutData = layoutData;
+}
+
+/**
+ * Sets the receiver's location to the point specified by
+ * the arguments which are relative to the receiver's
+ * parent (or its display if its parent is null), unless
+ * the receiver is a shell. In this case, the point is
+ * relative to the display.
+ *
+ * @param x the new x coordinate for the receiver
+ * @param y the new y coordinate for the receiver
+ *
+ * @exception SWTException
+ *
+ */
+public void setLocation (int x, int y) {
+ checkWidget ();
+ x = DPIUtil.autoScaleUp(x);
+ y = DPIUtil.autoScaleUp(y);
+ setLocationInPixels(x, y);
+}
+
+void setLocationInPixels (int x, int y) {
+ int flags = OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE | OS.SWP_DRAWFRAME;
+ setBoundsInPixels (x, y, 0, 0, flags);
+}
+
+/**
+ * Sets the receiver's location to the point specified by
+ * the arguments which are relative to the receiver's
+ * parent (or its display if its parent is null), unless
+ * the receiver is a shell. In this case, the point is
+ * relative to the display.
+ *
+ * @param location the new location for the receiver
+ *
+ * @exception SWTException
+ *
+ */
+public void setLocation (Point location) {
+ checkWidget ();
+ if (location == null) error (SWT.ERROR_NULL_ARGUMENT);
+ location = DPIUtil.autoScaleUp(location);
+ setLocationInPixels(location.x, location.y);
+}
+
+/**
+ * Sets the receiver's pop up menu to the argument.
+ * All controls may optionally have a pop up
+ * menu that is displayed when the user requests one for
+ * the control. The sequence of key strokes, button presses
+ * and/or button releases that are used to request a pop up
+ * menu is platform specific.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setMenu (Menu menu) {
+ checkWidget ();
+ if (menu != null) {
+ if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((menu.style & SWT.POP_UP) == 0) {
+ error (SWT.ERROR_MENU_NOT_POP_UP);
+ }
+ if (menu.parent != menuShell ()) {
+ error (SWT.ERROR_INVALID_PARENT);
+ }
+ }
+ this.menu = menu;
+}
+
+/**
+ * Sets the orientation of the receiver, which must be one
+ * of the constants SWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
+ *
+ *
+ *
+ * @since 3.7
+ */
+public void setOrientation (int orientation) {
+ checkWidget ();
+ int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT;
+ if ((orientation & flags) == 0 || (orientation & flags) == flags) return;
+ style &= ~SWT.MIRRORED;
+ style &= ~flags;
+ style |= orientation & flags;
+ style &= ~SWT.FLIP_TEXT_DIRECTION;
+ updateOrientation ();
+ checkMirrored ();
+}
+
+boolean setRadioFocus (boolean tabbing) {
+ return false;
+}
+
+boolean setRadioSelection (boolean value) {
+ return false;
+}
+
+/**
+ * If the argument is false
, causes subsequent drawing
+ * operations in the receiver to be ignored. No drawing of any kind
+ * can occur in the receiver until the flag is set to true.
+ * Graphics operations that occurred while the flag was
+ * false
are lost. When the flag is set to true
,
+ * the entire widget is marked as needing to be redrawn. Nested calls
+ * to this method are stacked.
+ *
+ *
+ *
+ * @see #redraw(int, int, int, int, boolean)
+ * @see #update()
+ */
+public void setRedraw (boolean redraw) {
+ checkWidget ();
+ /*
+ * Feature in Windows. When WM_SETREDRAW is used to turn
+ * off drawing in a widget, it clears the WS_VISIBLE bits
+ * and then sets them when redraw is turned back on. This
+ * means that WM_SETREDRAW will make a widget unexpectedly
+ * visible. The fix is to track the visibility state while
+ * drawing is turned off and restore it when drawing is
+ * turned back on.
+ */
+ if (drawCount == 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.WS_VISIBLE) == 0) state |= HIDDEN;
+ }
+ if (redraw) {
+ if (--drawCount == 0) {
+ long topHandle = topHandle ();
+ OS.SendMessage (topHandle, OS.WM_SETREDRAW, 1, 0);
+ if (handle != topHandle) OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
+ if ((state & HIDDEN) != 0) {
+ state &= ~HIDDEN;
+ OS.ShowWindow (topHandle, OS.SW_HIDE);
+ if (handle != topHandle) OS.ShowWindow (handle, OS.SW_HIDE);
+ } else {
+ int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (topHandle, null, 0, flags);
+ }
+ }
+ } else {
+ if (drawCount++ == 0) {
+ long topHandle = topHandle ();
+ OS.SendMessage (topHandle, OS.WM_SETREDRAW, 0, 0);
+ if (handle != topHandle) OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
+ }
+ }
+}
+
+/**
+ * Sets the shape of the control to the region specified
+ * by the argument. When the argument is null, the
+ * default shape of the control is restored.
+ *
+ * @param region the region that defines the shape of the control (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public void setRegion (Region region) {
+ checkWidget ();
+ if (region != null && region.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ long hRegion = 0;
+ if (region != null) {
+ hRegion = OS.CreateRectRgn (0, 0, 0, 0);
+ OS.CombineRgn (hRegion, region.handle, hRegion, OS.RGN_OR);
+ }
+ OS.SetWindowRgn (handle, hRegion, true);
+ this.region = region;
+}
+
+/**
+ * Sets the receiver's size to the point specified by the arguments.
+ *
+ *
+ */
+public void setSize (int width, int height) {
+ checkWidget ();
+ width = DPIUtil.autoScaleUp(width);
+ height = DPIUtil.autoScaleUp(height);
+ setSizeInPixels(width, height);
+}
+
+void setSizeInPixels (int width, int height) {
+ int flags = OS.SWP_NOMOVE | OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
+ setBoundsInPixels (0, 0, Math.max (0, width), Math.max (0, height), flags);
+}
+
+/**
+ * Sets the receiver's size to the point specified by the argument.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setSize (Point size) {
+ checkWidget ();
+ if (size == null) error (SWT.ERROR_NULL_ARGUMENT);
+ size = DPIUtil.autoScaleUp(size);
+ setSizeInPixels(size.x, size.y);
+}
+
+@Override
+boolean setTabItemFocus () {
+ if (!isShowing ()) return false;
+ return forceFocus ();
+}
+
+/**
+ * Sets the base text direction (a.k.a. "paragraph direction") of the receiver,
+ * which must be one of the constants SWT.LEFT_TO_RIGHT
,
+ * SWT.RIGHT_TO_LEFT
, or SWT.AUTO_TEXT_DIRECTION
.
+ * setOrientation
would override this value with the text direction
+ * that is consistent with the new orientation.
+ *
+ *
+ *
+ * @see SWT#LEFT_TO_RIGHT
+ * @see SWT#RIGHT_TO_LEFT
+ * @see SWT#AUTO_TEXT_DIRECTION
+ * @see SWT#FLIP_TEXT_DIRECTION
+ *
+ * @since 3.102
+ */
+public void setTextDirection(int textDirection) {
+ checkWidget ();
+ textDirection &= (SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT);
+ updateTextDirection (textDirection);
+ if (textDirection == AUTO_TEXT_DIRECTION) {
+ state |= HAS_AUTO_DIRECTION;
+ } else {
+ state &= ~HAS_AUTO_DIRECTION;
+ }
+}
+
+/**
+ * Sets the receiver's tool tip text to the argument, which
+ * may be null indicating that the default tool tip for the
+ * control will be shown. For a control that has a default
+ * tool tip, such as the Tree control on Windows, setting
+ * the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ *
+ *
+ */
+public void setToolTipText (String string) {
+ checkWidget ();
+ toolTipText = string;
+ setToolTipText (getShell (), string);
+}
+
+void setToolTipText (Shell shell, String string) {
+ shell.setToolTipText (handle, string);
+}
+
+/**
+ * Sets whether this control should send touch events (by default controls do not).
+ * Setting this to false
causes the receiver to send gesture events
+ * instead. No exception is thrown if a touch-based input device is not
+ * detected (this can be determined with Display#getTouchEnabled()
).
+ *
+ * @param enabled the new touch-enabled state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Display#getTouchEnabled
+ *
+ * @since 3.7
+ */
+public void setTouchEnabled(boolean enabled) {
+ checkWidget();
+ if (enabled) {
+ OS.RegisterTouchWindow(handle, 0);
+ } else {
+ OS.UnregisterTouchWindow(handle);
+ }
+}
+
+/**
+ * Marks the receiver as visible if the argument is true
,
+ * and marks it invisible otherwise.
+ *
+ *
+ */
+public void setVisible (boolean visible) {
+ checkWidget ();
+ if (!getDrawing()) {
+ if (((state & HIDDEN) == 0) == visible) return;
+ } else {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if (((bits & OS.WS_VISIBLE) != 0) == visible) return;
+ }
+ if (visible) {
+ sendEvent (SWT.Show);
+ if (isDisposed ()) return;
+ }
+
+ /*
+ * Feature in Windows. If the receiver has focus, hiding
+ * the receiver causes no window to have focus. The fix is
+ * to assign focus to the first ancestor window that takes
+ * focus. If no window will take focus, set focus to the
+ * desktop.
+ */
+ Control control = null;
+ boolean fixFocus = false;
+ if (!visible) {
+ if (display.focusEvent != SWT.FocusOut) {
+ control = display.getFocusControl ();
+ fixFocus = isFocusAncestor (control);
+ }
+ }
+ if (!getDrawing()) {
+ state = visible ? state & ~HIDDEN : state | HIDDEN;
+ } else {
+ showWidget (visible);
+ if (isDisposed ()) return;
+ }
+ if (!visible) {
+ sendEvent (SWT.Hide);
+ if (isDisposed ()) return;
+ }
+ if (fixFocus) fixFocus (control);
+}
+
+void sort (int [] items) {
+ /* Shell Sort from K&R, pg 108 */
+ int length = items.length;
+ for (int gap=length/2; gap>0; gap/=2) {
+ for (int i=gap; i
+ *
+ *
+ * @since 2.1
+ */
+public Point toControl (int x, int y) {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(toControlInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y)));
+}
+
+Point toControlInPixels (int x, int y) {
+ POINT pt = new POINT ();
+ pt.x = x; pt.y = y;
+ OS.ScreenToClient (handle, pt);
+ return new Point (pt.x, pt.y);
+}
+
+/**
+ * Returns a point which is the result of converting the
+ * argument, which is specified in display relative coordinates,
+ * to coordinates relative to the receiver.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public Point toControl (Point point) {
+ checkWidget ();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ point = DPIUtil.autoScaleUp(point);
+ return DPIUtil.autoScaleDown(toControlInPixels(point.x, point.y));
+}
+
+/**
+ * Returns a point which is the result of converting the
+ * argument, which is specified in coordinates relative to
+ * the receiver, to display relative coordinates.
+ *
+ *
+ *
+ * @since 2.1
+ */
+public Point toDisplay (int x, int y) {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(toDisplayInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y)));
+}
+
+Point toDisplayInPixels (int x, int y) {
+ POINT pt = new POINT ();
+ pt.x = x; pt.y = y;
+ OS.ClientToScreen (handle, pt);
+ return new Point (pt.x, pt.y);
+}
+
+/**
+ * Returns a point which is the result of converting the
+ * argument, which is specified in coordinates relative to
+ * the receiver, to display relative coordinates.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public Point toDisplay (Point point) {
+ checkWidget ();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ point = DPIUtil.autoScaleUp(point);
+ return DPIUtil.autoScaleDown(toDisplayInPixels(point.x, point.y));
+}
+
+long topHandle () {
+ return handle;
+}
+
+boolean translateAccelerator (MSG msg) {
+ return menuShell ().translateAccelerator (msg);
+}
+
+boolean translateMnemonic (Event event, Control control) {
+ if (control == this) return false;
+ if (!isVisible () || !isEnabled ()) return false;
+ event.doit = mnemonicMatch (event.character);
+ return traverse (event);
+}
+
+boolean translateMnemonic (MSG msg) {
+ if (msg.wParam < 0x20) return false;
+ long hwnd = msg.hwnd;
+ if (OS.GetKeyState (OS.VK_MENU) >= 0) {
+ long code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
+ if ((code & OS.DLGC_WANTALLKEYS) != 0) return false;
+ if ((code & OS.DLGC_BUTTON) == 0) return false;
+ }
+ Decorations shell = menuShell ();
+ if (shell.isVisible () && shell.isEnabled ()) {
+ display.lastAscii = (int)msg.wParam;
+ display.lastNull = display.lastDead = false;
+ Event event = new Event ();
+ event.detail = SWT.TRAVERSE_MNEMONIC;
+ if (setKeyState (event, SWT.Traverse, msg.wParam, msg.lParam)) {
+ return translateMnemonic (event, null) || shell.translateMnemonic (event, this);
+ }
+ }
+ return false;
+}
+
+boolean translateTraversal (MSG msg) {
+ long hwnd = msg.hwnd;
+ int key = (int)msg.wParam;
+ if (key == OS.VK_MENU) {
+ if ((msg.lParam & 0x40000000) == 0) {
+ OS.SendMessage (hwnd, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
+ }
+ return false;
+ }
+ int detail = SWT.TRAVERSE_NONE;
+ boolean doit = true, all = false;
+ boolean lastVirtual = false;
+ int lastKey = key, lastAscii = 0;
+ switch (key) {
+ case OS.VK_ESCAPE: {
+ all = true;
+ lastAscii = 27;
+ long code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
+ if ((code & OS.DLGC_WANTALLKEYS) != 0) {
+ /*
+ * Use DLGC_HASSETSEL to determine that the control
+ * is a text widget. A text widget normally wants
+ * all keys except VK_ESCAPE. If this bit is not
+ * set, then assume the control wants all keys,
+ * including VK_ESCAPE.
+ */
+ if ((code & OS.DLGC_HASSETSEL) == 0) doit = false;
+ }
+ detail = SWT.TRAVERSE_ESCAPE;
+ break;
+ }
+ case OS.VK_RETURN: {
+ all = true;
+ lastAscii = '\r';
+ long code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
+ if ((code & OS.DLGC_WANTALLKEYS) != 0) doit = false;
+ detail = SWT.TRAVERSE_RETURN;
+ break;
+ }
+ case OS.VK_TAB: {
+ lastAscii = '\t';
+ boolean next = OS.GetKeyState (OS.VK_SHIFT) >= 0;
+ long code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
+ if ((code & (OS.DLGC_WANTTAB | OS.DLGC_WANTALLKEYS)) != 0) {
+ /*
+ * Use DLGC_HASSETSEL to determine that the control is a
+ * text widget. If the control is a text widget, then
+ * Ctrl+Tab and Shift+Tab should traverse out of the widget.
+ * If the control is not a text widget, the correct behavior
+ * is to give every character, including Tab, Ctrl+Tab and
+ * Shift+Tab to the control.
+ */
+ if ((code & OS.DLGC_HASSETSEL) != 0) {
+ if (next && OS.GetKeyState (OS.VK_CONTROL) >= 0) {
+ doit = false;
+ }
+ } else {
+ doit = false;
+ }
+ }
+ detail = next ? SWT.TRAVERSE_TAB_NEXT : SWT.TRAVERSE_TAB_PREVIOUS;
+ break;
+ }
+ case OS.VK_UP:
+ case OS.VK_LEFT:
+ case OS.VK_DOWN:
+ case OS.VK_RIGHT: {
+ lastVirtual = true;
+ long code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
+ if ((code & (OS.DLGC_WANTARROWS /*| OS.DLGC_WANTALLKEYS*/)) != 0) doit = false;
+ boolean next = key == OS.VK_DOWN || key == OS.VK_RIGHT;
+ if (parent != null && (parent.style & SWT.MIRRORED) != 0) {
+ if (key == OS.VK_LEFT || key == OS.VK_RIGHT) next = !next;
+ }
+ detail = next ? SWT.TRAVERSE_ARROW_NEXT : SWT.TRAVERSE_ARROW_PREVIOUS;
+ break;
+ }
+ case OS.VK_PRIOR:
+ case OS.VK_NEXT: {
+ all = true;
+ lastVirtual = true;
+ if (OS.GetKeyState (OS.VK_CONTROL) >= 0) return false;
+ long code = OS.SendMessage (hwnd, OS.WM_GETDLGCODE, 0, 0);
+ if ((code & OS.DLGC_WANTALLKEYS) != 0) {
+ /*
+ * Use DLGC_HASSETSEL to determine that the control is a
+ * text widget. If the control is a text widget, then
+ * Ctrl+PgUp and Ctrl+PgDn should traverse out of the widget.
+ */
+ if ((code & OS.DLGC_HASSETSEL) == 0) doit = false;
+ }
+ detail = key == OS.VK_PRIOR ? SWT.TRAVERSE_PAGE_PREVIOUS : SWT.TRAVERSE_PAGE_NEXT;
+ break;
+ }
+ default:
+ return false;
+ }
+ Event event = new Event ();
+ event.doit = doit;
+ event.detail = detail;
+ display.lastKey = lastKey;
+ display.lastAscii = lastAscii;
+ display.lastVirtual = lastVirtual;
+ display.lastNull = display.lastDead = false;
+ if (!setKeyState (event, SWT.Traverse, msg.wParam, msg.lParam)) return false;
+ Shell shell = getShell ();
+ Control control = this;
+ do {
+ if (control.traverse (event)) {
+ OS.SendMessage (hwnd, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
+ return true;
+ }
+ if (!event.doit && control.hooks (SWT.Traverse)) return false;
+ if (control == shell) return false;
+ control = control.parent;
+ } while (all && control != null);
+ return false;
+}
+
+boolean traverse (Event event) {
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the traverse
+ * event. If this happens, return true to stop further
+ * event processing.
+ */
+ sendEvent (SWT.Traverse, event);
+ if (isDisposed ()) return true;
+ if (!event.doit) return false;
+ switch (event.detail) {
+ case SWT.TRAVERSE_NONE: return true;
+ case SWT.TRAVERSE_ESCAPE: return traverseEscape ();
+ case SWT.TRAVERSE_RETURN: return traverseReturn ();
+ case SWT.TRAVERSE_TAB_NEXT: return traverseGroup (true);
+ case SWT.TRAVERSE_TAB_PREVIOUS: return traverseGroup (false);
+ case SWT.TRAVERSE_ARROW_NEXT: return traverseItem (true);
+ case SWT.TRAVERSE_ARROW_PREVIOUS: return traverseItem (false);
+ case SWT.TRAVERSE_MNEMONIC: return traverseMnemonic (event.character);
+ case SWT.TRAVERSE_PAGE_NEXT: return traversePage (true);
+ case SWT.TRAVERSE_PAGE_PREVIOUS: return traversePage (false);
+ }
+ return false;
+}
+
+/**
+ * Based on the argument, perform one of the expected platform
+ * traversal action. The argument should be one of the constants:
+ * SWT.TRAVERSE_ESCAPE
, SWT.TRAVERSE_RETURN
,
+ * SWT.TRAVERSE_TAB_NEXT
, SWT.TRAVERSE_TAB_PREVIOUS
,
+ * SWT.TRAVERSE_ARROW_NEXT
, SWT.TRAVERSE_ARROW_PREVIOUS
,
+ * SWT.TRAVERSE_PAGE_NEXT
and SWT.TRAVERSE_PAGE_PREVIOUS
.
+ *
+ * @param traversal the type of traversal
+ * @return true if the traversal succeeded
+ *
+ * @exception SWTException
+ *
+ */
+public boolean traverse (int traversal) {
+ checkWidget ();
+ Event event = new Event ();
+ event.doit = true;
+ event.detail = traversal;
+ return traverse (event);
+}
+
+/**
+ * Performs a platform traversal action corresponding to a KeyDown
event.
+ *
+ * SWT.TRAVERSE_NONE
, SWT.TRAVERSE_MNEMONIC
,
+ * SWT.TRAVERSE_ESCAPE
, SWT.TRAVERSE_RETURN
,
+ * SWT.TRAVERSE_TAB_NEXT
, SWT.TRAVERSE_TAB_PREVIOUS
,
+ * SWT.TRAVERSE_ARROW_NEXT
, SWT.TRAVERSE_ARROW_PREVIOUS
,
+ * SWT.TRAVERSE_PAGE_NEXT
and SWT.TRAVERSE_PAGE_PREVIOUS
.
+ * If traversal
is SWT.TRAVERSE_NONE
then the Traverse
+ * event is created with standard values based on the KeyDown event. If
+ * traversal
is one of the other traversal constants then the Traverse
+ * event is created with this detail, and its doit
is taken from the
+ * KeyDown event.
+ * SWT.TRAVERSE_NONE
to compute
+ * this from event
+ * @param event the KeyDown event
+ *
+ * @return true
if the traversal succeeded
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.6
+ */
+public boolean traverse (int traversal, Event event) {
+ checkWidget ();
+ if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return traverse (traversal, event.character, event.keyCode, event.keyLocation, event.stateMask, event.doit);
+}
+
+/**
+ * Performs a platform traversal action corresponding to a KeyDown
event.
+ *
+ * SWT.TRAVERSE_NONE
, SWT.TRAVERSE_MNEMONIC
,
+ * SWT.TRAVERSE_ESCAPE
, SWT.TRAVERSE_RETURN
,
+ * SWT.TRAVERSE_TAB_NEXT
, SWT.TRAVERSE_TAB_PREVIOUS
,
+ * SWT.TRAVERSE_ARROW_NEXT
, SWT.TRAVERSE_ARROW_PREVIOUS
,
+ * SWT.TRAVERSE_PAGE_NEXT
and SWT.TRAVERSE_PAGE_PREVIOUS
.
+ * If traversal
is SWT.TRAVERSE_NONE
then the Traverse
+ * event is created with standard values based on the KeyDown event. If
+ * traversal
is one of the other traversal constants then the Traverse
+ * event is created with this detail, and its doit
is taken from the
+ * KeyDown event.
+ * SWT.TRAVERSE_NONE
to compute
+ * this from event
+ * @param event the KeyDown event
+ *
+ * @return true
if the traversal succeeded
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.6
+ */
+public boolean traverse (int traversal, KeyEvent event) {
+ checkWidget ();
+ if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return traverse (traversal, event.character, event.keyCode, event.keyLocation, event.stateMask, event.doit);
+}
+
+boolean traverse (int traversal, char character, int keyCode, int keyLocation, int stateMask, boolean doit) {
+ if (traversal == SWT.TRAVERSE_NONE) {
+ switch (keyCode) {
+ case SWT.ESC: {
+ traversal = SWT.TRAVERSE_ESCAPE;
+ doit = true;
+ break;
+ }
+ case SWT.CR: {
+ traversal = SWT.TRAVERSE_RETURN;
+ doit = true;
+ break;
+ }
+ case SWT.ARROW_DOWN:
+ case SWT.ARROW_RIGHT: {
+ traversal = SWT.TRAVERSE_ARROW_NEXT;
+ doit = false;
+ break;
+ }
+ case SWT.ARROW_UP:
+ case SWT.ARROW_LEFT: {
+ traversal = SWT.TRAVERSE_ARROW_PREVIOUS;
+ doit = false;
+ break;
+ }
+ case SWT.TAB: {
+ traversal = (stateMask & SWT.SHIFT) != 0 ? SWT.TRAVERSE_TAB_PREVIOUS : SWT.TRAVERSE_TAB_NEXT;
+ doit = true;
+ break;
+ }
+ case SWT.PAGE_DOWN: {
+ if ((stateMask & SWT.CTRL) != 0) {
+ traversal = SWT.TRAVERSE_PAGE_NEXT;
+ doit = true;
+ }
+ break;
+ }
+ case SWT.PAGE_UP: {
+ if ((stateMask & SWT.CTRL) != 0) {
+ traversal = SWT.TRAVERSE_PAGE_PREVIOUS;
+ doit = true;
+ }
+ break;
+ }
+ default: {
+ if (character != 0 && (stateMask & (SWT.ALT | SWT.CTRL)) == SWT.ALT) {
+ traversal = SWT.TRAVERSE_MNEMONIC;
+ doit = true;
+ }
+ break;
+ }
+ }
+ }
+
+ Event event = new Event ();
+ event.character = character;
+ event.detail = traversal;
+ event.doit = doit;
+ event.keyCode = keyCode;
+ event.keyLocation = keyLocation;
+ event.stateMask = stateMask;
+
+ Shell shell = getShell ();
+ boolean all = false;
+ switch (traversal) {
+ case SWT.TRAVERSE_ESCAPE:
+ case SWT.TRAVERSE_RETURN:
+ case SWT.TRAVERSE_PAGE_NEXT:
+ case SWT.TRAVERSE_PAGE_PREVIOUS: {
+ all = true;
+ // FALL THROUGH
+ }
+ case SWT.TRAVERSE_ARROW_NEXT:
+ case SWT.TRAVERSE_ARROW_PREVIOUS:
+ case SWT.TRAVERSE_TAB_NEXT:
+ case SWT.TRAVERSE_TAB_PREVIOUS: {
+ /* traversal is a valid traversal action */
+ break;
+ }
+ case SWT.TRAVERSE_MNEMONIC: {
+ return translateMnemonic (event, null) || shell.translateMnemonic (event, this);
+ }
+ default: {
+ /* traversal is not a valid traversal action */
+ return false;
+ }
+ }
+
+ Control control = this;
+ do {
+ if (control.traverse (event)) {
+ OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
+ return true;
+ }
+ if (!event.doit && control.hooks (SWT.Traverse)) return false;
+ if (control == shell) return false;
+ control = control.parent;
+ } while (all && control != null);
+ return false;
+}
+
+boolean traverseEscape () {
+ return false;
+}
+
+boolean traverseGroup (boolean next) {
+ Control root = computeTabRoot ();
+ Widget group = computeTabGroup ();
+ Widget [] list = root.computeTabList ();
+ int length = list.length;
+ int index = 0;
+ while (index < length) {
+ if (list [index] == group) break;
+ index++;
+ }
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in focus in
+ * or out events. Ensure that a disposed widget is
+ * not accessed.
+ */
+ if (index == length) return false;
+ int start = index, offset = (next) ? 1 : -1;
+ while ((index = ((index + offset + length) % length)) != start) {
+ Widget widget = list [index];
+ if (!widget.isDisposed () && widget.setTabGroupFocus ()) {
+ return true;
+ }
+ }
+ if (group.isDisposed ()) return false;
+ return group.setTabGroupFocus ();
+}
+
+boolean traverseItem (boolean next) {
+ Control [] children = parent._getChildren ();
+ int length = children.length;
+ int index = 0;
+ while (index < length) {
+ if (children [index] == this) break;
+ index++;
+ }
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in focus in
+ * or out events. Ensure that a disposed widget is
+ * not accessed.
+ */
+ if (index == length) return false;
+ int start = index, offset = (next) ? 1 : -1;
+ while ((index = (index + offset + length) % length) != start) {
+ Control child = children [index];
+ if (!child.isDisposed () && child.isTabItem ()) {
+ if (child.setTabItemFocus ()) return true;
+ }
+ }
+ return false;
+}
+
+boolean traverseMnemonic (char key) {
+ if (mnemonicHit (key)) {
+ OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
+ return true;
+ }
+ return false;
+}
+
+boolean traversePage (boolean next) {
+ return false;
+}
+
+boolean traverseReturn () {
+ return false;
+}
+
+void unsubclass () {
+ long newProc = windowProc ();
+ long oldProc = display.windowProc;
+ if (oldProc == newProc) return;
+ OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, newProc);
+}
+
+/**
+ * Forces all outstanding paint requests for the widget
+ * to be processed before this method returns. If there
+ * are no outstanding paint request, this method does
+ * nothing.
+ *
+ *
+ *
+ * @see #redraw()
+ * @see #redraw(int, int, int, int, boolean)
+ * @see PaintListener
+ * @see SWT#Paint
+ */
+public void update () {
+ checkWidget ();
+ update (false);
+}
+
+void update (boolean all) {
+// checkWidget ();
+ int flags = OS.RDW_UPDATENOW;
+ if (all) flags |= OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (handle, null, 0, flags);
+}
+
+void updateBackgroundColor () {
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ setBackgroundPixel (control.background);
+}
+
+void updateBackgroundImage () {
+ Control control = findBackgroundControl ();
+ Image image = control != null ? control.backgroundImage : backgroundImage;
+ setBackgroundImage (image != null ? image.handle : 0);
+}
+
+void updateBackgroundMode () {
+ int oldState = state & PARENT_BACKGROUND;
+ checkBackground ();
+ if (oldState != (state & PARENT_BACKGROUND)) {
+ setBackground ();
+ }
+}
+
+void updateFont (Font oldFont, Font newFont) {
+ if (getFont ().equals (oldFont)) setFont (newFont);
+}
+
+void updateLayout (boolean resize, boolean all) {
+ /* Do nothing */
+}
+
+void updateOrientation () {
+ int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ bits |= OS.WS_EX_LAYOUTRTL;
+ } else {
+ bits &= ~OS.WS_EX_LAYOUTRTL;
+ }
+ bits &= ~OS.WS_EX_RTLREADING;
+ OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
+ OS.InvalidateRect (handle, null, true);
+}
+
+boolean updateTextDirection (int textDirection) {
+ if (textDirection == AUTO_TEXT_DIRECTION) {
+ textDirection = resolveTextDirection();
+ state |= HAS_AUTO_DIRECTION;
+ } else {
+ state &= ~HAS_AUTO_DIRECTION;
+ }
+ if (textDirection == 0) return false;
+ int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ /*
+ * OS.WS_EX_RTLREADING means that the text direction is opposite to the
+ * natural one for the current layout. So text direction would be RTL when
+ * one and only one of the flags OS.WS_EX_LAYOUTRTL | OS.WS_EX_RTLREADING is
+ * on.
+ */
+ int flags = OS.WS_EX_LAYOUTRTL | OS.WS_EX_RTLREADING;
+ boolean oldRtl = ((bits & flags) != 0 && (bits & flags) != flags);
+ boolean newRtl = textDirection == SWT.RIGHT_TO_LEFT;
+ if (newRtl == oldRtl) return false;
+ oldRtl = (bits & OS.WS_EX_LAYOUTRTL) != 0;
+ if (newRtl != oldRtl) {
+ bits |= OS.WS_EX_RTLREADING;
+ style |= SWT.FLIP_TEXT_DIRECTION;
+ } else {
+ bits &= ~OS.WS_EX_RTLREADING;
+ style &= ~SWT.FLIP_TEXT_DIRECTION;
+ }
+ OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
+ OS.InvalidateRect (handle, null, true);
+ return true;
+}
+
+CREATESTRUCT widgetCreateStruct () {
+ return null;
+}
+
+int widgetExtStyle () {
+ int bits = 0;
+ if ((style & SWT.BORDER) != 0) bits |= OS.WS_EX_CLIENTEDGE;
+// if ((style & SWT.BORDER) != 0) {
+// if ((style & SWT.FLAT) == 0) bits |= OS.WS_EX_CLIENTEDGE;
+// }
+ bits |= OS.WS_EX_NOINHERITLAYOUT;
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.WS_EX_LAYOUTRTL;
+ if ((style & SWT.FLIP_TEXT_DIRECTION) != 0) bits |= OS.WS_EX_RTLREADING;
+ return bits;
+}
+
+long widgetParent () {
+ return parent.handle;
+}
+
+int widgetStyle () {
+ /* Force clipping of siblings by setting WS_CLIPSIBLINGS */
+ int bits = OS.WS_CHILD | OS.WS_VISIBLE | OS.WS_CLIPSIBLINGS;
+// if ((style & SWT.BORDER) != 0) {
+// if ((style & SWT.FLAT) != 0) bits |= OS.WS_BORDER;
+// }
+ return bits;
+
+ /*
+ * This code is intentionally commented. When clipping
+ * of both siblings and children is not enforced, it is
+ * possible for application code to draw outside of the
+ * control.
+ */
+// int bits = OS.WS_CHILD | OS.WS_VISIBLE;
+// if ((style & SWT.CLIP_SIBLINGS) != 0) bits |= OS.WS_CLIPSIBLINGS;
+// if ((style & SWT.CLIP_CHILDREN) != 0) bits |= OS.WS_CLIPCHILDREN;
+// return bits;
+}
+
+/**
+ * Changes the parent of the widget to be the one provided.
+ * Returns true
if the parent is successfully changed.
+ *
+ * @param parent the new parent for the control.
+ * @return true
if the parent is changed and false
otherwise.
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException null
+ *
+ */
+public boolean setParent (Composite parent) {
+ checkWidget ();
+ if (parent == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (parent.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.parent == parent) return true;
+ if (!isReparentable ()) return false;
+ releaseParent ();
+ Shell newShell = parent.getShell (), oldShell = getShell ();
+ Decorations newDecorations = parent.menuShell (), oldDecorations = menuShell ();
+ if (oldShell != newShell || oldDecorations != newDecorations) {
+ Menu [] menus = oldShell.findMenus (this);
+ fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus);
+ }
+ long topHandle = topHandle ();
+ if (OS.SetParent (topHandle, parent.handle) == 0) return false;
+ this.parent = parent;
+ int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (topHandle, OS.HWND_BOTTOM, 0, 0, 0, 0, flags);
+ reskin (SWT.ALL);
+ return true;
+}
+
+abstract TCHAR windowClass ();
+
+abstract long windowProc ();
+
+long windowProc (long hwnd, int msg, long wParam, long lParam) {
+ Display display = this.display;
+ LRESULT result = null;
+ switch (msg) {
+ case OS.WM_ACTIVATE: result = WM_ACTIVATE (wParam, lParam); break;
+ case OS.WM_CAPTURECHANGED: result = WM_CAPTURECHANGED (wParam, lParam); break;
+ case OS.WM_CHANGEUISTATE: result = WM_CHANGEUISTATE (wParam, lParam); break;
+ case OS.WM_CHAR: result = WM_CHAR (wParam, lParam); break;
+ case OS.WM_CLEAR: result = WM_CLEAR (wParam, lParam); break;
+ case OS.WM_CLOSE: result = WM_CLOSE (wParam, lParam); break;
+ case OS.WM_COMMAND: result = WM_COMMAND (wParam, lParam); break;
+ case OS.WM_CONTEXTMENU: result = WM_CONTEXTMENU (wParam, lParam); break;
+ case OS.WM_CTLCOLORBTN:
+ case OS.WM_CTLCOLORDLG:
+ case OS.WM_CTLCOLOREDIT:
+ case OS.WM_CTLCOLORLISTBOX:
+ case OS.WM_CTLCOLORMSGBOX:
+ case OS.WM_CTLCOLORSCROLLBAR:
+ case OS.WM_CTLCOLORSTATIC: result = WM_CTLCOLOR (wParam, lParam); break;
+ case OS.WM_CUT: result = WM_CUT (wParam, lParam); break;
+ case OS.WM_DESTROY: result = WM_DESTROY (wParam, lParam); break;
+ case OS.WM_DRAWITEM: result = WM_DRAWITEM (wParam, lParam); break;
+ case OS.WM_ENDSESSION: result = WM_ENDSESSION (wParam, lParam); break;
+ case OS.WM_ENTERIDLE: result = WM_ENTERIDLE (wParam, lParam); break;
+ case OS.WM_ERASEBKGND: result = WM_ERASEBKGND (wParam, lParam); break;
+ case OS.WM_GESTURE: result = WM_GESTURE (wParam, lParam); break;
+ case OS.WM_GETDLGCODE: result = WM_GETDLGCODE (wParam, lParam); break;
+ case OS.WM_GETFONT: result = WM_GETFONT (wParam, lParam); break;
+ case OS.WM_GETOBJECT: result = WM_GETOBJECT (wParam, lParam); break;
+ case OS.WM_GETMINMAXINFO: result = WM_GETMINMAXINFO (wParam, lParam); break;
+ case OS.WM_HELP: result = WM_HELP (wParam, lParam); break;
+ case OS.WM_HSCROLL: result = WM_HSCROLL (wParam, lParam); break;
+ case OS.WM_IME_CHAR: result = WM_IME_CHAR (wParam, lParam); break;
+ case OS.WM_IME_COMPOSITION: result = WM_IME_COMPOSITION (wParam, lParam); break;
+ case OS.WM_IME_COMPOSITION_START: result = WM_IME_COMPOSITION_START (wParam, lParam); break;
+ case OS.WM_IME_ENDCOMPOSITION: result = WM_IME_ENDCOMPOSITION (wParam, lParam); break;
+ case OS.WM_INITMENUPOPUP: result = WM_INITMENUPOPUP (wParam, lParam); break;
+ case OS.WM_INPUTLANGCHANGE: result = WM_INPUTLANGCHANGE (wParam, lParam); break;
+ case OS.WM_HOTKEY: result = WM_HOTKEY (wParam, lParam); break;
+ case OS.WM_KEYDOWN: result = WM_KEYDOWN (wParam, lParam); break;
+ case OS.WM_KEYUP: result = WM_KEYUP (wParam, lParam); break;
+ case OS.WM_KILLFOCUS: result = WM_KILLFOCUS (wParam, lParam); break;
+ case OS.WM_LBUTTONDBLCLK: result = WM_LBUTTONDBLCLK (wParam, lParam); break;
+ case OS.WM_LBUTTONDOWN: result = WM_LBUTTONDOWN (wParam, lParam); break;
+ case OS.WM_LBUTTONUP: result = WM_LBUTTONUP (wParam, lParam); break;
+ case OS.WM_MBUTTONDBLCLK: result = WM_MBUTTONDBLCLK (wParam, lParam); break;
+ case OS.WM_MBUTTONDOWN: result = WM_MBUTTONDOWN (wParam, lParam); break;
+ case OS.WM_MBUTTONUP: result = WM_MBUTTONUP (wParam, lParam); break;
+ case OS.WM_MEASUREITEM: result = WM_MEASUREITEM (wParam, lParam); break;
+ case OS.WM_MENUCHAR: result = WM_MENUCHAR (wParam, lParam); break;
+ case OS.WM_MENUSELECT: result = WM_MENUSELECT (wParam, lParam); break;
+ case OS.WM_MOUSEACTIVATE: result = WM_MOUSEACTIVATE (wParam, lParam); break;
+ case OS.WM_MOUSEHOVER: result = WM_MOUSEHOVER (wParam, lParam); break;
+ case OS.WM_MOUSELEAVE: result = WM_MOUSELEAVE (wParam, lParam); break;
+ case OS.WM_MOUSEMOVE: result = WM_MOUSEMOVE (wParam, lParam); break;
+ case OS.WM_MOUSEWHEEL: result = WM_MOUSEWHEEL (wParam, lParam); break;
+ case OS.WM_MOUSEHWHEEL: result = WM_MOUSEHWHEEL (wParam, lParam); break;
+ case OS.WM_MOVE: result = WM_MOVE (wParam, lParam); break;
+ case OS.WM_NCACTIVATE: result = WM_NCACTIVATE (wParam, lParam); break;
+ case OS.WM_NCCALCSIZE: result = WM_NCCALCSIZE (wParam, lParam); break;
+ case OS.WM_NCHITTEST: result = WM_NCHITTEST (wParam, lParam); break;
+ case OS.WM_NCLBUTTONDOWN: result = WM_NCLBUTTONDOWN (wParam, lParam); break;
+ case OS.WM_NCPAINT: result = WM_NCPAINT (wParam, lParam); break;
+ case OS.WM_NOTIFY: result = WM_NOTIFY (wParam, lParam); break;
+ case OS.WM_PAINT: result = WM_PAINT (wParam, lParam); break;
+ case OS.WM_ENTERMENULOOP: result = WM_ENTERMENULOOP (wParam, lParam); break;
+ case OS.WM_EXITMENULOOP: result = WM_EXITMENULOOP (wParam, lParam); break;
+ case OS.WM_ENTERSIZEMOVE: result = WM_ENTERSIZEMOVE (wParam, lParam); break;
+ case OS.WM_EXITSIZEMOVE: result = WM_EXITSIZEMOVE (wParam, lParam); break;
+ case OS.WM_PARENTNOTIFY: result = WM_PARENTNOTIFY (wParam, lParam); break;
+ case OS.WM_PASTE: result = WM_PASTE (wParam, lParam); break;
+ case OS.WM_PRINT: result = WM_PRINT (wParam, lParam); break;
+ case OS.WM_PRINTCLIENT: result = WM_PRINTCLIENT (wParam, lParam); break;
+ case OS.WM_QUERYENDSESSION: result = WM_QUERYENDSESSION (wParam, lParam); break;
+ case OS.WM_QUERYOPEN: result = WM_QUERYOPEN (wParam, lParam); break;
+ case OS.WM_RBUTTONDBLCLK: result = WM_RBUTTONDBLCLK (wParam, lParam); break;
+ case OS.WM_RBUTTONDOWN: result = WM_RBUTTONDOWN (wParam, lParam); break;
+ case OS.WM_RBUTTONUP: result = WM_RBUTTONUP (wParam, lParam); break;
+ case OS.WM_SETCURSOR: result = WM_SETCURSOR (wParam, lParam); break;
+ case OS.WM_SETFOCUS: result = WM_SETFOCUS (wParam, lParam); break;
+ case OS.WM_SETFONT: result = WM_SETFONT (wParam, lParam); break;
+ case OS.WM_SETTINGCHANGE: result = WM_SETTINGCHANGE (wParam, lParam); break;
+ case OS.WM_SETREDRAW: result = WM_SETREDRAW (wParam, lParam); break;
+ case OS.WM_SHOWWINDOW: result = WM_SHOWWINDOW (wParam, lParam); break;
+ case OS.WM_SIZE: result = WM_SIZE (wParam, lParam); break;
+ case OS.WM_SYSCHAR: result = WM_SYSCHAR (wParam, lParam); break;
+ case OS.WM_SYSCOLORCHANGE: result = WM_SYSCOLORCHANGE (wParam, lParam); break;
+ case OS.WM_SYSCOMMAND: result = WM_SYSCOMMAND (wParam, lParam); break;
+ case OS.WM_SYSKEYDOWN: result = WM_SYSKEYDOWN (wParam, lParam); break;
+ case OS.WM_SYSKEYUP: result = WM_SYSKEYUP (wParam, lParam); break;
+ case OS.WM_TABLET_FLICK: result = WM_TABLET_FLICK (wParam, lParam); break;
+ case OS.WM_TIMER: result = WM_TIMER (wParam, lParam); break;
+ case OS.WM_TOUCH: result = WM_TOUCH (wParam, lParam); break;
+ case OS.WM_UNDO: result = WM_UNDO (wParam, lParam); break;
+ case OS.WM_UNINITMENUPOPUP: result = WM_UNINITMENUPOPUP (wParam, lParam); break;
+ case OS.WM_UPDATEUISTATE: result = WM_UPDATEUISTATE (wParam, lParam); break;
+ case OS.WM_VSCROLL: result = WM_VSCROLL (wParam, lParam); break;
+ case OS.WM_WINDOWPOSCHANGED: result = WM_WINDOWPOSCHANGED (wParam, lParam); break;
+ case OS.WM_WINDOWPOSCHANGING: result = WM_WINDOWPOSCHANGING (wParam, lParam); break;
+ case OS.WM_XBUTTONDBLCLK: result = WM_XBUTTONDBLCLK (wParam, lParam); break;
+ case OS.WM_XBUTTONDOWN: result = WM_XBUTTONDOWN (wParam, lParam); break;
+ case OS.WM_XBUTTONUP: result = WM_XBUTTONUP (wParam, lParam); break;
+ case OS.WM_DPICHANGED: result = WM_DPICHANGED (wParam, lParam); break;
+ }
+ if (result != null) return result.value;
+ // widget could be disposed at this point
+ display.sendPreExternalEventDispatchEvent ();
+ try {
+ return callWindowProc (hwnd, msg, wParam, lParam);
+ } finally {
+ // widget could be disposed at this point
+ display.sendPostExternalEventDispatchEvent ();
+ }
+}
+
+LRESULT WM_ACTIVATE (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_CAPTURECHANGED (long wParam, long lParam) {
+ return wmCaptureChanged (handle, wParam, lParam);
+}
+
+LRESULT WM_CHANGEUISTATE (long wParam, long lParam) {
+ if ((state & IGNORE_WM_CHANGEUISTATE) != 0) return LRESULT.ZERO;
+ return null;
+}
+
+LRESULT WM_CHAR (long wParam, long lParam) {
+ return wmChar (handle, wParam, lParam);
+}
+
+LRESULT WM_CLEAR (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_CLOSE (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_COMMAND (long wParam, long lParam) {
+ /*
+ * When the WM_COMMAND message is sent from a
+ * menu, the HWND parameter in LPARAM is zero.
+ */
+ if (lParam == 0) {
+ Decorations shell = menuShell ();
+ if (shell.isEnabled ()) {
+ int id = OS.LOWORD (wParam);
+ MenuItem item = display.getMenuItem (id);
+ if (item != null && item.isEnabled ()) {
+ return item.wmCommandChild (wParam, lParam);
+ }
+ }
+ return null;
+ }
+ Control control = display.getControl (lParam);
+ if (control == null) return null;
+ return control.wmCommandChild (wParam, lParam);
+}
+
+LRESULT WM_CONTEXTMENU (long wParam, long lParam) {
+ return wmContextMenu (handle, wParam, lParam);
+}
+
+LRESULT WM_CTLCOLOR (long wParam, long lParam) {
+ Control control = display.getControl (lParam);
+ if (control == null) return null;
+ return control.wmColorChild (wParam, lParam);
+}
+
+LRESULT WM_CUT (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_DESTROY (long wParam, long lParam) {
+ OS.KillTimer (this.handle, Menu.ID_TOOLTIP_TIMER);
+ return null;
+}
+
+LRESULT WM_DPICHANGED (long wParam, long lParam) {
+ // Map DPI to Zoom and compare
+ int nativeZoom = DPIUtil.mapDPIToZoom (OS.HIWORD (wParam));
+ int newSWTZoom = DPIUtil.getZoomForAutoscaleProperty (nativeZoom);
+ int oldSWTZoom = DPIUtil.getDeviceZoom();
+
+ // Throw the DPI change event if zoom value changes
+ if (newSWTZoom != oldSWTZoom) {
+ Event event = new Event();
+ event.type = SWT.ZoomChanged;
+ event.widget = this;
+ event.detail = newSWTZoom;
+ event.doit = true;
+ notifyListeners(SWT.ZoomChanged, event);
+ return LRESULT.ZERO;
+ }
+ return LRESULT.ONE;
+}
+
+LRESULT WM_DRAWITEM (long wParam, long lParam) {
+ DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
+ OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
+ if (struct.CtlType == OS.ODT_MENU) {
+ MenuItem item = display.getMenuItem (struct.itemID);
+ if (item == null) return null;
+ return item.wmDrawChild (wParam, lParam);
+ }
+ Control control = display.getControl (struct.hwndItem);
+ if (control == null) return null;
+ return control.wmDrawChild (wParam, lParam);
+}
+
+LRESULT WM_ENDSESSION (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_ENTERIDLE (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_ENTERMENULOOP (long wParam, long lParam) {
+ display.externalEventLoop = true;
+ return null;
+}
+
+LRESULT WM_ENTERSIZEMOVE (long wParam, long lParam) {
+ display.externalEventLoop = true;
+ return null;
+}
+
+LRESULT WM_ERASEBKGND (long wParam, long lParam) {
+ if ((state & DRAW_BACKGROUND) != 0) {
+ if (findImageControl () != null) return LRESULT.ONE;
+ }
+ if ((state & THEME_BACKGROUND) != 0) {
+ if (OS.IsAppThemed ()) {
+ if (findThemeControl () != null) return LRESULT.ONE;
+ }
+ }
+ return null;
+}
+
+LRESULT WM_EXITMENULOOP (long wParam, long lParam) {
+ display.externalEventLoop = false;
+ return null;
+}
+
+LRESULT WM_EXITSIZEMOVE (long wParam, long lParam) {
+ display.externalEventLoop = false;
+ return null;
+}
+
+LRESULT WM_GESTURE (long wParam, long lParam) {
+ if (hooks (SWT.Gesture) || filters (SWT.Gesture)) {
+ GESTUREINFO gi = new GESTUREINFO ();
+ gi.cbSize = GESTUREINFO.sizeof;
+ if (OS.GetGestureInfo (lParam, gi)) {
+ if (!sendGestureEvent (gi)) {
+ OS.CloseGestureInfoHandle (lParam);
+ return LRESULT.ZERO;
+ }
+ }
+ }
+ return null;
+}
+
+LRESULT WM_GETDLGCODE (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_GETFONT (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_GETOBJECT (long wParam, long lParam) {
+ if (accessible != null) {
+ long result = accessible.internal_WM_GETOBJECT (wParam, lParam);
+ if (result != 0) return new LRESULT (result);
+ }
+ return null;
+}
+
+LRESULT WM_GETMINMAXINFO (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_HOTKEY (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_HELP (long wParam, long lParam) {
+ HELPINFO lphi = new HELPINFO ();
+ OS.MoveMemory (lphi, lParam, HELPINFO.sizeof);
+ Decorations shell = menuShell ();
+ if (!shell.isEnabled ()) return null;
+ if (lphi.iContextType == OS.HELPINFO_MENUITEM) {
+ MenuItem item = display.getMenuItem (lphi.iCtrlId);
+ if (item != null && item.isEnabled ()) {
+ Widget widget = null;
+ if (item.hooks (SWT.Help)) {
+ widget = item;
+ } else {
+ Menu menu = item.parent;
+ if (menu.hooks (SWT.Help)) widget = menu;
+ }
+ if (widget != null) {
+ long hwndShell = shell.handle;
+ OS.SendMessage (hwndShell, OS.WM_CANCELMODE, 0, 0);
+ widget.postEvent (SWT.Help);
+ return LRESULT.ONE;
+ }
+ }
+ return null;
+ }
+ if (hooks (SWT.Help)) {
+ postEvent (SWT.Help);
+ return LRESULT.ONE;
+ }
+ return null;
+}
+
+LRESULT WM_HSCROLL (long wParam, long lParam) {
+ Control control = display.getControl (lParam);
+ if (control == null) return null;
+ return control.wmScrollChild (wParam, lParam);
+}
+
+LRESULT WM_IME_CHAR (long wParam, long lParam) {
+ return wmIMEChar (handle, wParam, lParam);
+}
+
+LRESULT WM_IME_COMPOSITION (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_IME_COMPOSITION_START (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_IME_ENDCOMPOSITION (long wParam, long lParam) {
+ return null;
+}
+
+LRESULT WM_UNINITMENUPOPUP (long wParam, long lParam) {
+ Menu hiddenMenu = menuShell ().findMenu (wParam);
+ if (hiddenMenu != null) {
+ Shell shell = getShell ();
+ hiddenMenu.sendEvent (SWT.Hide);
+ if (hiddenMenu == shell.activeMenu) shell.activeMenu = null;
+ }
+ return null;
+}
+
+LRESULT WM_INITMENUPOPUP (long wParam, long lParam) {
+
+ /* Ignore WM_INITMENUPOPUP for an accelerator */
+ if (display.accelKeyHit) return null;
+
+ /*
+ * If the high order word of LPARAM is non-zero,
+ * the menu is the system menu and we can ignore
+ * WPARAM. Otherwise, use WPARAM to find the menu.
+ */
+ Shell shell = getShell ();
+ Menu oldMenu = shell.activeMenu, newMenu = null;
+ if (OS.HIWORD (lParam) == 0) {
+ newMenu = menuShell ().findMenu (wParam);
+ if (newMenu != null) newMenu.update ();
+ }
+ Menu menu = newMenu;
+ while (menu != null && menu != oldMenu) {
+ menu = menu.getParentMenu ();
+ }
+ if (menu == null) {
+ menu = shell.activeMenu;
+ while (menu != null) {
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the hide
+ * event. If this happens, stop searching up the
+ * ancestor list because there is no longer a link
+ * to follow.
+ */
+ menu.sendEvent (SWT.Hide);
+ if (menu.isDisposed ()) break;
+ menu = menu.getParentMenu ();
+ Menu ancestor = newMenu;
+ while (ancestor != null && ancestor != menu) {
+ ancestor = ancestor.getParentMenu ();
+ }
+ if (ancestor != null) break;
+ }
+ }
+
+ /*
+ * The shell and the new menu may be disposed because of
+ * sending the hide event to the ancestor menus but setting
+ * a field to null in a disposed shell is not harmful.
+ */
+ if (newMenu != null && newMenu.isDisposed ()) newMenu = null;
+ shell.activeMenu = newMenu;
+
+ /* Send the show event */
+ if (newMenu != null && newMenu != oldMenu) {
+ newMenu.sendEvent (SWT.Show);
+ // widget could be disposed at this point
+ }
+ return null;
+}
+
+LRESULT WM_INPUTLANGCHANGE (long wParam, long lParam) {
+ menuShell().destroyAccelerators();
+ return null;
+}
+
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ return wmKeyDown (handle, wParam, lParam);
+}
+
+LRESULT WM_KEYUP (long wParam, long lParam) {
+ return wmKeyUp (handle, wParam, lParam);
+}
+
+LRESULT WM_KILLFOCUS (long wParam, long lParam) {
+ return wmKillFocus (handle, wParam, lParam);
+}
+
+LRESULT WM_LBUTTONDBLCLK (long wParam, long lParam) {
+ return wmLButtonDblClk (handle, wParam, lParam);
+}
+
+LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
+ return wmLButtonDown (handle, wParam, lParam);
+}
+
+LRESULT WM_LBUTTONUP (long wParam, long lParam) {
+ return wmLButtonUp (handle, wParam, lParam);
+}
+
+LRESULT WM_MBUTTONDBLCLK (long wParam, long lParam) {
+ return wmMButtonDblClk (handle, wParam, lParam);
+}
+
+LRESULT WM_MBUTTONDOWN (long wParam, long lParam) {
+ return wmMButtonDown (handle, wParam, lParam);
+}
+
+LRESULT WM_MBUTTONUP (long wParam, long lParam) {
+ return wmMButtonUp (handle, wParam, lParam);
+}
+
+LRESULT WM_MEASUREITEM (long wParam, long lParam) {
+ MEASUREITEMSTRUCT struct = new MEASUREITEMSTRUCT ();
+ OS.MoveMemory (struct, lParam, MEASUREITEMSTRUCT.sizeof);
+ if (struct.CtlType == OS.ODT_MENU) {
+ MenuItem item = display.getMenuItem (struct.itemID);
+ if (item == null) return null;
+ return item.wmMeasureChild (wParam, lParam);
+ }
+ long hwnd = OS.GetDlgItem (handle, struct.CtlID);
+ Control control = display.getControl (hwnd);
+ if (control == null) return null;
+ return control.wmMeasureChild (wParam, lParam);
+}
+
+LRESULT WM_MENUCHAR (long wParam, long lParam) {
+ /*
+ * Feature in Windows. When the user types Alt+CoolItem
.
+ * Composite
,
+ * it does not make sense to add Control
children to it,
+ * or set a layout on it.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see SWT#FLAT
+ * @see SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public CoolBar (Composite parent, int style) {
+ super (parent, checkStyle (style));
+ /*
+ * Ensure that either of HORIZONTAL or VERTICAL is set.
+ * NOTE: HORIZONTAL and VERTICAL have the same values
+ * as H_SCROLL and V_SCROLL so it is necessary to first
+ * clear these bits to avoid scroll bars and then reset
+ * the bits using the original style supplied by the
+ * programmer.
+ *
+ * NOTE: The CCS_VERT style cannot be applied when the
+ * widget is created because of this conflict.
+ */
+ if ((style & SWT.VERTICAL) != 0) {
+ this.style |= SWT.VERTICAL;
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ OS.SetWindowLong (handle, OS.GWL_STYLE, bits | OS.CCS_VERT);
+ } else {
+ this.style |= SWT.HORIZONTAL;
+ }
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ return OS.CallWindowProc (ReBarProc, hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ style |= SWT.NO_FOCUS;
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ int width = 0, height = 0;
+ int border = getBorderWidthInPixels ();
+ int newWidth = wHint == SWT.DEFAULT ? 0x3FFF : wHint + (border * 2);
+ int newHeight = hHint == SWT.DEFAULT ? 0x3FFF : hHint + (border * 2);
+ int count = (int)OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
+ if (count != 0) {
+ ignoreResize = true;
+ boolean redraw = false;
+ if (OS.IsWindowVisible (handle)) {
+ redraw = true;
+ OS.UpdateWindow (handle);
+ OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
+ }
+ RECT oldRect = new RECT ();
+ OS.GetWindowRect (handle, oldRect);
+ int oldWidth = oldRect.right - oldRect.left;
+ int oldHeight = oldRect.bottom - oldRect.top;
+ int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER;
+ OS.SetWindowPos (handle, 0, 0, 0, newWidth, newHeight, flags);
+ RECT rect = new RECT ();
+ OS.SendMessage (handle, OS.RB_GETRECT, count - 1, rect);
+ height = Math.max (height, rect.bottom);
+ OS.SetWindowPos (handle, 0, 0, 0, oldWidth, oldHeight, flags);
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_IDEALSIZE | OS.RBBIM_STYLE;
+ int rowWidth = 0;
+ for (int i = 0; i < count; i++) {
+ OS.SendMessage(handle, OS.RB_GETBANDINFO, i, rbBand);
+ if ((rbBand.fStyle & OS.RBBS_BREAK) != 0) {
+ width = Math.max(width, rowWidth);
+ rowWidth = 0;
+ }
+ rowWidth += rbBand.cxIdeal + getMargin (i);
+ }
+ width = Math.max(width, rowWidth);
+ if (redraw) {
+ OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
+ }
+ ignoreResize = false;
+ }
+ if (width == 0) width = DEFAULT_COOLBAR_WIDTH;
+ if (height == 0) height = DEFAULT_COOLBAR_HEIGHT;
+ if ((style & SWT.VERTICAL) != 0) {
+ int tmp = width;
+ width = height;
+ height = tmp;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ height += border * 2;
+ width += border * 2;
+ return new Point (width, height);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state &= ~(CANVAS | THEME_BACKGROUND);
+
+ /*
+ * Feature in Windows. When the control is created,
+ * it does not use the default system font. A new HFONT
+ * is created and destroyed when the control is destroyed.
+ * This means that a program that queries the font from
+ * this control, uses the font in another control and then
+ * destroys this control will have the font unexpectedly
+ * destroyed in the other control. The fix is to assign
+ * the font ourselves each time the control is created.
+ * The control will not destroy a font that it did not
+ * create.
+ */
+ long hFont = OS.GetStockObject (OS.SYSTEM_FONT);
+ OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
+}
+
+void createItem (CoolItem item, int index) {
+ int count = (int)OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
+ if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
+ int id = 0;
+ while (id < items.length && items [id] != null) id++;
+ if (id == items.length) {
+ CoolItem [] newItems = new CoolItem [items.length + 4];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ long hHeap = OS.GetProcessHeap ();
+ long lpText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof);
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_TEXT | OS.RBBIM_STYLE | OS.RBBIM_ID;
+ rbBand.fStyle = OS.RBBS_VARIABLEHEIGHT | OS.RBBS_GRIPPERALWAYS;
+ if ((item.style & SWT.DROP_DOWN) != 0) {
+ rbBand.fStyle |= OS.RBBS_USECHEVRON;
+ }
+ rbBand.lpText = lpText;
+ rbBand.wID = id;
+
+ /*
+ * Feature in Windows. When inserting an item at end of a row,
+ * sometimes, Windows will begin to place the item on the right
+ * side of the cool bar. The fix is to resize the new items to
+ * the maximum size and then resize the next to last item to the
+ * ideal size.
+ */
+ int lastIndex = getLastIndexOfRow (index - 1);
+ boolean fixLast = index == lastIndex + 1;
+ if (fixLast) {
+ rbBand.fMask |= OS.RBBIM_SIZE;
+ rbBand.cx = MAX_WIDTH;
+ }
+
+ /*
+ * Feature in Windows. Is possible that the item at index zero
+ * has the RBBS_BREAK flag set. When a new item is inserted at
+ * position zero, the previous item at position zero moves to
+ * a new line. The fix is to detect this case and clear the
+ * RBBS_BREAK flag on the previous item before inserting the
+ * new item.
+ */
+ if (index == 0 && count > 0) {
+ getItem (0).setWrap (false);
+ }
+
+ /* Insert the item */
+ if (OS.SendMessage (handle, OS.RB_INSERTBAND, index, rbBand) == 0) {
+ error (SWT.ERROR_ITEM_NOT_ADDED);
+ }
+
+ /* Resize the next to last item to the ideal size */
+ if (fixLast) {
+ resizeToPreferredWidth (lastIndex);
+ }
+
+ OS.HeapFree (hHeap, 0, lpText);
+ items [item.id = id] = item;
+ int length = originalItems.length;
+ CoolItem [] newOriginals = new CoolItem [length + 1];
+ System.arraycopy (originalItems, 0, newOriginals, 0, index);
+ System.arraycopy (originalItems, index, newOriginals, index + 1, length - index);
+ newOriginals [index] = item;
+ originalItems = newOriginals;
+}
+
+@Override
+void createWidget () {
+ super.createWidget ();
+ items = new CoolItem [4];
+ originalItems = new CoolItem [0];
+}
+
+void destroyItem (CoolItem item) {
+ int index = (int)OS.SendMessage (handle, OS.RB_IDTOINDEX, item.id, 0);
+ int count = (int)OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
+ if (count != 0) {
+ int lastIndex = getLastIndexOfRow (index);
+ if (index == lastIndex) {
+ /*
+ * Feature in Windows. If the last item in a row is
+ * given its ideal size, it will be placed at the far
+ * right hand edge of the coolbar. It is preferred
+ * that the last item appear next to the second last
+ * item. The fix is to size the last item of each row
+ * so that it occupies all the available space to the
+ * right in the row.
+ */
+ resizeToMaximumWidth (lastIndex - 1);
+ }
+ }
+
+ /*
+ * Feature in Windows. When Windows removed a rebar
+ * band, it makes the band child invisible. The fix
+ * is to show the child.
+ */
+ Control control = item.control;
+ boolean wasVisible = control != null && !control.isDisposed() && control.getVisible ();
+
+ /*
+ * When a wrapped item is being deleted, make the next
+ * item in the row wrapped in order to preserve the row.
+ * In order to avoid an unnecessary layout, temporarily
+ * ignore WM_SIZE. If the next item is wrapped then a
+ * row will be deleted and the WM_SIZE is necessary.
+ */
+ CoolItem nextItem = null;
+ if (item.getWrap ()) {
+ if (index + 1 < count) {
+ nextItem = getItem (index + 1);
+ ignoreResize = !nextItem.getWrap ();
+ }
+ }
+ if (OS.SendMessage (handle, OS.RB_DELETEBAND, index, 0) == 0) {
+ error (SWT.ERROR_ITEM_NOT_REMOVED);
+ }
+ items [item.id] = null;
+ item.id = -1;
+ if (ignoreResize) {
+ nextItem.setWrap (true);
+ ignoreResize = false;
+ }
+
+ /* Restore the visible state of the control */
+ if (wasVisible) control.setVisible (true);
+
+ index = 0;
+ while (index < originalItems.length) {
+ if (originalItems [index] == item) break;
+ index++;
+ }
+ int length = originalItems.length - 1;
+ CoolItem [] newOriginals = new CoolItem [length];
+ System.arraycopy (originalItems, 0, newOriginals, 0, index);
+ System.arraycopy (originalItems, index + 1, newOriginals, index, length - index);
+ originalItems = newOriginals;
+}
+
+@Override
+void drawThemeBackground (long hDC, long hwnd, RECT rect) {
+ if (OS.IsAppThemed ()) {
+ if (background == -1 && (style & SWT.FLAT) != 0) {
+ Control control = findBackgroundControl ();
+ if (control != null && control.backgroundImage != null) {
+ fillBackground (hDC, control.getBackgroundPixel (), rect);
+ return;
+ }
+ }
+ }
+ RECT rect2 = new RECT ();
+ OS.GetClientRect (handle, rect2);
+ OS.MapWindowPoints (handle, hwnd, rect2, 2);
+ POINT lpPoint = new POINT ();
+ OS.SetWindowOrgEx (hDC, -rect2.left, -rect2.top, lpPoint);
+ OS.SendMessage (handle, OS.WM_PRINT, hDC, OS.PRF_CLIENT | OS.PRF_ERASEBKGND);
+ OS.SetWindowOrgEx (hDC, lpPoint.x, lpPoint.y, null);
+}
+
+@Override
+Control findThemeControl () {
+ if ((style & SWT.FLAT) != 0) return this;
+ return background == -1 && backgroundImage == null ? this : super.findThemeControl ();
+}
+
+int getMargin (int index) {
+ int margin = 0;
+ MARGINS margins = new MARGINS ();
+ OS.SendMessage (handle, OS.RB_GETBANDMARGINS, 0, margins);
+ margin += margins.cxLeftWidth + margins.cxRightWidth;
+ RECT rect = new RECT ();
+ OS.SendMessage (handle, OS.RB_GETBANDBORDERS, index, rect);
+ if ((style & SWT.FLAT) != 0) {
+ /*
+ * Bug in Windows. When the style bit RBS_BANDBORDERS is not set
+ * the rectangle returned by RBS_BANDBORDERS is four pixels too small.
+ * The fix is to add four pixels to the result.
+ */
+ if ((style & SWT.VERTICAL) != 0) {
+ margin += rect.top + 4;
+ } else {
+ margin += rect.left + 4;
+ }
+ } else {
+ if ((style & SWT.VERTICAL) != 0) {
+ margin += rect.top + rect.bottom;
+ } else {
+ margin += rect.left + rect.right;
+ }
+ }
+ if ((style & SWT.FLAT) == 0) {
+ if (!isLastItemOfRow (index)) {
+ margin += CoolBar.SEPARATOR_WIDTH;
+ }
+ }
+ return margin;
+}
+
+/**
+ * Returns the item that is currently displayed at the given,
+ * zero-relative index. Throws an exception if the index is
+ * out of range.
+ *
+ * @param index the visual index of the item to return
+ * @return the item at the given visual index
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public CoolItem getItem (int index) {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
+ if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_ID;
+ OS.SendMessage (handle, OS.RB_GETBANDINFO, index, rbBand);
+ return items [rbBand.wID];
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemCount () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
+}
+
+/**
+ * Returns an array of zero-relative ints that map
+ * the creation order of the receiver's items to the
+ * order in which they are currently being displayed.
+ *
+ *
+ */
+public int [] getItemOrder () {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
+ int [] indices = new int [count];
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_ID;
+ for (int i=0; i
+ *
+ */
+public CoolItem [] getItems () {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
+ CoolItem [] result = new CoolItem [count];
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_ID;
+ for (int i=0; i
+ *
+ */
+public int [] getWrapIndices () {
+ checkWidget ();
+ CoolItem [] items = getItems ();
+ int [] indices = new int [items.length];
+ int count = 0;
+ for (int i=0; i
+ *
+ */
+public int indexOf (CoolItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ return (int)OS.SendMessage (handle, OS.RB_IDTOINDEX, item.id, 0);
+}
+
+void resizeToPreferredWidth (int index) {
+ /*
+ * Bug in Windows. When RB_GETBANDBORDERS is sent
+ * with an index out of range, Windows GP's. The
+ * fix is to ensure the index is in range.
+ */
+ int count = (int)OS.SendMessage(handle, OS.RB_GETBANDCOUNT, 0, 0);
+ if (0 <= index && index < count) {
+ REBARBANDINFO rbBand = new REBARBANDINFO();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_IDEALSIZE;
+ OS.SendMessage (handle, OS.RB_GETBANDINFO, index, rbBand);
+ RECT rect = new RECT ();
+ OS.SendMessage (handle, OS.RB_GETBANDBORDERS, index, rect);
+ rbBand.cx = rbBand.cxIdeal + rect.left;
+ if ((style & SWT.FLAT) == 0) rbBand.cx += rect.right;
+ rbBand.fMask = OS.RBBIM_SIZE;
+ OS.SendMessage (handle, OS.RB_SETBANDINFO, index, rbBand);
+ }
+}
+
+void resizeToMaximumWidth (int index) {
+ REBARBANDINFO rbBand = new REBARBANDINFO();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_SIZE;
+ rbBand.cx = MAX_WIDTH;
+ OS.SendMessage (handle, OS.RB_SETBANDINFO, index, rbBand);
+}
+
+@Override
+void releaseChildren (boolean destroy) {
+ if (items != null) {
+ for (int i=0; i
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public void setItemLayout (int [] itemOrder, int [] wrapIndices, Point [] sizes) {
+ checkWidget ();
+ if (sizes == null) error (SWT.ERROR_NULL_ARGUMENT);
+ Point [] sizesInPoints = new Point [sizes.length];
+ for (int i = 0; i < sizes.length; i++) {
+ sizesInPoints[i] = DPIUtil.autoScaleUp(sizes[i]);
+ }
+ setItemLayoutInPixels (itemOrder, wrapIndices, sizesInPoints);
+}
+
+void setItemLayoutInPixels (int [] itemOrder, int [] wrapIndices, Point [] sizes) {
+ setRedraw (false);
+ setItemOrder (itemOrder);
+ setWrapIndices (wrapIndices);
+ setItemSizes (sizes);
+ setRedraw (true);
+}
+
+/*
+ * Sets the order that the items in the receiver should
+ * be displayed in to the given argument which is described
+ * in terms of the zero-relative ordering of when the items
+ * were added.
+ *
+ * @param itemOrder the new order to display the items in
+ *
+ * @exception SWTException
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+void setItemOrder (int [] itemOrder) {
+ if (itemOrder == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int itemCount = (int)OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
+ if (itemOrder.length != itemCount) error (SWT.ERROR_INVALID_ARGUMENT);
+
+ /* Ensure that itemOrder does not contain any duplicates. */
+ boolean [] set = new boolean [itemCount];
+ for (int i=0; i
+ *
+ * @exception SWTException
+ *
+ */
+void setItemSizes (Point [] sizes) {
+ if (sizes == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int count = (int)OS.SendMessage (handle, OS.RB_GETBANDCOUNT, 0, 0);
+ if (sizes.length != count) error (SWT.ERROR_INVALID_ARGUMENT);
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_ID;
+ for (int i=0; i
+ *
+ * CoolBar
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public CoolItem (CoolBar parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ parent.createItem (this, parent.getItemCount ());
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a CoolBar
), a style value
+ * describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public CoolItem (CoolBar parent, int style, int index) {
+ super (parent, style);
+ this.parent = parent;
+ parent.createItem (this, index);
+}
+
+/**
+ * Adds the listener to the collection of listeners that will
+ * be notified when the control is selected by the user, by sending it one
+ * of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called when the mouse is over
+ * the drop-down arrow (or 'chevron') portion of the cool item,
+ * the event object detail field contains the value SWT.ARROW
,
+ * and the x and y fields in the event object represent the point at
+ * the bottom left of the chevron, where the menu should be popped up.
+ * widgetDefaultSelected
is not called.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ *
+ * @since 2.0
+ */
+public void addSelectionListener(SelectionListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+/**
+ * Returns the preferred size of the receiver.
+ * CoolItem
is the size that
+ * it would best be displayed at. The width hint and height hint arguments
+ * allow the caller to ask the instance questions such as "Given a particular
+ * width, how high does it need to be to show all of the contents?"
+ * To indicate that the caller does not wish to constrain a particular
+ * dimension, the constant SWT.DEFAULT
is passed for the hint.
+ * SWT.DEFAULT
)
+ * @param hHint the height hint (can be SWT.DEFAULT
)
+ * @return the preferred size
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Layout
+ * @see #getBounds
+ * @see #getSize
+ * @see Control#getBorderWidth
+ * @see Scrollable#computeTrim
+ * @see Scrollable#getClientArea
+ */
+public Point computeSize (int wHint, int hHint) {
+ checkWidget ();
+ wHint = (wHint != SWT.DEFAULT ? DPIUtil.autoScaleUp(wHint) : wHint);
+ hHint = (hHint != SWT.DEFAULT ? DPIUtil.autoScaleUp(hHint) : hHint);
+ return DPIUtil.autoScaleDown(computeSizeInPixels(wHint, hHint));
+}
+Point computeSizeInPixels (int wHint, int hHint) {
+ int index = parent.indexOf (this);
+ if (index == -1) return new Point (0, 0);
+ int width = wHint, height = hHint;
+ if (wHint == SWT.DEFAULT) width = 32;
+ if (hHint == SWT.DEFAULT) height = 32;
+ if ((parent.style & SWT.VERTICAL) != 0) {
+ height += parent.getMargin (index);
+ } else {
+ width += parent.getMargin (index);
+ }
+ return new Point (width, height);
+}
+
+@Override
+void destroyWidget () {
+ parent.destroyItem (this);
+ releaseHandle ();
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent.
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException
+ *
+ */
+public Rectangle getBounds () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getBoundsInPixels());
+}
+
+Rectangle getBoundsInPixels () {
+ int index = parent.indexOf (this);
+ if (index == -1) return new Rectangle (0, 0, 0, 0);
+ long hwnd = parent.handle;
+ RECT rect = new RECT ();
+ OS.SendMessage (hwnd, OS.RB_GETRECT, index, rect);
+ MARGINS margins = new MARGINS ();
+ OS.SendMessage (hwnd, OS.RB_GETBANDMARGINS, 0, margins);
+ rect.left -= margins.cxLeftWidth;
+ rect.right += margins.cxRightWidth;
+ if (!parent.isLastItemOfRow (index)) {
+ rect.right += (parent.style & SWT.FLAT) == 0 ? CoolBar.SEPARATOR_WIDTH : 0;
+ }
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ if ((parent.style & SWT.VERTICAL) != 0) {
+ return new Rectangle (rect.top, rect.left, height, width);
+ }
+ return new Rectangle (rect.left, rect.top, width, height);
+}
+
+Rectangle getClientArea () {
+ checkWidget ();
+ int index = parent.indexOf (this);
+ if (index == -1) return new Rectangle (0, 0, 0, 0);
+ long hwnd = parent.handle;
+ RECT insetRect = new RECT ();
+ OS.SendMessage (hwnd, OS.RB_GETBANDBORDERS, index, insetRect);
+ RECT rect = new RECT ();
+ OS.SendMessage (hwnd, OS.RB_GETRECT, index, rect);
+ int x = rect.left + insetRect.left;
+ int y = rect.top;
+ int width = rect.right - rect.left - insetRect.left;
+ int height = rect.bottom - rect.top;
+ if ((parent.style & SWT.FLAT) == 0) {
+ y += insetRect.top;
+ width -= insetRect.right;
+ height -= insetRect.top + insetRect.bottom;
+ }
+ if (index == 0) {
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_HEADERSIZE;
+ OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
+ width = width - rbBand.cxHeader + 1;
+ }
+ return new Rectangle (x, y, Math.max (0, width), Math.max (0, height));
+}
+
+/**
+ * Returns the control that is associated with the receiver.
+ *
+ * @return the control that is contained by the receiver
+ *
+ * @exception SWTException
+ *
+ */
+public Control getControl () {
+ checkWidget ();
+ return control;
+}
+
+/**
+ * Returns the receiver's parent, which must be a CoolBar
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException
+ *
+ */
+public CoolBar getParent () {
+ checkWidget ();
+ return parent;
+}
+
+@Override
+void releaseHandle () {
+ super.releaseHandle ();
+ parent = null;
+ id = -1;
+ control = null;
+}
+
+/**
+ * Sets the control that is associated with the receiver
+ * to the argument.
+ *
+ * @param control the new control that will be contained by the receiver
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setControl (Control control) {
+ checkWidget ();
+ if (control != null) {
+ if (control.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (control.parent != parent) error (SWT.ERROR_INVALID_PARENT);
+ }
+ int index = parent.indexOf (this);
+ if (index == -1) return;
+ if (this.control != null && this.control.isDisposed ()) {
+ this.control = null;
+ }
+ Control oldControl = this.control, newControl = control;
+ long hwnd = parent.handle;
+ long hwndChild = newControl != null ? control.topHandle () : 0;
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_CHILD;
+ rbBand.hwndChild = hwndChild;
+ this.control = newControl;
+
+ /*
+ * Feature in Windows. When Windows sets the rebar band child,
+ * it makes the new child visible and hides the old child and
+ * moves the new child to the top of the Z-order. The fix is
+ * to save and restore the visibility and Z-order.
+ */
+ long hwndAbove = 0;
+ if (newControl != null) {
+ hwndAbove = OS.GetWindow (hwndChild, OS.GW_HWNDPREV);
+ }
+ boolean hideNew = newControl != null && !newControl.getVisible ();
+ boolean showOld = oldControl != null && oldControl.getVisible ();
+ OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
+ if (hideNew) newControl.setVisible (false);
+ if (showOld) oldControl.setVisible (true);
+ if (hwndAbove != 0 && hwndAbove != hwndChild) {
+ int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (hwndChild, hwndAbove, 0, 0, 0, 0, flags);
+ }
+}
+
+/**
+ * Returns a point describing the receiver's ideal size.
+ * The x coordinate of the result is the ideal width of the receiver.
+ * The y coordinate of the result is the ideal height of the receiver.
+ *
+ * @return the receiver's ideal size
+ *
+ * @exception SWTException
+ *
+ */
+public Point getPreferredSize () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getPreferredSizeInPixels());
+}
+
+Point getPreferredSizeInPixels () {
+ int index = parent.indexOf (this);
+ if (index == -1) return new Point (0, 0);
+ long hwnd = parent.handle;
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE;
+ OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
+ int width = rbBand.cxIdeal + parent.getMargin (index);
+ if ((parent.style & SWT.VERTICAL) != 0) {
+ return new Point (rbBand.cyMaxChild, width);
+ }
+ return new Point (width, rbBand.cyMaxChild);
+}
+
+/**
+ * Sets the receiver's ideal size to the point specified by the arguments.
+ *
+ * @param width the new ideal width for the receiver
+ * @param height the new ideal height for the receiver
+ *
+ * @exception SWTException
+ *
+ */
+public void setPreferredSize (int width, int height) {
+ checkWidget ();
+ setPreferredSizeInPixels(DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height));
+}
+
+void setPreferredSizeInPixels (int width, int height) {
+ int index = parent.indexOf (this);
+ if (index == -1) return;
+ width = Math.max (0, width);
+ height = Math.max (0, height);
+ ideal = true;
+ long hwnd = parent.handle;
+ int cxIdeal, cyMaxChild;
+ if ((parent.style & SWT.VERTICAL) != 0) {
+ cxIdeal = Math.max (0, height - parent.getMargin (index));
+ cyMaxChild = width;
+ } else {
+ cxIdeal = Math.max (0, width - parent.getMargin (index));
+ cyMaxChild = height;
+ }
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+
+ /* Get the child size fields first so we don't overwrite them. */
+ rbBand.fMask = OS.RBBIM_CHILDSIZE;
+ OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
+
+ /* Set the size fields we are currently modifying. */
+ rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE;
+ rbBand.cxIdeal = cxIdeal;
+ rbBand.cyMaxChild = cyMaxChild;
+ if (!minimum) rbBand.cyMinChild = cyMaxChild;
+ OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
+}
+
+/**
+ * Sets the receiver's ideal size to the point specified by the argument.
+ *
+ * @param size the new ideal size for the receiver
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setPreferredSize (Point size) {
+ checkWidget ();
+ if (size == null) error(SWT.ERROR_NULL_ARGUMENT);
+ size = DPIUtil.autoScaleUp(size);
+ setPreferredSizeInPixels(size.x, size.y);
+}
+
+/**
+ * Returns a point describing the receiver's size. The
+ * x coordinate of the result is the width of the receiver.
+ * The y coordinate of the result is the height of the
+ * receiver.
+ *
+ * @return the receiver's size
+ *
+ * @exception SWTException
+ *
+ */
+public Point getSize () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getSizeInPixels());
+}
+
+Point getSizeInPixels() {
+ int index = parent.indexOf (this);
+ if (index == -1) new Point (0, 0);
+ long hwnd = parent.handle;
+ RECT rect = new RECT ();
+ OS.SendMessage (hwnd, OS.RB_GETRECT, index, rect);
+ MARGINS margins = new MARGINS ();
+ OS.SendMessage (hwnd, OS.RB_GETBANDMARGINS, 0, margins);
+ rect.left -= margins.cxLeftWidth;
+ rect.right += margins.cxRightWidth;
+ if (!parent.isLastItemOfRow (index)) {
+ rect.right += (parent.style & SWT.FLAT) == 0 ? CoolBar.SEPARATOR_WIDTH : 0;
+ }
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ if ((parent.style & SWT.VERTICAL) != 0) {
+ return new Point (height, width);
+ }
+ return new Point (width, height);
+}
+
+/**
+ * Sets the receiver's size to the point specified by the arguments.
+ *
+ *
+ */
+public void setSize (int width, int height) {
+ checkWidget ();
+ setSizeInPixels(DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height));
+}
+
+void setSizeInPixels (int width, int height) {
+ int index = parent.indexOf (this);
+ if (index == -1) return;
+ width = Math.max (0, width);
+ height = Math.max (0, height);
+ long hwnd = parent.handle;
+ int cx, cyChild, cxIdeal;
+ if ((parent.style & SWT.VERTICAL) != 0) {
+ cx = height;
+ cyChild = width;
+ cxIdeal = Math.max (0, height - parent.getMargin (index));
+ } else {
+ cx = width;
+ cyChild = height;
+ cxIdeal = Math.max (0, width - parent.getMargin (index));
+ }
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+
+ /* Get the child size fields first so we don't overwrite them. */
+ rbBand.fMask = OS.RBBIM_CHILDSIZE | OS.RBBIM_IDEALSIZE;
+ OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
+
+ /* Set the size fields we are currently modifying. */
+ if (!ideal) rbBand.cxIdeal = cxIdeal;
+ if (!minimum) rbBand.cyMinChild = cyChild;
+ rbBand.cyChild = cyChild;
+
+ /*
+ * Do not set the size for the last item on the row.
+ */
+ if (!parent.isLastItemOfRow (index)) {
+ MARGINS margins = new MARGINS ();
+ OS.SendMessage (hwnd, OS.RB_GETBANDMARGINS, 0, margins);
+ cx -= margins.cxLeftWidth + margins.cxRightWidth;
+ int separator = (parent.style & SWT.FLAT) == 0 ? CoolBar.SEPARATOR_WIDTH : 0;
+ rbBand.cx = cx - separator;
+ rbBand.fMask |= OS.RBBIM_SIZE;
+ }
+ OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
+}
+
+/**
+ * Sets the receiver's size to the point specified by the argument.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setSize (Point size) {
+ checkWidget ();
+ if (size == null) error(SWT.ERROR_NULL_ARGUMENT);
+ size = DPIUtil.autoScaleUp(size);
+ setSizeInPixels(size.x, size.y);
+}
+
+/**
+ * Returns the minimum size that the cool item can
+ * be resized to using the cool item's gripper.
+ *
+ * @return a point containing the minimum width and height of the cool item, in SWT logical points
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.0
+ */
+public Point getMinimumSize () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getMinimumSizeInPixels());
+}
+
+Point getMinimumSizeInPixels () {
+ int index = parent.indexOf (this);
+ if (index == -1) return new Point (0, 0);
+ long hwnd = parent.handle;
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_CHILDSIZE;
+ OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
+ if ((parent.style & SWT.VERTICAL) != 0) {
+ return new Point (rbBand.cyMinChild, rbBand.cxMinChild);
+ }
+ return new Point (rbBand.cxMinChild, rbBand.cyMinChild);
+}
+
+/**
+ * Sets the minimum size that the cool item can be resized to
+ * using the cool item's gripper, to the point specified by the arguments.
+ *
+ * @param width the minimum width of the cool item, in SWT logical points
+ * @param height the minimum height of the cool item, in SWT logical points
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.0
+ */
+public void setMinimumSize (int width, int height) {
+ checkWidget ();
+ setMinimumSizeInPixels(DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height));
+}
+
+void setMinimumSizeInPixels (int width, int height) {
+ int index = parent.indexOf (this);
+ if (index == -1) return;
+ width = Math.max (0, width);
+ height = Math.max (0, height);
+ minimum = true;
+ long hwnd = parent.handle;
+ int cxMinChild, cyMinChild;
+ if ((parent.style & SWT.VERTICAL) != 0) {
+ cxMinChild = height;
+ cyMinChild = width;
+ } else {
+ cxMinChild = width;
+ cyMinChild = height;
+ }
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+
+ /* Get the child size fields first so we don't overwrite them. */
+ rbBand.fMask = OS.RBBIM_CHILDSIZE;
+ OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
+
+ /* Set the size fields we are currently modifying. */
+ rbBand.cxMinChild = cxMinChild;
+ rbBand.cyMinChild = cyMinChild;
+ OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
+}
+
+/**
+ * Sets the minimum size that the cool item can be resized to
+ * using the cool item's gripper, to the point specified by the argument.
+ *
+ * @param size a point representing the minimum width and height of the cool item, in SWT logical points
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.0
+ */
+public void setMinimumSize (Point size) {
+ checkWidget ();
+ if (size == null) error (SWT.ERROR_NULL_ARGUMENT);
+ size = DPIUtil.autoScaleUp(size);
+ setMinimumSizeInPixels(size.x, size.y);
+}
+
+boolean getWrap() {
+ int index = parent.indexOf (this);
+ long hwnd = parent.handle;
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_STYLE;
+ OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
+ return (rbBand.fStyle & OS.RBBS_BREAK) != 0;
+}
+
+void setWrap(boolean wrap) {
+ int index = parent.indexOf (this);
+ long hwnd = parent.handle;
+ REBARBANDINFO rbBand = new REBARBANDINFO ();
+ rbBand.cbSize = REBARBANDINFO.sizeof;
+ rbBand.fMask = OS.RBBIM_STYLE;
+ OS.SendMessage (hwnd, OS.RB_GETBANDINFO, index, rbBand);
+ if (wrap) {
+ rbBand.fStyle |= OS.RBBS_BREAK;
+ } else {
+ rbBand.fStyle &= ~OS.RBBS_BREAK;
+ }
+ OS.SendMessage (hwnd, OS.RB_SETBANDINFO, index, rbBand);
+}
+
+/**
+ * Removes the listener from the collection of listeners that
+ * will be notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ *
+ * @since 2.0
+ */
+public void removeSelectionListener(SelectionListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/DateTime.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/DateTime.java
new file mode 100644
index 000000000..512ab512b
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/DateTime.java
@@ -0,0 +1,854 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class are selectable user interface
+ * objects that allow the user to enter and modify date
+ * or time values.
+ * Composite
,
+ * it does not make sense to add children to it, or set a layout on it.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#DATE
+ * @see SWT#TIME
+ * @see SWT#CALENDAR
+ * @see SWT#CALENDAR_WEEKNUMBERS
+ * @see SWT#SHORT
+ * @see SWT#MEDIUM
+ * @see SWT#LONG
+ * @see SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public DateTime (Composite parent, int style) {
+ super (parent, checkStyle (style));
+ if ((this.style & SWT.SHORT) != 0) {
+ String buffer = ((this.style & SWT.DATE) != 0) ? getCustomShortDateFormat() : getCustomShortTimeFormat();
+ TCHAR lpszFormat = new TCHAR (0, buffer, true);
+ OS.SendMessage (handle, OS.DTM_SETFORMAT, 0, lpszFormat);
+ }
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the control is selected by the user, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called when the user changes the control's value.
+ * widgetDefaultSelected
is typically called when ENTER is pressed.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection, typedListener);
+ addListener (SWT.DefaultSelection, typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ return OS.CallWindowProc (windowProc (), hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ style &= ~(SWT.H_SCROLL | SWT.V_SCROLL);
+ style = checkBits (style, SWT.DATE, SWT.TIME, SWT.CALENDAR, 0, 0, 0);
+ style = checkBits (style, SWT.MEDIUM, SWT.SHORT, SWT.LONG, 0, 0, 0);
+ if ((style & SWT.DATE) == 0) style &=~ SWT.DROP_DOWN;
+ return style;
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0;
+ if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
+ if ((style & SWT.CALENDAR) != 0) {
+ RECT rect = new RECT ();
+ OS.SendMessage(handle, OS.MCM_GETMINREQRECT, 0, rect);
+ width = rect.right;
+ height = rect.bottom;
+ } else {
+ // customize the style of the drop-down calendar, to get the correct size
+ if ((style & SWT.CALENDAR_WEEKNUMBERS) != 0) {
+ // get current style and add week numbers to the calendar drop-down
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ OS.SendMessage(handle, OS.DTM_SETMCSTYLE, 0, bits | OS.MCS_WEEKNUMBERS);
+ }
+ SIZE size = new SIZE ();
+ OS.SendMessage(handle, OS.DTM_GETIDEALSIZE, 0, size);
+ width = size.cx;
+ height = size.cy;
+ // TODO: Can maybe use DTM_GETDATETIMEPICKERINFO for this
+ int upDownHeight = OS.GetSystemMetrics (OS.SM_CYVSCROLL) + 7;
+ height = Math.max (height, upDownHeight);
+ }
+ }
+ if (width == 0) width = DEFAULT_WIDTH;
+ if (height == 0) height = DEFAULT_HEIGHT;
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ int border = getBorderWidthInPixels ();
+ width += border * 2;
+ height += border * 2;
+ return new Point (width, height);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state &= ~(CANVAS | THEME_BACKGROUND);
+
+ if ((style & SWT.BORDER) == 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ bits &= ~(OS.WS_EX_CLIENTEDGE | OS.WS_EX_STATICEDGE);
+ OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
+ }
+}
+
+@Override
+int defaultBackground () {
+ return OS.GetSysColor (OS.COLOR_WINDOW);
+}
+
+String getCustomShortDateFormat () {
+ TCHAR tchar = new TCHAR (getCodePage (), 80);
+ int size = OS.GetLocaleInfo (OS.LOCALE_USER_DEFAULT, OS.LOCALE_SYEARMONTH, tchar, 80);
+ return size != 0 ? tchar.toString (0, size - 1) : "M/yyyy"; //$NON-NLS-1$
+}
+
+String getCustomShortTimeFormat () {
+ StringBuilder buffer = new StringBuilder (getTimeFormat ());
+ int length = buffer.length ();
+ boolean inQuotes = false;
+ int start = 0, end = 0;
+ while (start < length) {
+ char ch = buffer.charAt (start);
+ if (ch == SINGLE_QUOTE) inQuotes = !inQuotes;
+ else if (ch == SECONDS_FORMAT_CONSTANT && !inQuotes) {
+ end = start + 1;
+ while (end < length && buffer.charAt (end) == SECONDS_FORMAT_CONSTANT) end++;
+ // skip the preceding separator
+ while (start > 0 && buffer.charAt (start) != MINUTES_FORMAT_CONSTANT) start--;
+ start++;
+ break;
+ }
+ start++;
+ }
+ if (start < end) buffer.delete (start, end);
+ return buffer.toString ();
+}
+
+String getTimeFormat () {
+ TCHAR tchar = new TCHAR (getCodePage (), 80);
+ int size = OS.GetLocaleInfo (OS.LOCALE_USER_DEFAULT, OS.LOCALE_STIMEFORMAT, tchar, 80);
+ return size > 0 ? tchar.toString (0, size - 1) : "h:mm:ss tt"; //$NON-NLS-1$
+}
+
+/**
+ * Returns the receiver's date, or day of the month.
+ *
+ *
+ */
+public int getDay () {
+ checkWidget ();
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ return systime.wDay;
+}
+
+/**
+ * Returns the receiver's hours.
+ *
+ *
+ */
+public int getHours () {
+ checkWidget ();
+ if ((style & SWT.CALENDAR) != 0) return time.wHour;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ return systime.wHour;
+}
+
+/**
+ * Returns the receiver's minutes.
+ *
+ *
+ */
+public int getMinutes () {
+ checkWidget ();
+ if ((style & SWT.CALENDAR) != 0) return time.wMinute;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ return systime.wMinute;
+}
+
+/**
+ * Returns the receiver's month.
+ *
+ *
+ */
+public int getMonth () {
+ checkWidget ();
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ return systime.wMonth - 1;
+}
+
+@Override
+String getNameText() {
+ return (style & SWT.TIME) != 0 ? getHours() + ":" + getMinutes() + ":" + getSeconds()
+ : (getMonth() + 1) + "/" + getDay() + "/" + getYear();
+}
+
+/**
+ * Returns the receiver's seconds.
+ *
+ *
+ */
+public int getSeconds () {
+ checkWidget ();
+ if ((style & SWT.CALENDAR) != 0) return time.wSecond;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ return systime.wSecond;
+}
+
+/**
+ * Returns the receiver's year.
+ *
+ *
+ */
+public int getYear () {
+ checkWidget ();
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ return systime.wYear;
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ lastSystemTime = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection, listener);
+}
+
+/**
+ * Sets the receiver's year, month, and day in a single operation.
+ *
+ *
+ *
+ * @since 3.4
+ */
+public void setDate (int year, int month, int day) {
+ checkWidget ();
+ if (year < MIN_YEAR || year > MAX_YEAR) return;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
+ systime.wYear = (short)year;
+ systime.wMonth = (short)(month + 1);
+ systime.wDay = (short)day;
+ OS.SendMessage (handle, msg, 0, systime);
+ lastSystemTime = null;
+}
+
+/**
+ * Sets the receiver's date, or day of the month, to the specified day.
+ *
+ *
+ *
+ * @see #setDate
+ */
+public void setDay (int day) {
+ checkWidget ();
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
+ systime.wDay = (short)day;
+ OS.SendMessage (handle, msg, 0, systime);
+ lastSystemTime = null;
+}
+
+/**
+ * Sets the receiver's hours.
+ *
+ *
+ */
+public void setHours (int hours) {
+ checkWidget ();
+ if (hours < 0 || hours > 23) return;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
+ systime.wHour = (short)hours;
+ OS.SendMessage (handle, msg, 0, systime);
+ if ((style & SWT.CALENDAR) != 0 && hours >= 0 && hours <= 23) time.wHour = (short)hours;
+}
+
+/**
+ * Sets the receiver's minutes.
+ *
+ *
+ */
+public void setMinutes (int minutes) {
+ checkWidget ();
+ if (minutes < 0 || minutes > 59) return;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
+ systime.wMinute = (short)minutes;
+ OS.SendMessage (handle, msg, 0, systime);
+ if ((style & SWT.CALENDAR) != 0 && minutes >= 0 && minutes <= 59) time.wMinute = (short)minutes;
+}
+
+/**
+ * Sets the receiver's month.
+ *
+ *
+ *
+ * @see #setDate
+ */
+public void setMonth (int month) {
+ checkWidget ();
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
+ systime.wMonth = (short)(month + 1);
+ OS.SendMessage (handle, msg, 0, systime);
+ lastSystemTime = null;
+}
+
+@Override
+public void setOrientation (int orientation) {
+ /* Currently supported only for CALENDAR style. */
+ if ((style & SWT.CALENDAR) != 0) super.setOrientation (orientation);
+}
+/**
+ * Sets the receiver's seconds.
+ *
+ *
+ */
+public void setSeconds (int seconds) {
+ checkWidget ();
+ if (seconds < 0 || seconds > 59) return;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
+ systime.wSecond = (short)seconds;
+ OS.SendMessage (handle, msg, 0, systime);
+ if ((style & SWT.CALENDAR) != 0 && seconds >= 0 && seconds <= 59) time.wSecond = (short)seconds;
+}
+
+/**
+ * Sets the receiver's hours, minutes, and seconds in a single operation.
+ *
+ * @param hours an integer between 0 and 23
+ * @param minutes an integer between 0 and 59
+ * @param seconds an integer between 0 and 59
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public void setTime (int hours, int minutes, int seconds) {
+ checkWidget ();
+ if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59) return;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
+ systime.wHour = (short)hours;
+ systime.wMinute = (short)minutes;
+ systime.wSecond = (short)seconds;
+ OS.SendMessage (handle, msg, 0, systime);
+ if ((style & SWT.CALENDAR) != 0
+ && hours >= 0 && hours <= 23
+ && minutes >= 0 && minutes <= 59
+ && seconds >= 0 && seconds <= 59) {
+ time.wHour = (short)hours;
+ time.wMinute = (short)minutes;
+ time.wSecond = (short)seconds;
+ }
+}
+
+/**
+ * Sets the receiver's year.
+ *
+ *
+ *
+ * @see #setDate
+ */
+public void setYear (int year) {
+ checkWidget ();
+ if (year < MIN_YEAR || year > MAX_YEAR) return;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME;
+ OS.SendMessage (handle, msg, 0, systime);
+ msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME;
+ systime.wYear = (short)year;
+ OS.SendMessage (handle, msg, 0, systime);
+ lastSystemTime = null;
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle () | OS.WS_TABSTOP;
+ if ((style & SWT.CALENDAR_WEEKNUMBERS) != 0) {
+ bits |= OS.MCS_WEEKNUMBERS;
+ }
+ if ((style & SWT.CALENDAR) != 0) return bits | OS.MCS_NOTODAY;
+ /*
+ * Bug in Windows: When WS_CLIPCHILDREN is set in a
+ * Date and Time Picker, the widget draws on top of
+ * the updown control. The fix is to clear the bits.
+ */
+ bits &= ~OS.WS_CLIPCHILDREN;
+ if ((style & SWT.TIME) != 0) bits |= OS.DTS_TIMEFORMAT;
+ if ((style & SWT.DATE) != 0) {
+ bits |= ((style & SWT.MEDIUM) != 0 ? OS.DTS_SHORTDATECENTURYFORMAT : OS.DTS_LONGDATEFORMAT);
+ if ((style & SWT.DROP_DOWN) == 0) bits |= OS.DTS_UPDOWN;
+ }
+ return bits;
+}
+
+@Override
+TCHAR windowClass () {
+ return (style & SWT.CALENDAR) != 0 ? CalendarClass : DateTimeClass;
+}
+
+@Override
+long windowProc () {
+ return (style & SWT.CALENDAR) != 0 ? CalendarProc : DateTimeProc;
+}
+
+@Override
+LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
+ switch (hdr.code) {
+ case OS.DTN_CLOSEUP: {
+ /*
+ * Feature in Windows. When the user selects the drop-down button,
+ * the DateTimePicker runs a modal loop and consumes WM_LBUTTONUP.
+ * This is done without adding a mouse capture. Since WM_LBUTTONUP
+ * is not delivered, the normal mechanism where a mouse capture is
+ * added on mouse down and removed when the mouse is released
+ * is broken, leaving an unwanted capture. The fix is to avoid
+ * setting capture on mouse down right after WM_LBUTTONUP is consumed.
+ */
+ display.captureChanged = true;
+ break;
+ }
+ case OS.MCN_SELCHANGE: {
+ if (ignoreSelection) break;
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ OS.SendMessage (handle, OS.MCM_GETCURSEL, 0, systime);
+ sendSelectionEvent (SWT.Selection);
+ break;
+ }
+ case OS.DTN_DATETIMECHANGE: {
+ SYSTEMTIME systime = new SYSTEMTIME ();
+ OS.SendMessage (handle, OS.DTM_GETSYSTEMTIME, 0, systime);
+ if (lastSystemTime == null || systime.wDay != lastSystemTime.wDay || systime.wMonth != lastSystemTime.wMonth || systime.wYear != lastSystemTime.wYear) {
+ sendSelectionEvent (SWT.Selection);
+ if ((style & SWT.TIME) == 0) lastSystemTime = systime;
+ }
+ break;
+ }
+ }
+ return super.wmNotifyChild (hdr, wParam, lParam);
+}
+
+@Override
+LRESULT WM_CHAR (long wParam, long lParam) {
+ LRESULT result = super.WM_CHAR (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. For some reason, when the
+ * user presses tab, return or escape, Windows beeps.
+ * The fix is to look for these keys and not call
+ * the window proc.
+ */
+ switch ((int)wParam) {
+ case SWT.CR:
+ sendSelectionEvent (SWT.DefaultSelection);
+ // FALL THROUGH
+ case SWT.TAB:
+ case SWT.ESC: return LRESULT.ZERO;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONDBLCLK (long wParam, long lParam) {
+ LRESULT result = super.WM_LBUTTONDBLCLK (wParam, lParam);
+ if (isDisposed ()) return LRESULT.ZERO;
+ if ((style & SWT.CALENDAR) != 0) {
+ MCHITTESTINFO pMCHitTest = new MCHITTESTINFO ();
+ pMCHitTest.cbSize = MCHITTESTINFO.sizeof;
+ POINT pt = new POINT ();
+ pt.x = OS.GET_X_LPARAM (lParam);
+ pt.y = OS.GET_Y_LPARAM (lParam);
+ pMCHitTest.pt = pt;
+ long code = OS.SendMessage (handle, OS.MCM_HITTEST, 0, pMCHitTest);
+ if ((code & OS.MCHT_CALENDARDATE) == OS.MCHT_CALENDARDATE) doubleClick = true;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
+ if (result == LRESULT.ZERO) return result;
+ doubleClick = false;
+ /*
+ * Feature in Windows. For some reason, the calendar control
+ * does not take focus on WM_LBUTTONDOWN. The fix is to
+ * explicitly set focus.
+ */
+ if ((style & SWT.CALENDAR) != 0) {
+ if ((style & SWT.NO_FOCUS) == 0) OS.SetFocus (handle);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONUP (long wParam, long lParam) {
+ LRESULT result = super.WM_LBUTTONUP (wParam, lParam);
+ if (isDisposed ()) return LRESULT.ZERO;
+ if (doubleClick) sendSelectionEvent (SWT.DefaultSelection);
+ doubleClick = false;
+ return result;
+}
+
+@Override
+LRESULT WM_TIMER (long wParam, long lParam) {
+ LRESULT result = super.WM_TIMER (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. For some reason, Windows sends WM_NOTIFY with
+ * MCN_SELCHANGE at regular intervals. This is unexpected. The fix is
+ * to ignore MCN_SELCHANGE during WM_TIMER.
+ */
+ ignoreSelection = true;
+ long code = callWindowProc(handle, OS.WM_TIMER, wParam, lParam);
+ ignoreSelection = false;
+ return code == 0 ? LRESULT.ZERO : new LRESULT(code);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Decorations.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Decorations.java
new file mode 100644
index 000000000..9c584ce36
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Decorations.java
@@ -0,0 +1,1710 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class provide the appearance and
+ * behavior of Shells
, but are not top
+ * level shells or dialogs. Class Shell
+ * shares a significant amount of code with this class,
+ * and is a subclass.
+ * Shell
should be used.
+ *
+ *
+ * Note: The styles supported by this class must be treated
+ * as HINTs, since the window manager for the
+ * desktop on which the instance is visible has ultimate
+ * control over the appearance and behavior of decorations.
+ * For example, some window managers only support resizable
+ * windows and will always assume the RESIZE style, even if
+ * it is not set.
+ * RESIZE
) until it is
+ * no longer maximized.
+ *
+ *
+ * Class SWT
provides two "convenience constants"
+ * for the most commonly required style combinations:
+ *
+ *
+ * SHELL_TRIM
CLOSE | TITLE | MIN | MAX | RESIZE
)
+ * DIALOG_TRIM
TITLE | CLOSE | BORDER
)
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#BORDER
+ * @see SWT#CLOSE
+ * @see SWT#MIN
+ * @see SWT#MAX
+ * @see SWT#RESIZE
+ * @see SWT#TITLE
+ * @see SWT#NO_TRIM
+ * @see SWT#NO_MOVE
+ * @see SWT#SHELL_TRIM
+ * @see SWT#DIALOG_TRIM
+ * @see SWT#ON_TOP
+ * @see SWT#TOOL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Decorations (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+void _setMaximized (boolean maximized) {
+ swFlags = maximized ? OS.SW_SHOWMAXIMIZED : OS.SW_RESTORE;
+ if (!OS.IsWindowVisible (handle)) return;
+ if (maximized == OS.IsZoomed (handle)) return;
+ OS.ShowWindow (handle, swFlags);
+ OS.UpdateWindow (handle);
+}
+
+void _setMinimized (boolean minimized) {
+ swFlags = minimized ? OS.SW_SHOWMINNOACTIVE : OS.SW_RESTORE;
+ if (!OS.IsWindowVisible (handle)) return;
+ if (minimized == OS.IsIconic (handle)) return;
+ int flags = swFlags;
+ if (flags == OS.SW_SHOWMINNOACTIVE && handle == OS.GetActiveWindow ()) {
+ flags = OS.SW_MINIMIZE;
+ }
+ OS.ShowWindow (handle, flags);
+ OS.UpdateWindow (handle);
+}
+
+void addMenu (Menu menu) {
+ if (menus == null) menus = new Menu [4];
+ for (int i=0; isetImage()
. The image is typically
+ * displayed by the window manager when the instance is
+ * marked as iconified, and may also be displayed somewhere
+ * in the trim when the instance is in normal or maximized
+ * states.
+ * setImage()
is called. It does not provide
+ * access to a window manager provided, "default" image
+ * even if one exists.
+ *
+ *
+ */
+public Image getImage () {
+ checkWidget ();
+ return image;
+}
+
+/**
+ * Returns the receiver's images if they had previously been
+ * set using setImages()
. Images are typically
+ * displayed by the window manager when the instance is
+ * marked as iconified, and may also be displayed somewhere
+ * in the trim when the instance is in normal or maximized
+ * states. Depending where the icon is displayed, the platform
+ * chooses the icon with the "best" attributes. It is expected
+ * that the array will contain the same icon rendered at different
+ * sizes, with different depth and transparency attributes.
+ *
+ * setImages()
is called. It does not provide
+ * access to a window manager provided, "default" image
+ * even if one exists.
+ *
+ *
+ *
+ * @since 3.0
+ */
+public Image [] getImages () {
+ checkWidget ();
+ if (images == null) return new Image [0];
+ Image [] result = new Image [images.length];
+ System.arraycopy (images, 0, result, 0, images.length);
+ return result;
+}
+
+@Override Point getLocationInPixels () {
+ checkWidget ();
+ if (OS.IsIconic (handle)) {
+ WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT ();
+ lpwndpl.length = WINDOWPLACEMENT.sizeof;
+ OS.GetWindowPlacement (handle, lpwndpl);
+ if ((lpwndpl.flags & OS.WPF_RESTORETOMAXIMIZED) != 0) {
+ return new Point (maxRect.left, maxRect.top);
+ }
+ return new Point (lpwndpl.left, lpwndpl.top);
+ }
+ return super.getLocationInPixels ();
+}
+
+/**
+ * Returns true
if the receiver is currently
+ * maximized, and false otherwise.
+ *
+ *
+ *
+ * @see #setMaximized
+ */
+public boolean getMaximized () {
+ checkWidget ();
+ if (OS.IsWindowVisible (handle)) return OS.IsZoomed (handle);
+ return swFlags == OS.SW_SHOWMAXIMIZED;
+}
+
+/**
+ * Returns the receiver's menu bar if one had previously
+ * been set, otherwise returns null.
+ *
+ * @return the menu bar or null
+ *
+ * @exception SWTException
+ *
+ */
+public Menu getMenuBar () {
+ checkWidget ();
+ return menuBar;
+}
+
+/**
+ * Returns true
if the receiver is currently
+ * minimized, and false otherwise.
+ *
+ *
+ *
+ * @see #setMinimized
+ */
+public boolean getMinimized () {
+ checkWidget ();
+ if (OS.IsWindowVisible (handle)) return OS.IsIconic (handle);
+ return swFlags == OS.SW_SHOWMINNOACTIVE;
+}
+
+@Override
+String getNameText () {
+ return getText ();
+}
+
+@Override Point getSizeInPixels () {
+ checkWidget ();
+ if (OS.IsIconic (handle)) {
+ WINDOWPLACEMENT lpwndpl = new WINDOWPLACEMENT ();
+ lpwndpl.length = WINDOWPLACEMENT.sizeof;
+ OS.GetWindowPlacement (handle, lpwndpl);
+ if ((lpwndpl.flags & OS.WPF_RESTORETOMAXIMIZED) != 0) {
+ int width = maxRect.right - maxRect.left;
+ int height = maxRect.bottom - maxRect.top;
+ return new Point (width, height);
+ }
+ int width = lpwndpl.right - lpwndpl.left;
+ int height = lpwndpl.bottom - lpwndpl.top;
+ return new Point (width, height);
+ }
+ return super.getSizeInPixels ();
+}
+
+/**
+ * Returns the receiver's text, which is the string that the
+ * window manager will typically display as the receiver's
+ * title. If the text has not previously been set,
+ * returns an empty string.
+ *
+ * @return the text
+ *
+ * @exception SWTException
+ *
+ */
+public String getText () {
+ checkWidget ();
+ int length = OS.GetWindowTextLength (handle);
+ if (length == 0) return "";
+ char [] buffer = new char [length + 1];
+ OS.GetWindowText (handle, buffer, length + 1);
+ return new String (buffer, 0, length);
+}
+
+@Override
+public boolean isReparentable () {
+ checkWidget ();
+ /*
+ * Feature in Windows. Calling SetParent() for a shell causes
+ * a kind of fake MDI to happen. It doesn't work well on Windows
+ * and is not supported on the other platforms. The fix is to
+ * disallow the SetParent().
+ */
+ return false;
+}
+
+@Override
+boolean isTabGroup () {
+ /*
+ * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX.
+ */
+ return true;
+}
+
+@Override
+boolean isTabItem () {
+ /*
+ * Can't test WS_TAB bits because they are the same as WS_MAXIMIZEBOX.
+ */
+ return false;
+}
+
+@Override
+Decorations menuShell () {
+ return this;
+}
+
+@Override
+void releaseChildren (boolean destroy) {
+ if (menuBar != null) {
+ menuBar.release (false);
+ menuBar = null;
+ }
+ super.releaseChildren (destroy);
+ if (menus != null) {
+ for (int i=0; i
+ *
+ * @exception SWTException
+ *
+ */
+public void setDefaultButton (Button button) {
+ checkWidget ();
+ if (button != null) {
+ if (button.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (button.menuShell () != this) error(SWT.ERROR_INVALID_PARENT);
+ }
+ setDefaultButton (button, true);
+}
+
+void setDefaultButton (Button button, boolean save) {
+ if (button == null) {
+ if (defaultButton == saveDefault) {
+ if (save) saveDefault = null;
+ return;
+ }
+ } else {
+ if ((button.style & SWT.PUSH) == 0) return;
+ if (button == defaultButton) {
+ if (save) saveDefault = defaultButton;
+ return;
+ }
+ }
+ if (defaultButton != null) {
+ if (!defaultButton.isDisposed ()) defaultButton.setDefault (false);
+ }
+ if ((defaultButton = button) == null) defaultButton = saveDefault;
+ if (defaultButton != null) {
+ if (!defaultButton.isDisposed ()) defaultButton.setDefault (true);
+ }
+ if (save) saveDefault = defaultButton;
+ if (saveDefault != null && saveDefault.isDisposed ()) saveDefault = null;
+}
+
+/**
+ * Sets the receiver's image to the argument, which may
+ * be null. The image is typically displayed by the window
+ * manager when the instance is marked as iconified, and
+ * may also be displayed somewhere in the trim when the
+ * instance is in normal or maximized states.
+ *
+ * @param image the new image (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setImage (Image image) {
+ checkWidget ();
+ if (image != null && image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ this.image = image;
+ setImages (image, null);
+}
+
+void setImages (Image image, Image [] images) {
+ if (smallImage != null) smallImage.dispose ();
+ if (largeImage != null) largeImage.dispose ();
+ smallImage = largeImage = null;
+ long hSmallIcon = 0, hLargeIcon = 0;
+ Image smallIcon = null, largeIcon = null;
+ if (image != null) {
+ smallIcon = largeIcon = image;
+ } else {
+ if (images != null && images.length > 0) {
+ int depth = display.getIconDepth ();
+ ImageData [] datas = null;
+ if (images.length > 1) {
+ Image [] bestImages = new Image [images.length];
+ System.arraycopy (images, 0, bestImages, 0, images.length);
+ datas = new ImageData [images.length];
+ for (int i=0; i
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.0
+ */
+public void setImages (Image [] images) {
+ checkWidget ();
+ if (images == null) error (SWT.ERROR_INVALID_ARGUMENT);
+ for (int i = 0; i < images.length; i++) {
+ if (images [i] == null || images [i].isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.images = images;
+ setImages (null, images);
+}
+
+/**
+ * Sets the maximized state of the receiver.
+ * If the argument is true
causes the receiver
+ * to switch to the maximized state, and if the argument is
+ * false
and the receiver was previously maximized,
+ * causes the receiver to switch back to either the minimized
+ * or normal states.
+ * setMaximized(true)
+ * and setMinimized(true)
will vary by platform. Typically,
+ * the behavior will match the platform user's expectations, but not
+ * always. This should be avoided if possible.
+ *
+ *
+ *
+ * @see #setMinimized
+ */
+public void setMaximized (boolean maximized) {
+ checkWidget ();
+ Display.lpStartupInfo = null;
+ _setMaximized (maximized);
+}
+
+/**
+ * Sets the receiver's menu bar to the argument, which
+ * may be null.
+ *
+ * @param menu the new menu bar
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setMenuBar (Menu menu) {
+ checkWidget ();
+ if (menuBar == menu) return;
+ if (menu != null) {
+ if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((menu.style & SWT.BAR) == 0) error (SWT.ERROR_MENU_NOT_BAR);
+ if (menu.parent != this) error (SWT.ERROR_INVALID_PARENT);
+ }
+ if (menu != null) display.removeBar (menu);
+ menuBar = menu;
+ long hMenu = menuBar != null ? menuBar.handle: 0;
+ OS.SetMenu (handle, hMenu);
+ destroyAccelerators ();
+}
+
+/**
+ * Sets the minimized stated of the receiver.
+ * If the argument is true
causes the receiver
+ * to switch to the minimized state, and if the argument is
+ * false
and the receiver was previously minimized,
+ * causes the receiver to switch back to either the maximized
+ * or normal states.
+ * setMaximized(true)
+ * and setMinimized(true)
will vary by platform. Typically,
+ * the behavior will match the platform user's expectations, but not
+ * always. This should be avoided if possible.
+ *
+ *
+ *
+ * @see #setMaximized
+ */
+public void setMinimized (boolean minimized) {
+ checkWidget ();
+ Display.lpStartupInfo = null;
+ _setMinimized (minimized);
+}
+
+@Override
+public void setOrientation (int orientation) {
+ super.setOrientation (orientation);
+ if (menus != null) {
+ for (int i=0; i
+ *
+ * @exception SWTException
+ *
+ */
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ /* Use the character encoding for the default locale */
+ TCHAR buffer = new TCHAR (0, string, true);
+ /* Ensure that the title appears in the task bar.*/
+ if ((state & FOREIGN_HANDLE) != 0) {
+ long hHeap = OS.GetProcessHeap ();
+ int byteCount = buffer.length () * TCHAR.sizeof;
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory (pszText, buffer, byteCount);
+ OS.DefWindowProc (handle, OS.WM_SETTEXT, 0, pszText);
+ if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
+ } else {
+ OS.SetWindowText (handle, buffer);
+ }
+ if ((state & HAS_AUTO_DIRECTION) != 0) {
+ updateTextDirection (AUTO_TEXT_DIRECTION);
+ }
+}
+
+@Override
+public void setVisible (boolean visible) {
+ checkWidget ();
+ if (!getDrawing()) {
+ if (((state & HIDDEN) == 0) == visible) return;
+ } else {
+ if (visible == OS.IsWindowVisible (handle)) return;
+ }
+ if (visible) {
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the show
+ * event. If this happens, just return.
+ */
+ sendEvent (SWT.Show);
+ if (isDisposed ()) return;
+ if (!getDrawing()) {
+ state &= ~HIDDEN;
+ } else {
+ if (menuBar != null) {
+ display.removeBar (menuBar);
+ OS.DrawMenuBar (handle);
+ }
+ STARTUPINFO lpStartUpInfo = Display.lpStartupInfo;
+ if (lpStartUpInfo != null && (lpStartUpInfo.dwFlags & OS.STARTF_USESHOWWINDOW) != 0) {
+ OS.ShowWindow (handle, lpStartUpInfo.wShowWindow);
+ } else {
+ OS.ShowWindow (handle, swFlags);
+ }
+ if (isDisposed ()) return;
+ opened = true;
+ if (!moved) {
+ moved = true;
+ Point location = getLocationInPixels ();
+ oldX = location.x;
+ oldY = location.y;
+ }
+ if (!resized) {
+ resized = true;
+ Rectangle rect = getClientAreaInPixels ();
+ oldWidth = rect.width;
+ oldHeight = rect.height;
+ }
+ /*
+ * Bug in Windows. On Vista using the Classic theme,
+ * when the window is hung and UpdateWindow() is called,
+ * nothing is drawn, and outstanding WM_PAINTs are cleared.
+ * This causes pixel corruption. The fix is to avoid calling
+ * update on hung windows.
+ */
+ if (OS.IsAppThemed () || !OS.IsHungAppWindow (handle)) {
+ OS.UpdateWindow (handle);
+ }
+ }
+ } else {
+ if (OS.IsIconic (handle)) {
+ swFlags = OS.SW_SHOWMINNOACTIVE;
+ } else {
+ if (OS.IsZoomed (handle)) {
+ swFlags = OS.SW_SHOWMAXIMIZED;
+ } else {
+ swFlags = OS.SW_SHOWNOACTIVATE;
+ }
+ }
+ if (!getDrawing()) {
+ state |= HIDDEN;
+ } else {
+ OS.ShowWindow (handle, OS.SW_HIDE);
+ }
+ if (isDisposed ()) return;
+ sendEvent (SWT.Hide);
+ }
+}
+
+void sort (Image [] images, ImageData [] datas, int width, int height, int depth) {
+ /* Shell Sort from K&R, pg 108 */
+ int length = images.length;
+ if (length <= 1) return;
+ for (int gap=length/2; gap>0; gap/=2) {
+ for (int i=gap; iDialog
typically contains other widgets
+ * that are not accessible. A Dialog
is not
+ * a Widget
.
+ *
+ *
+ * public class MyDialog extends Dialog {
+ * Object result;
+ *
+ * public MyDialog (Shell parent, int style) {
+ * super (parent, style);
+ * }
+ * public MyDialog (Shell parent) {
+ * this (parent, 0); // your default style bits go here (not the Shell's style bits)
+ * }
+ * public Object open () {
+ * Shell parent = getParent();
+ * Shell shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
+ * shell.setText(getText());
+ * // Your code goes here (widget creation, set result, etc).
+ * shell.open();
+ * Display display = parent.getDisplay();
+ * while (!shell.isDisposed()) {
+ * if (!display.readAndDispatch()) display.sleep();
+ * }
+ * return result;
+ * }
+ * }
+ *
PRIMARY_MODAL
+ * is not supported by a particular dialog, it would be upgraded to
+ * APPLICATION_MODAL
. In addition, as is the case
+ * for shells, the window manager for the desktop on which the
+ * instance is visible has ultimate control over the appearance
+ * and behavior of the instance, including its modality.
+ *
+ *
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public Dialog (Shell parent) {
+ this (parent, SWT.PRIMARY_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * @param parent a shell which will be the parent of the new instance
+ * @param style the style of dialog to construct
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#PRIMARY_MODAL
+ * @see SWT#APPLICATION_MODAL
+ * @see SWT#SYSTEM_MODAL
+ */
+public Dialog (Shell parent, int style) {
+ checkParent (parent);
+ this.parent = parent;
+ this.style = style;
+ title = "";
+}
+
+/**
+ * Checks that this class can be subclassed.
+ * Widget.checkSubclass()
.
+ *
+ *
+ *
+ * @see Widget#checkSubclass
+ */
+protected void checkSubclass () {
+ if (!Display.isValidClass (getClass ())) {
+ error (SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+
+/**
+ * Throws an exception if the specified widget can not be
+ * used as a parent for the receiver.
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+void checkParent (Shell parent) {
+ if (parent == null) error (SWT.ERROR_NULL_ARGUMENT);
+ parent.checkWidget ();
+}
+
+static int checkStyle (Shell parent, int style) {
+ int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
+ if ((style & SWT.SHEET) != 0) {
+ style &= ~SWT.SHEET;
+ if ((style & mask) == 0) {
+ style |= parent == null ? SWT.APPLICATION_MODAL : SWT.PRIMARY_MODAL;
+ }
+ }
+ if ((style & mask) == 0) {
+ style |= SWT.APPLICATION_MODAL;
+ }
+ style &= ~SWT.MIRRORED;
+ if ((style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)) == 0) {
+ if (parent != null) {
+ if ((parent.style & SWT.LEFT_TO_RIGHT) != 0) style |= SWT.LEFT_TO_RIGHT;
+ if ((parent.style & SWT.RIGHT_TO_LEFT) != 0) style |= SWT.RIGHT_TO_LEFT;
+ }
+ }
+ return Widget.checkBits (style, SWT.LEFT_TO_RIGHT, SWT.RIGHT_TO_LEFT, 0, 0, 0, 0);
+}
+
+/**
+ * Does whatever dialog specific cleanup is required, and then
+ * uses the code in SWTError.error
to handle the error.
+ *
+ * @param code the descriptive error code
+ *
+ * @see SWT#error(int)
+ */
+void error (int code) {
+ SWT.error(code);
+}
+
+/**
+ * Returns the receiver's parent, which must be a Shell
+ * or null.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException
+ *
+ */
+public Shell getParent () {
+ return parent;
+}
+
+/**
+ * Returns the receiver's style information.
+ *
+ *
+ */
+public int getStyle () {
+ return style;
+}
+
+/**
+ * Returns the receiver's text, which is the string that the
+ * window manager will typically display as the receiver's
+ * title. If the text has not previously been set,
+ * returns an empty string.
+ *
+ * @return the text
+ *
+ * @exception SWTException
+ *
+ */
+public String getText () {
+ return title;
+}
+
+/**
+ * Sets the receiver's text, which is the string that the
+ * window manager will typically display as the receiver's
+ * title, to the argument, which must not be null.
+ *
+ * @param string the new text
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setText (String string) {
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ title = string;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/DirectoryDialog.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/DirectoryDialog.java
new file mode 100644
index 000000000..60bda29cc
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/DirectoryDialog.java
@@ -0,0 +1,375 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Martin Karpisek
+ *
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public DirectoryDialog (Shell parent) {
+ this (parent, SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public DirectoryDialog (Shell parent, int style) {
+ super (parent, checkStyle (parent, style));
+ checkSubclass ();
+}
+
+long BrowseCallbackProc (long hwnd, long uMsg, long lParam, long lpData) {
+ switch ((int)uMsg) {
+ case OS.BFFM_INITIALIZED:
+ if (filterPath != null && filterPath.length () != 0) {
+ /* Use the character encoding for the default locale */
+ TCHAR buffer = new TCHAR (0, filterPath.replace ('/', '\\'), true);
+ OS.SendMessage (hwnd, OS.BFFM_SETSELECTION, 1, buffer);
+ }
+ if (title != null && title.length () != 0) {
+ /* Use the character encoding for the default locale */
+ TCHAR buffer = new TCHAR (0, title, true);
+ OS.SetWindowText (hwnd, buffer);
+ }
+ break;
+ case OS.BFFM_VALIDATEFAILED:
+ /* Use the character encoding for the default locale */
+ int length = OS.wcslen (lParam);
+ TCHAR buffer = new TCHAR (0, length);
+ int byteCount = buffer.length () * TCHAR.sizeof;
+ OS.MoveMemory (buffer, lParam, byteCount);
+ directoryPath = buffer.toString (0, length);
+ break;
+ }
+ return 0;
+}
+
+/**
+ * Returns the path which the dialog will use to filter
+ * the directories it shows.
+ *
+ * @return the filter path
+ *
+ * @see #setFilterPath
+ */
+public String getFilterPath () {
+ return filterPath;
+}
+
+/**
+ * Returns the dialog's message, which is a description of
+ * the purpose for which it was opened. This message will be
+ * visible on the dialog while it is open.
+ *
+ * @return the message
+ */
+public String getMessage () {
+ return message;
+}
+
+/**
+ * Makes the dialog visible and brings it to the front
+ * of the display.
+ *
+ * @return a string describing the absolute path of the selected directory,
+ * or null if the dialog was cancelled or an error occurred
+ *
+ * @exception SWTException
+ *
+ */
+public String open() {
+ if (OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
+ return openCommonItemDialog();
+ }
+ return openCommonFileDialog();
+}
+
+private String openCommonFileDialog () {
+ long hHeap = OS.GetProcessHeap ();
+
+ /* Get the owner HWND for the dialog */
+ long hwndOwner = 0;
+ if (parent != null) hwndOwner = parent.handle;
+
+ /* Copy the message to OS memory */
+ long lpszTitle = 0;
+ if (message.length () != 0) {
+ String string = message;
+ if (string.indexOf ('&') != -1) {
+ int length = string.length ();
+ char [] buffer = new char [length * 2];
+ int index = 0;
+ for (int i=0; iDirectoryDialog
+ * doesn't have any provision to set a message.
+ *
+ *
+ */
+public void setMessage (String string) {
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ message = string;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Display.java
new file mode 100644
index 000000000..832317961
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Display.java
@@ -0,0 +1,4985 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import java.net.*;
+import java.util.*;
+import java.util.function.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class are responsible for managing the
+ * connection between SWT and the underlying operating
+ * system. Their most important function is to implement
+ * the SWT event loop in terms of the platform event model.
+ * They also provide various methods for accessing information
+ * about the operating system, and have overall control over
+ * the operating system resources which SWT allocates.
+ * dispose()
message.
+ * Display
+ * instance is distinguished as the user-interface thread
+ * for that display.
+ *
+ *
+ * Widget
and its subclasses), may only be called
+ * from the thread. (To support multi-threaded user-interface
+ * applications, class Display
provides inter-thread
+ * communication methods which allow threads other than the
+ * user-interface thread to request that it perform operations
+ * on their behalf.)
+ * Display
s until that display has been disposed.
+ * (Note that, this is in addition to the restriction mentioned
+ * above concerning platform support for multiple displays. Thus,
+ * the only way to have multiple simultaneously active displays,
+ * even on platforms which support it, is to have multiple threads.)
+ * ERROR_THREAD_INVALID_ACCESS
"
+ * SWT exception.
+ *
+ *
+ *
+ *
+ *
+ * @see #getCurrent
+ * @see #getDefault
+ * @see Widget#checkSubclass
+ * @see Shell
+ */
+public Display () {
+ this (null);
+}
+
+/**
+ * Constructs a new instance of this class using the parameter.
+ *
+ * @param data the device data
+ */
+public Display (DeviceData data) {
+ super (data);
+}
+
+Control _getFocusControl () {
+ return findControl (OS.GetFocus ());
+}
+
+void addBar (Menu menu) {
+ if (bars == null) bars = new Menu [4];
+ int length = bars.length;
+ for (int i=0; iSWT
. When the event does occur,
+ * the listener is notified by sending it the handleEvent()
+ * message.
+ * SWT.None
from
+ * within the handleEvent()
method can be used to
+ * change the event type and stop subsequent Java listeners
+ * from running. Because event filters run before other listeners,
+ * event filters can both block other listeners and set arbitrary
+ * fields within an event. For this reason, event filters are both
+ * powerful and dangerous. They should generally be avoided for
+ * performance, debugging and code maintenance reasons.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Listener
+ * @see SWT
+ * @see #removeFilter
+ * @see #removeListener
+ *
+ * @since 3.0
+ */
+public void addFilter (int eventType, Listener listener) {
+ checkDevice ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (filterTable == null) filterTable = new EventTable ();
+ filterTable.hook (eventType, listener);
+}
+
+void addLayoutDeferred (Composite comp) {
+ if (layoutDeferred == null) layoutDeferred = new Composite [64];
+ if (layoutDeferredCount == layoutDeferred.length) {
+ Composite [] temp = new Composite [layoutDeferred.length + 64];
+ System.arraycopy (layoutDeferred, 0, temp, 0, layoutDeferred.length);
+ layoutDeferred = temp;
+ }
+ layoutDeferred[layoutDeferredCount++] = comp;
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when an event of the given type occurs. The event
+ * type is one of the event constants defined in class SWT
.
+ * When the event does occur in the display, the listener is notified by
+ * sending it the handleEvent()
message.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should be notified when the event occurs
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Listener
+ * @see SWT
+ * @see #removeListener
+ *
+ * @since 2.0
+ */
+public void addListener (int eventType, Listener listener) {
+ checkDevice ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) eventTable = new EventTable ();
+ eventTable.hook (eventType, listener);
+}
+
+void addMenuItem (MenuItem item) {
+ if (items == null) items = new MenuItem [64];
+ for (int i=0; inull
as the
+ * runnable simply wakes the user-interface thread when run.
+ * null
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #syncExec
+ */
+public void asyncExec (Runnable runnable) {
+ synchronized (Device.class) {
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+ synchronizer.asyncExec (runnable);
+ }
+}
+
+/**
+ * Causes the system hardware to emit a short sound
+ * (if it supports this capability).
+ *
+ * @exception SWTException
+ *
+ */
+public void beep () {
+ checkDevice ();
+ OS.MessageBeep (OS.MB_OK);
+}
+
+/**
+ * Checks that this class can be subclassed.
+ * Widget.checkSubclass()
.
+ *
+ *
+ *
+ * @see Widget#checkSubclass
+ */
+protected void checkSubclass () {
+ if (!isValidClass (getClass ())) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+@Override
+protected void checkDevice () {
+ if (thread == null) error (SWT.ERROR_WIDGET_DISPOSED);
+ if (thread != Thread.currentThread ()) {
+ /*
+ * Bug in IBM JVM 1.6. For some reason, under
+ * conditions that are yet to be full understood,
+ * Thread.currentThread() is either returning null
+ * or a different instance from the one that was
+ * saved when the Display was created. This is
+ * possibly a JIT problem because modifying this
+ * method to print logging information when the
+ * error happens seems to fix the problem. The
+ * fix is to use operating system calls to verify
+ * that the current thread is not the Display thread.
+ *
+ * NOTE: Despite the fact that Thread.currentThread()
+ * is used in other places, the failure has not been
+ * observed in all places where it is called.
+ */
+ if (threadId != OS.GetCurrentThreadId ()) {
+ error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ }
+ }
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+}
+
+static void checkDisplay (Thread thread, boolean multiple) {
+ synchronized (Device.class) {
+ for (int i=0; iinit
.
+ * release
.
+ *
run()
method of the runnable to
+ * be invoked by the user-interface thread just before the
+ * receiver is disposed. Specifying a null
runnable
+ * is ignored.
+ *
+ * @param runnable code to run at dispose time.
+ *
+ * @exception SWTException Widget
subclass which
+ * represents it in the currently running application, if
+ * such exists, or null if no matching widget can be found.
+ * + * IMPORTANT: This method should not be called from + * application code. The arguments are platform-specific. + *
+ * + * @param handle the handle for the widget + * @return the SWT widget that the handle represents + * + * @exception SWTExceptionWidget
subclass which represents
+ * the handle/id pair in the currently running application,
+ * if such exists, or null if no matching widget can be found.
+ * + * IMPORTANT: This method should not be called from + * application code. The arguments are platform-specific. + *
+ * + * @param handle the handle for the widget + * @param id the id for the subwidget (usually an item) + * @return the SWT widget that the handle/id pair represents + * + * @exception SWTExceptionWidget
subclass which represents
+ * the widget/id pair in the currently running application,
+ * if such exists, or null if no matching widget can be found.
+ *
+ * @param widget the widget
+ * @param id the id for the subwidget (usually an item)
+ * @return the SWT subwidget (usually an item) that the widget/id pair represents
+ *
+ * @exception SWTException null
as the thread will return null
+ * for the display.
+ *
+ * @param thread the user-interface thread
+ * @return the display for the given thread
+ */
+public static Display findDisplay (Thread thread) {
+ synchronized (Device.class) {
+ for (int i=0; inull
if there is no application menu bar for the platform.
+ *
+ * @return the application menu bar, or null
+ *
+ * @exception SWTException null
+ *
+ * @exception SWTException
+ * Applications may have associated arbitrary objects with the
+ * receiver in this fashion. If the objects stored in the
+ * properties need to be notified when the display is disposed
+ * of, it is the application's responsibility to provide a
+ * disposeExec()
handler which does so.
+ *
+ * Applications may put arbitrary objects in this field. If
+ * the object stored in the display specific data needs to
+ * be notified when the display is disposed of, it is the
+ * application's responsibility to provide a
+ * disposeExec()
handler which does so.
+ *
LEFT
or RIGHT
.
+ * The button dismissal alignment is the ordering that should be used when positioning the
+ * default dismissal button for a dialog. For example, in a dialog that contains an OK and
+ * CANCEL button, on platforms where the button dismissal alignment is LEFT
, the
+ * button ordering should be OK/CANCEL. When button dismissal alignment is RIGHT
,
+ * the button ordering should be CANCEL/OK.
+ *
+ * @return the button dismissal order
+ *
+ * @exception SWTException null
+ *
+ * @exception SWTException + * Note: This operation is a hint and is not supported on + * platforms that do not have this concept. + *
+ * + * @return the high contrast mode + * + * @exception SWTExceptiontrue
if the current OS theme has a dark appearance, else
+ * returns false
.
+ * + * Note: This operation is a hint and is not supported on platforms that do not + * have this concept. + *
+ *+ * Note: Windows 10 onwards users can separately configure the theme for OS and + * Application level and this can be read from the Windows registry. Since the + * application needs to honor the application level theme, this API reads the + * Application level theme setting. + *
+ * + * @returntrue
if the current OS theme has a dark appearance, else
+ * returns false
.
+ *
+ * @since 3.112
+ */
+public static boolean isSystemDarkTheme () {
+ boolean isDarkTheme = false;
+ /*
+ * Win10 onwards we can read the Dark Theme from the OS registry.
+ */
+ if (OS.WIN32_VERSION >= OS.VERSION (10, 0)) {
+ try {
+ int result = OS.readRegistryDword(OS.HKEY_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", "AppsUseLightTheme");
+ isDarkTheme = (result == 0);
+ } catch (Exception e) {
+ // Registry entry not found
+ }
+ }
+ return isDarkTheme;
+}
+
+int getLastEventTime () {
+ return OS.GetMessageTime ();
+}
+
+MenuItem getMenuItem (int id) {
+ if (items == null) return null;
+ id = id - ID_START;
+ if (0 <= id && id < items.length) return items [id];
+ return null;
+}
+
+int getMessageCount () {
+ /*
+ * On Windows10 (update 18272), an NPE is seen in below code which leads to a
+ * possible crash, adding a null check for synchronizer instance. For more
+ * details refer bug 540762
+ */
+ if (synchronizer != null) return synchronizer.getMessageCount ();
+ return 0;
+}
+
+
+Shell getModalShell () {
+ if (modalShells == null) return null;
+ int index = modalShells.length;
+ while (--index >= 0) {
+ Shell shell = modalShells [index];
+ if (shell != null) return shell;
+ }
+ return null;
+}
+
+Dialog getModalDialog () {
+ return modalDialog;
+}
+
+Monitor getMonitor (long hmonitor) {
+ MONITORINFO lpmi = new MONITORINFO ();
+ lpmi.cbSize = MONITORINFO.sizeof;
+ OS.GetMonitorInfo (hmonitor, lpmi);
+ Monitor monitor = new Monitor ();
+ monitor.handle = hmonitor;
+ Rectangle boundsInPixels = new Rectangle (lpmi.rcMonitor_left, lpmi.rcMonitor_top, lpmi.rcMonitor_right - lpmi.rcMonitor_left,lpmi.rcMonitor_bottom - lpmi.rcMonitor_top);
+ monitor.setBounds (DPIUtil.autoScaleDown (boundsInPixels));
+ Rectangle clientAreaInPixels = new Rectangle (lpmi.rcWork_left, lpmi.rcWork_top, lpmi.rcWork_right - lpmi.rcWork_left, lpmi.rcWork_bottom - lpmi.rcWork_top);
+ monitor.setClientArea (DPIUtil.autoScaleDown (clientAreaInPixels));
+ if (OS.WIN32_VERSION >= OS.VERSION (6, 3)) {
+ int [] dpiX = new int[1];
+ int [] dpiY = new int[1];
+ int result = OS.GetDpiForMonitor (monitor.handle, OS.MDT_EFFECTIVE_DPI, dpiX, dpiY);
+ result = (result == OS.S_OK) ? DPIUtil.mapDPIToZoom (dpiX[0]) : 100;
+ /*
+ * Always return true monitor zoom value as fetched from native, else will lead
+ * to scaling issue on OS Win8.1 and above, for more details refer bug 537614.
+ */
+ monitor.zoom = result;
+ } else {
+ monitor.zoom = getDeviceZoom ();
+ }
+ return monitor;
+}
+
+/**
+ * Returns an array of monitors attached to the device.
+ *
+ * @return the array of monitors
+ *
+ * @since 3.0
+ */
+public Monitor [] getMonitors () {
+ checkDevice ();
+ monitors = new Monitor [4];
+ Callback callback = new Callback (this, "monitorEnumProc", 4); //$NON-NLS-1$
+ long lpfnEnum = callback.getAddress ();
+ if (lpfnEnum == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ OS.EnumDisplayMonitors (0, null, lpfnEnum, 0);
+ callback.dispose ();
+ Monitor [] result = new Monitor [monitorCount];
+ System.arraycopy (monitors, 0, result, 0, monitorCount);
+ monitors = null;
+ monitorCount = 0;
+ return result;
+}
+
+long getMsgProc (long code, long wParam, long lParam) {
+ if (embeddedHwnd == 0) {
+ long hInstance = OS.GetModuleHandle (null);
+ embeddedHwnd = OS.CreateWindowEx (0,
+ windowClass,
+ null,
+ OS.WS_OVERLAPPED,
+ 0, 0, 0, 0,
+ 0,
+ 0,
+ hInstance,
+ null);
+ embeddedCallback = new Callback (this, "embeddedProc", 4); //$NON-NLS-1$
+ embeddedProc = embeddedCallback.getAddress ();
+ if (embeddedProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ OS.SetWindowLongPtr (embeddedHwnd, OS.GWLP_WNDPROC, embeddedProc);
+ }
+ if (code >= 0 && (wParam & OS.PM_REMOVE) != 0) {
+ MSG msg = new MSG ();
+ OS.MoveMemory (msg, lParam, MSG.sizeof);
+ switch (msg.message) {
+ case OS.WM_KEYDOWN:
+ case OS.WM_KEYUP:
+ case OS.WM_SYSKEYDOWN:
+ case OS.WM_SYSKEYUP: {
+ Control control = findControl (msg.hwnd);
+ if (control != null) {
+ long hHeap = OS.GetProcessHeap ();
+ long keyMsg = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, MSG.sizeof);
+ OS.MoveMemory (keyMsg, msg, MSG.sizeof);
+ OS.PostMessage (hwndMessage, SWT_KEYMSG, wParam, keyMsg);
+ switch ((int)msg.wParam) {
+ case OS.VK_SHIFT:
+ case OS.VK_MENU:
+ case OS.VK_CONTROL:
+ case OS.VK_CAPITAL:
+ case OS.VK_NUMLOCK:
+ case OS.VK_SCROLL:
+ break;
+ default:
+ msg.message = OS.WM_NULL;
+ OS.MoveMemory (lParam, msg, MSG.sizeof);
+ }
+ }
+ }
+ }
+ }
+ return OS.CallNextHookEx (msgHook, (int)code, wParam, lParam);
+}
+
+/**
+ * Returns the primary monitor for that device.
+ *
+ * @return the primary monitor
+ *
+ * @since 3.0
+ */
+public Monitor getPrimaryMonitor () {
+ checkDevice ();
+ long hmonitor = OS.MonitorFromWindow (0, OS.MONITOR_DEFAULTTOPRIMARY);
+ return getMonitor (hmonitor);
+}
+
+/**
+ * Returns a (possibly empty) array containing all shells which have
+ * not been disposed and have the receiver as their display.
+ *
+ * @return the receiver's shells
+ *
+ * @exception SWTException syncExec
+ * or null if no such runnable is currently being invoked by
+ * the user-interface thread.
+ * + * Note: If a runnable invoked by asyncExec is currently + * running, this method will return null. + *
+ * + * @return the receiver's sync-interface thread + * + * @exception SWTExceptionSWT
. Any value other
+ * than one of the SWT color constants which is passed
+ * in will result in the color black. This color should
+ * not be free'd because it was allocated by the system,
+ * not the application.
+ *
+ * @param id the color constant
+ * @return the matching color
+ *
+ * @exception SWTException SWT
. This cursor should
+ * not be free'd because it was allocated by the system,
+ * not the application. A value of null
will
+ * be returned if the supplied constant is not an SWT cursor
+ * constant.
+ *
+ * @param id the SWT cursor constant
+ * @return the corresponding cursor or null
+ *
+ * @exception SWTException + * Typically, applications which want the default look + * should simply not set the font on the widgets they + * create. Widgets are always created with the correct + * default font for the class of user-interface component + * they represent. + *
+ * + * @return a font + * + * @exception SWTExceptionSWT
. This image should
+ * not be free'd because it was allocated by the system,
+ * not the application. A value of null
will
+ * be returned either if the supplied constant is not an
+ * SWT icon constant or if the platform does not define an
+ * image that corresponds to the constant.
+ *
+ * @param id the SWT icon constant
+ * @return the corresponding image or null
+ *
+ * @exception SWTException null
on platforms where no menu is provided for the application.
+ *
+ * @return the system menu, or null
+ *
+ * @exception SWTException null
+ *
+ * @exception SWTException null
+ *
+ * @exception SWTException true
if a touch-aware input device is detected, or false
otherwise
+ *
+ * @exception SWTException
+ * IMPORTANT: This method is not part of the public
+ * API for Display
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ * This method is called after create
.
+ *
Display
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ *
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ */
+@Override
+public void internal_dispose_GC (long hDC, GCData data) {
+ OS.ReleaseDC (0, hDC);
+}
+
+boolean isXMouseActive () {
+ /*
+ * NOTE: X-Mouse is active when bit 1 of the UserPreferencesMask is set.
+ */
+ boolean xMouseActive = false;
+ try {
+ int result = OS.readRegistryDword(OS.HKEY_CURRENT_USER, "Control Panel\\Desktop", "UserPreferencesMask");
+ xMouseActive = (result & 0x01) != 0;
+ } catch (Exception e) {
+ // Registry entry not found
+ }
+ return xMouseActive;
+}
+
+boolean isValidThread () {
+ return thread == Thread.currentThread ();
+}
+
+/**
+ * Maps a point from one coordinate system to another.
+ * When the control is null, coordinates are mapped to
+ * the display.
+ * + * NOTE: On right-to-left platforms where the coordinate + * systems are mirrored, special care needs to be taken + * when mapping coordinates from one control to another + * to ensure the result is correctly mirrored. + * + * Mapping a point that is the origin of a rectangle and + * then adding the width and height is not equivalent to + * mapping the rectangle. When one control is mirrored + * and the other is not, adding the width and height to a + * point that was mapped causes the rectangle to extend + * in the wrong direction. Mapping the entire rectangle + * instead of just one point causes both the origin and + * the corner of the rectangle to be mapped. + *
+ * + * @param from the sourceControl
or null
+ * @param to the destination Control
or null
+ * @param point to be mapped
+ * @return point with mapped coordinates
+ *
+ * @exception IllegalArgumentException + * NOTE: On right-to-left platforms where the coordinate + * systems are mirrored, special care needs to be taken + * when mapping coordinates from one control to another + * to ensure the result is correctly mirrored. + * + * Mapping a point that is the origin of a rectangle and + * then adding the width and height is not equivalent to + * mapping the rectangle. When one control is mirrored + * and the other is not, adding the width and height to a + * point that was mapped causes the rectangle to extend + * in the wrong direction. Mapping the entire rectangle + * instead of just one point causes both the origin and + * the corner of the rectangle to be mapped. + *
+ * + * @param from the sourceControl
or null
+ * @param to the destination Control
or null
+ * @param x coordinates to be mapped
+ * @param y coordinates to be mapped
+ * @return point with mapped coordinates
+ *
+ * @exception IllegalArgumentException + * NOTE: On right-to-left platforms where the coordinate + * systems are mirrored, special care needs to be taken + * when mapping coordinates from one control to another + * to ensure the result is correctly mirrored. + * + * Mapping a point that is the origin of a rectangle and + * then adding the width and height is not equivalent to + * mapping the rectangle. When one control is mirrored + * and the other is not, adding the width and height to a + * point that was mapped causes the rectangle to extend + * in the wrong direction. Mapping the entire rectangle + * instead of just one point causes both the origin and + * the corner of the rectangle to be mapped. + *
+ * + * @param from the sourceControl
or null
+ * @param to the destination Control
or null
+ * @param rectangle to be mapped
+ * @return rectangle with mapped coordinates
+ *
+ * @exception IllegalArgumentException + * NOTE: On right-to-left platforms where the coordinate + * systems are mirrored, special care needs to be taken + * when mapping coordinates from one control to another + * to ensure the result is correctly mirrored. + * + * Mapping a point that is the origin of a rectangle and + * then adding the width and height is not equivalent to + * mapping the rectangle. When one control is mirrored + * and the other is not, adding the width and height to a + * point that was mapped causes the rectangle to extend + * in the wrong direction. Mapping the entire rectangle + * instead of just one point causes both the origin and + * the corner of the rectangle to be mapped. + *
+ * + * @param from the sourceControl
or null
+ * @param to the destination Control
or null
+ * @param x coordinates to be mapped
+ * @param y coordinates to be mapped
+ * @param width coordinates to be mapped
+ * @param height coordinates to be mapped
+ * @return rectangle with mapped coordinates
+ *
+ * @exception IllegalArgumentException post
is used to generate low level keyboard
+ * and mouse events. The intent is to enable automated UI
+ * testing by simulating the input from the user. Most
+ * SWT applications should never need to call this method.
+ * + * Note that this operation can fail when the operating system + * fails to generate the event for any reason. For example, + * this can happen when there is no such key or mouse button + * or when the system event queue is full. + *
+ *+ * Event Types: + *
KeyDown, KeyUp + *
The following fields in the Event
apply:
+ *
Either one of:
+ *SWT
Optional (on some platforms):
+ *SWT
+ * MouseDown, MouseUp
+ *The following fields in the Event
apply:
+ *
MouseMove
+ *The following fields in the Event
apply:
+ *
MouseWheel
+ *The following fields in the Event
apply:
true
+ * if there is potentially more work to do, or false
+ * if the caller can sleep until another event is placed on
+ * the event queue.
+ *
+ * In addition to checking the system event queue, this method also
+ * checks if any inter-thread messages (created by syncExec()
+ * or asyncExec()
) are waiting to be processed, and if
+ * so handles them before returning.
+ *
false
if the caller can sleep upon return from this method
+ *
+ * @exception SWTException true
when sent the message
+ * isDisposed()
.
+ *
+ * When a device is destroyed, resources that were acquired
+ * on behalf of the programmer need to be returned to the
+ * operating system. For example, if the device allocated a
+ * font to be used as the system font, this font would be
+ * freed in release
. Also,to assist the garbage
+ * collector and minimize the amount of memory that is not
+ * reclaimed when the programmer keeps a reference to a
+ * disposed device, all fields except the handle are zero'd.
+ * The handle is needed by destroy
.
+ *
destroy
.
+ *
+ * @see Device#dispose
+ * @see #destroy
+ */
+@Override
+protected void release () {
+ sendEvent (SWT.Dispose, new Event ());
+ Shell [] shells = getShells ();
+ for (int i=0; iSWT
.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ * Applications may have associated arbitrary objects with the
+ * receiver in this fashion. If the objects stored in the
+ * properties need to be notified when the display is disposed
+ * of, it is the application's responsibility provide a
+ * disposeExec()
handler which does so.
+ *
+ * Applications may put arbitrary objects in this field. If
+ * the object stored in the display specific data needs to
+ * be notified when the display is disposed of, it is the
+ * application's responsibility provide a
+ * disposeExec()
handler which does so.
+ *
+ * The application name can be used in several ways, + * depending on the platform and tools being used. + * Accessibility tools could ask for the application + * name. On Windows, if the application name is set + * to any value other than "SWT" (case insensitive), + * it is used to set the application user model ID + * which is used by the OS for taskbar grouping. + * @see AppUserModelID (Windows) + *
+ * Specifying null
for the name clears it.
+ *
null
+ */
+public static void setAppName (String name) {
+ APP_NAME = name;
+}
+
+/**
+ * Sets the application version to the argument.
+ *
+ * @param version the new app version
+ *
+ * @since 3.6
+ */
+public static void setAppVersion (String version) {
+ APP_VERSION = version;
+}
+
+void setModalDialog (Dialog modalDailog) {
+ this.modalDialog = modalDailog;
+ Shell [] shells = getShells ();
+ for (int i=0; i
+ * The default SWT error handling policy is to rethrow exceptions.
+ *
+ * @param runtimeExceptionHandler new exception handler to be registered.
+ * @since 3.106
+ */
+public final void setRuntimeExceptionHandler (Consumer
+ * The default SWT error handling policy is to rethrow exceptions.
+ *
+ * @param errorHandler new error handler to be registered.
+ * @since 3.106
+ */
+public final void setErrorHandler (Consumer
+ * Note that at the time the runnable is invoked, widgets
+ * that have the receiver as their display may have been
+ * disposed. Therefore, it is necessary to check for this
+ * case inside the runnable before accessing the widget.
+ *
+ * Note that at the time the runnable is invoked, widgets
+ * that have the receiver as their display may have been
+ * disposed. Therefore, it is necessary to check for this
+ * case inside the runnable before accessing the widget.
+ *
+ * Note: For a given event, only the fields which are appropriate
+ * will be filled in. The contents of the fields which are not used
+ * by the event are unspecified.
+ *
+ * The location field can be used to differentiate key events that have
+ * the same key code and character but are generated by different keys
+ * in the keyboard. For example, a key down event with the key code equals
+ * to SWT.SHIFT can be generated by the left and the right shift keys in the
+ * keyboard. The location field can only be used to determine the location
+ * of the key code or character in the current event. It does not
+ * include information about the location of modifiers in state
+ * mask.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: Only one of the styles SAVE and OPEN may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * This is an index into the FilterExtensions array and
+ * the FilterNames array.
+ *
+ * The strings are platform specific. For example, on
+ * some platforms, an extension filter string is typically
+ * of the form "*.extension", where "*.*" matches all files.
+ * For filters with multiple extensions, use semicolon as
+ * a separator, e.g. "*.jpg;*.png".
+ *
+ * Note: On Mac, setting the file extension filter affects how
+ * app bundles are treated by the dialog. When a filter extension
+ * having the app extension (.app) is selected, bundles are treated
+ * as files. For all other extension filters, bundles are treated
+ * as directories. When no filter extension is set, bundles are
+ * treated as files.
+ *
+ * This is an index into the FilterExtensions array and
+ * the FilterNames array.
+ *
+ * Each name is a user-friendly short description shown for
+ * its corresponding filter. The
+ * Note that the path string is platform dependent.
+ * For convenience, either '/' or '\' can be used
+ * as a path separator.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * If the platform's font dialog does not have any effects selection controls,
+ * then this method always returns false.
+ *
+ * By default the effects selection controls are displayed if the
+ * platform font dialog supports effects selection.
+ *
+ * Shadow styles are hints and may not be honoured
+ * by the platform. To create a group with the
+ * default shadow style for the platform, do not
+ * specify a shadow style.
+ *
+ * Note: Only one of the above styles may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Mnemonics are indicated by an '&' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, focus is assigned
+ * to the first child of the group. On most platforms, the
+ * mnemonic appears underlined but may be emphasised in a
+ * platform specific manner. The mnemonic indicator character
+ * '&' can be escaped by doubling it in the string, causing
+ * a single '&' to be displayed.
+ *
+ * Note: If control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * The ranges array contains start and end pairs. Each pair refers to
+ * the corresponding style in the styles array. For example, the pair
+ * that starts at ranges[n] and ends at ranges[n+1] uses the style
+ * at styles[n/2] returned by
+ * The ranges array contains start and end pairs. Each pair refers to
+ * the corresponding style in the styles array. For example, the pair
+ * that starts at ranges[n] and ends at ranges[n+1] uses the style
+ * at styles[n/2].
+ *
+ * The text for an IME is the characters in the widget that
+ * are in the current composition. When the commit count is
+ * equal to the length of the composition text, then the
+ * in-line edit operation is complete.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: If control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ * Shadow styles are hints and may not be honored
+ * by the platform. To create a separator label
+ * with the default shadow style for the platform,
+ * do not specify a shadow style.
+ *
+ * Note: Only one of SHADOW_IN, SHADOW_OUT and SHADOW_NONE may be specified.
+ * SHADOW_NONE is a HINT. Only one of HORIZONTAL and VERTICAL may be specified.
+ * Only one of CENTER, LEFT and RIGHT may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * This method sets the widget label. The label may include
+ * the mnemonic character and line delimiters.
+ *
+ * Mnemonics are indicated by an '&' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, focus is assigned
+ * to the control that follows the label. On most platforms,
+ * the mnemonic appears underlined but may be emphasised in a
+ * platform specific manner. The mnemonic indicator character
+ * '&' can be escaped by doubling it in the string, causing
+ * a single '&' to be displayed.
+ *
+ * Note: If control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ * This method computes the size that the client area
+ * of the composite must be in order to position all
+ * children at their preferred size inside the
+ * composite according to the layout algorithm
+ * encoded by this layout.
+ *
+ * When a width or height hint is supplied, it is
+ * used to constrain the result. For example, if a
+ * width hint is provided that is less than the
+ * width of the client area, the layout may choose
+ * to wrap and increase height, clip, overlap, or
+ * otherwise constrain the children.
+ *
+ * This method positions and sizes the children of a
+ * composite using the layout algorithm encoded by this
+ * layout. Children of the composite are positioned in
+ * the client area of the composite. The position of
+ * the composite is not altered by this method.
+ *
+ * When the flush cache hint is true, the layout is
+ * instructed to flush any cached values associated
+ * with the children. Typically, a layout will cache
+ * the preferred sizes of the children to avoid the
+ * expense of computing these values each time the
+ * widget is laid out.
+ *
+ * When layout is triggered explicitly by the programmer
+ * the flush cache hint is true. When layout is triggered
+ * by a resize, either caused by the programmer or by the
+ * user, the hint is false.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ *
+ * Note: This operation is a hint and may be overridden by the platform.
+ *
+ * The string can contain both regular text and hyperlinks. A hyperlink
+ * is delimited by an anchor tag, <a> and </a>. Within an
+ * anchor, a single HREF attribute is supported. When a hyperlink is
+ * selected, the text field of the selection event contains either the
+ * text of the hyperlink or the value of its HREF, if one was specified.
+ * In the rare case of identical hyperlinks within the same string, the
+ * HREF attribute can be used to distinguish between them. The string may
+ * include the mnemonic character and line delimiters. The only delimiter
+ * the HREF attribute supports is the quotation mark ("). Text containing
+ * angle-bracket characters < or > may be escaped using \\, however
+ * this operation is a hint and varies from platform to platform.
+ *
+ * Mnemonics are indicated by an '&' that causes the next
+ * character to be the mnemonic. The receiver can have a
+ * mnemonic in the text preceding each link. When the user presses a
+ * key sequence that matches the mnemonic, focus is assigned
+ * to the link that follows the text. Mnemonics in links and in
+ * the trailing text are ignored. On most platforms,
+ * the mnemonic appears underlined but may be emphasised in a
+ * platform specific manner. The mnemonic indicator character
+ * '&' can be escaped by doubling it in the string, causing
+ * a single '&' to be displayed.
+ *
+ * Note: Only one of SINGLE and MULTI may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: If control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ * Note: To add an item at the end of the list, use the
+ * result of calling
+ * Also note, if control characters like '\n', '\t' etc. are used
+ * in the string, then the behavior is platform dependent.
+ *
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ *
+ * The list is searched starting at 0 until an
+ * item is found that is equal to the search item.
+ * If no item is found, -1 is returned. Indexing
+ * is zero based.
+ *
+ * @param string the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException
+ * If the item at a given index is not selected, it is selected.
+ * If the item at a given index was already selected, it remains selected.
+ * Indices that are out of range and duplicate indices are ignored.
+ * If the receiver is single-select and multiple indices are specified,
+ * then all indices are ignored.
+ *
+ * @param indices the array of indices for the items to select
+ *
+ * @exception IllegalArgumentException
+ * If an item in the given range is not selected, it is selected.
+ * If an item in the given range was already selected, it remains selected.
+ * Indices that are out of range are ignored and no items will be selected
+ * if start is greater than end.
+ * If the receiver is single-select and there is more than one item in the
+ * given range, then all indices are ignored.
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception SWTException
+ * If the receiver is single-select, do nothing.
+ *
+ * @exception SWTException
+ * Items that are not in the receiver are ignored.
+ * If the receiver is single-select and multiple items are specified,
+ * then all items are ignored.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException
+ * Indices that are out of range are ignored and no items will be selected
+ * if start is greater than end.
+ * If the receiver is single-select and there is more than one item in the
+ * given range, then all indices are ignored.
+ *
+ * @param start the start index of the items to select
+ * @param end the end index of the items to select
+ *
+ * @exception SWTException
+ * After creating an instance of a class that implements this interface
+ * it can be added to a widget using the
+ *
+ * Classes which implement this interface are described within SWT as
+ * providing the untyped listener API. Typically, widgets will
+ * also provide a higher-level typed listener API, that is based
+ * on the standard
+ * Note that, since all internal SWT event dispatching is based on untyped
+ * listeners, it is simple to build subsets of SWT for use on memory
+ * constrained, small footprint devices, by removing the classes and
+ * methods which implement the typed listener API.
+ *
+ * Note: Only one of BAR, DROP_DOWN and POP_UP may be specified.
+ * Only one of LEFT_TO_RIGHT or RIGHT_TO_LEFT may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * IMPORTANT: This field is not part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ *
+ * After constructing a menu, it can be set into its parent
+ * using
+ * The style value is either one of the style constants defined in
+ * class
+ * After constructing a menu or menuBar, it can be set into its parent
+ * using
+ * After constructing a drop-down menu, it can be set into its parentMenu
+ * using
+ * After constructing a drop-down menu, it can be set into its parentItem
+ * using
+ * Note that the bounds of a menu or menu item are undefined when
+ * the menu is not visible. This is because most platforms compute
+ * the bounds of a menu dynamically just before it is displayed.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ *
+ * Note that this is different from most widgets where the
+ * location of the widget is relative to the parent.
+ *
+ * Also note that the actual location of the menu is dependent
+ * on platform specific behavior. For example: on Linux with
+ * Wayland this operation is a hint due to lack of global
+ * coordinates.
+ *
+ * Note that this is different from most widgets where the
+ * location of the widget is relative to the parent.
+ *
+ * Note that the platform window manager ultimately has control
+ * over the location of popup menus.
+ *
+ *
+ * @param orientation new orientation style
+ *
+ * @exception SWTException
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ *
+ * Note: Only one of the styles CHECK, CASCADE, PUSH, RADIO and SEPARATOR
+ * may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * The style value is either one of the style constants defined in
+ * class
+ * When
+ * When the
+ * When the receiver is of type
+ * Note: This operation is a HINT and is not supported on
+ * platforms that do not have this concept (for example, Windows NT).
+ * Furthermore, some platforms (such as GTK2), cannot display both
+ * a check box and an image at the same time. Instead, they hide
+ * the image and display the check box. Some platforms (such as GTK3)
+ * support images alongside check boxes.
+ *
+ * Note: Disposing of a menu item that has a pull down menu
+ * will dispose of the menu. To avoid this behavior, set the
+ * menu to null before the menu item is disposed.
+ *
+ * When the receiver is of type
+ * Mnemonics are indicated by an '&' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, a selection
+ * event occurs. On most platforms, the mnemonic appears
+ * underlined but may be emphasised in a platform specific
+ * manner. The mnemonic indicator character '&' can be
+ * escaped by doubling it in the string, causing a single
+ * '&' to be displayed.
+ *
+ * Accelerator text is indicated by the '\t' character.
+ * On platforms that support accelerator text, the text
+ * that follows the '\t' character is displayed to the user,
+ * typically indicating the key stroke that will cause
+ * the item to become selected. On most platforms, the
+ * accelerator text appears right aligned in the menu.
+ * Setting the accelerator text does not install the
+ * accelerator key sequence. The accelerator key sequence
+ * is installed using #setAccelerator.
+ *
+ * The mnemonic indicator (character '&') is not displayed in a tool tip.
+ * To display a single '&' in the tool tip, the character '&' can be
+ * escaped by doubling it in the string.
+ *
+ * NOTE: Tooltips are currently not shown for top-level menu items in the
+ * {@link Shell#setMenuBar(Menu) shell menubar} on Windows, Mac, and Ubuntu Unity desktop.
+ *
+ * NOTE: This operation is a hint and behavior is platform specific, on Windows
+ * for CJK-style mnemonics of the form " (&C)" at the end of the tooltip text
+ * are not shown in tooltip.
+ *
+ * Note: Only one of the styles ICON_ERROR, ICON_INFORMATION, ICON_QUESTION,
+ * ICON_WARNING and ICON_WORKING may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept.
+ *
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * When
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ *
+ * At any given moment, a given scroll bar will have a
+ * single 'selection' that is considered to be its
+ * value, which is constrained to be within the range of
+ * values the scroll bar represents (that is, between its
+ * minimum and maximum values).
+ *
+ * Typically, scroll bars will be made up of five areas:
+ * Based on their style, scroll bars are either
+ * On some platforms, the size of the scroll bar's thumb can be
+ * varied relative to the magnitude of the range of values it
+ * represents (that is, relative to the difference between its
+ * maximum and minimum values). Typically, this is used to
+ * indicate some proportional value such as the ratio of the
+ * visible area of a document to the total amount of space that
+ * it would take to display it. SWT supports setting the thumb
+ * size even if the underlying platform does not, but in this
+ * case the appearance of the scroll bar will not change.
+ *
+ * Scroll bars are created by specifying either
+ * Note: Scroll bars are not Controls. On some platforms, scroll bars
+ * that appear as part of some standard controls such as a text or list
+ * have no operating system resources and are not children of the control.
+ * For this reason, scroll bars are treated specially. To create a control
+ * that looks like a scroll bar but has operating system resources, use
+ *
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * When
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ *
+ * This new value will be ignored if it is less than one, and will be
+ * clamped if it exceeds the receiver's current range.
+ *
+ * Note: This is similar to setting the values individually
+ * using the appropriate methods, but may be implemented in a
+ * more efficient fashion on some platforms.
+ *
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ *
+ * IMPORTANT: This class is intended to be subclassed only
+ * within the SWT implementation.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * In other words, it returns a rectangle such that, if the
+ * receiver's bounds were set to that rectangle, the area
+ * of the receiver which is capable of displaying data
+ * (that is, not covered by the "trimmings") would be the
+ * rectangle described by the arguments (relative to the
+ * receiver's parent).
+ *
+ * Instances are always displayed in one of the maximized,
+ * minimized or normal states:
+ * The modality of an instance may be specified using
+ * style bits. The modality style bits are used to determine
+ * whether input is blocked for other shells on the display.
+ * The
+ * Note: The styles supported by this class are treated
+ * as HINTs, since the window manager for the
+ * desktop on which the instance is visible has ultimate
+ * control over the appearance and behavior of decorations
+ * and modality. For example, some window managers only
+ * support resizable windows and will always assume the
+ * RESIZE style, even if it is not set. In addition, if a
+ * modality style is not supported, it is "upgraded" to a
+ * more restrictive modality style that is supported. For
+ * example, if
+ * Class
+ * Note: Only one of the styles APPLICATION_MODAL, MODELESS,
+ * PRIMARY_MODAL and SYSTEM_MODAL may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: Currently, null can be passed in for the display argument.
+ * This has the effect of creating the shell on the currently active
+ * display if there is one. If there is no current display, the
+ * shell is created on a "default" display. Passing in null as
+ * the display argument is not considered to be good coding style,
+ * and may not be supported in a future release of SWT.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: Currently, null can be passed in for the display argument.
+ * This has the effect of creating the shell on the currently active
+ * display if there is one. If there is no current display, the
+ * shell is created on a "default" display. Passing in null as
+ * the display argument is not considered to be good coding style,
+ * and may not be supported in a future release of SWT.
+ *
+ * Note: Currently, null can be passed in for the parent.
+ * This has the effect of creating the shell on the currently active
+ * display if there is one. If there is no current display, the
+ * shell is created on a "default" display. Passing in null as
+ * the parent is not considered to be good coding style,
+ * and may not be supported in a future release of SWT.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * Note: Currently, null can be passed in for the parent.
+ * This has the effect of creating the shell on the currently active
+ * display if there is one. If there is no current display, the
+ * shell is created on a "default" display. Passing in null as
+ * the parent is not considered to be good coding style,
+ * and may not be supported in a future release of SWT.
+ *
+ * IMPORTANT: This method is not part of the public
+ * API for
+ * IMPORTANT: This method is not part of the public
+ * API for
+ *
+ * @return the fullscreen state
+ *
+ * @exception SWTException
+ * @return the dialog shells
+ *
+ * @exception SWTException
+ *
+ * @return a ToolBar object representing the Shell's tool bar, or
+ * This operation requires the operating system's advanced
+ * widgets subsystem which may not be available on some
+ * platforms.
+ *
+ * Note: The result of intermixing calls to
+ * NOTE: This method also sets the size of the shell. Clients should
+ * not call {@link #setSize} or {@link #setBounds} on this shell.
+ * Furthermore, the passed region should not be modified any more.
+ *
+ * At any given moment, a given slider will have a
+ * single 'selection' that is considered to be its
+ * value, which is constrained to be within the range of
+ * values the slider represents (that is, between its
+ * minimum and maximum values).
+ *
+ * Typically, sliders will be made up of five areas:
+ *
+ * Based on their style, sliders are either
+ * On some platforms, the size of the slider's thumb can be
+ * varied relative to the magnitude of the range of values it
+ * represents (that is, relative to the difference between its
+ * maximum and minimum values). Typically, this is used to
+ * indicate some proportional value such as the ratio of the
+ * visible area of a document to the total amount of space that
+ * it would take to display it. SWT supports setting the thumb
+ * size even if the underlying platform does not, but in this
+ * case the appearance of the slider will not change.
+ *
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * When
+ * This new value will be ignored if it is less than one, and will be
+ * clamped if it exceeds the receiver's current range.
+ *
+ * Note: This is similar to setting the values individually
+ * using the appropriate methods, but may be implemented in a
+ * more efficient fashion on some platforms.
+ *
+ * Note that although this class is a subclass of
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ *
+ * The current selection is copied to the clipboard.
+ *
+ * The current selection is first copied to the
+ * clipboard and then deleted from the widget.
+ *
+ * The selected text is deleted from the widget
+ * and new text inserted from the clipboard.
+ *
+ * The digit setting is used to allow for floating point values in the receiver.
+ * For example, to set the selection to a floating point value of 1.37 call setDigits() with
+ * a value of 2 and setSelection() with a value of 137. Similarly, if getDigits() has a value
+ * of 2 and getSelection() returns 137 this should be interpreted as 1.37. This applies to all
+ * numeric APIs.
+ *
+ * To reset this value to the default, use
+ * Note: This is similar to setting the values individually
+ * using the appropriate methods, but may be implemented in a
+ * more efficient fashion on some platforms.
+ *
+ * IMPORTANT: Typical application code never
+ * needs to deal with this class. It is provided only to
+ * allow applications which require non-standard
+ * synchronization behavior to plug in the support they
+ * require. Subclasses which override the methods in
+ * this class must ensure that the superclass methods are
+ * invoked in their implementations
+ *
+ * The item children that may be added to instances of this class
+ * must be of type
+ * Note that although this class is a subclass of
+ * Note: Only one of the styles TOP and BOTTOM may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * When
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * The style value is either one of the style constants defined in
+ * class
+ * @return the control
+ *
+ * @exception SWTException
+ * @param control the new control (or null)
+ *
+ * @exception IllegalArgumentException
+ * Mnemonics are indicated by an '&' that causes the next
+ * character to be the mnemonic. When the user presses a
+ * key sequence that matches the mnemonic, a selection
+ * event occurs. On most platforms, the mnemonic appears
+ * underlined but may be emphasised in a platform specific
+ * manner. The mnemonic indicator character '&' can be
+ * escaped by doubling it in the string, causing a single
+ * '&' to be displayed.
+ *
+ * The mnemonic indicator (character '&') is not displayed in a tool tip.
+ * To display a single '&' in the tool tip, the character '&' can be
+ * escaped by doubling it in the string.
+ *
+ * NOTE: This operation is a hint and behavior is platform specific, on Windows
+ * for CJK-style mnemonics of the form " (&C)" at the end of the tooltip text
+ * are not shown in tooltip.
+ *
+ * The item children that may be added to instances of this class
+ * must be of type
+ * Style
+ * Here is an example of using a
+ * Note that although this class is a subclass of
+ * Note: Only one of the styles SINGLE, and MULTI may be specified.
+ *
+ * IMPORTANT: This class is not intended to be subclassed.
+ *
+ * The style value is either one of the style constants defined in
+ * class
+ * When
+ * Specifically, the indices of the returned array represent
+ * the current visual order of the items, and the contents
+ * of the array represent the creation order of the items.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ *
+ * The item that is returned represents an item that could be selected by the user.
+ * For example, if selection only occurs in items in the first column, then null is
+ * returned if the point is outside of the item.
+ * Note that the SWT.FULL_SELECTION style hint, which specifies the selection policy,
+ * determines the extent of the selection.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ *
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ *
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its selection, so modifying the array will
+ * not affect the receiver.
+ *
+ * If the item at a given index is not selected, it is selected.
+ * If the item at a given index was already selected, it remains selected.
+ * Indices that are out of range and duplicate indices are ignored.
+ * If the receiver is single-select and multiple indices are specified,
+ * then all indices are ignored.
+ *
+ * If an item in the given range is not selected, it is selected.
+ * If an item in the given range was already selected, it remains selected.
+ * Indices that are out of range are ignored and no items will be selected
+ * if start is greater than end.
+ * If the receiver is single-select and there is more than one item in the
+ * given range, then all indices are ignored.
+ *
+ * If the receiver is single-select, do nothing.
+ * null
.
+ * @since 3.106
+ */
+public final Consumernull
.
+ * @since 3.106
+ */
+public final Consumertrue
if an event requiring dispatching was placed on the queue.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #wake
+ */
+public boolean sleep () {
+ checkDevice ();
+ if (getMessageCount () != 0) return true;
+ sendPreExternalEventDispatchEvent ();
+ boolean result = OS.WaitMessage ();
+ sendPostExternalEventDispatchEvent ();
+ return result;
+}
+
+/**
+ * Causes the run()
method of the runnable to
+ * be invoked by the user-interface thread at the next
+ * reasonable opportunity. The thread which calls this method
+ * is suspended until the runnable completes. Specifying null
+ * as the runnable simply wakes the user-interface thread.
+ * null
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #asyncExec
+ */
+public void syncExec (Runnable runnable) {
+ Synchronizer synchronizer;
+ synchronized (Device.class) {
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+ synchronizer = this.synchronizer;
+ }
+ synchronizer.syncExec (runnable);
+}
+
+/**
+ * Causes the run()
method of the runnable to
+ * be invoked by the user-interface thread after the specified
+ * number of milliseconds have elapsed. If milliseconds is less
+ * than zero, the runnable is not executed.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #asyncExec
+ */
+public void timerExec (int milliseconds, Runnable runnable) {
+ checkDevice ();
+ if (runnable == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (timerList == null) timerList = new Runnable [4];
+ if (timerIds == null) timerIds = new long [4];
+ int index = 0;
+ while (index < timerList.length) {
+ if (timerList [index] == runnable) break;
+ index++;
+ }
+ long timerId = 0;
+ if (index != timerList.length) {
+ timerId = timerIds [index];
+ if (milliseconds < 0) {
+ OS.KillTimer (hwndMessage, timerId);
+ timerList [index] = null;
+ timerIds [index] = 0;
+ return;
+ }
+ } else {
+ if (milliseconds < 0) return;
+ index = 0;
+ while (index < timerList.length) {
+ if (timerList [index] == null) break;
+ index++;
+ }
+ timerId = nextTimerId++;
+ if (index == timerList.length) {
+ Runnable [] newTimerList = new Runnable [timerList.length + 4];
+ System.arraycopy (timerList, 0, newTimerList, 0, timerList.length);
+ timerList = newTimerList;
+ long [] newTimerIds = new long [timerIds.length + 4];
+ System.arraycopy (timerIds, 0, newTimerIds, 0, timerIds.length);
+ timerIds = newTimerIds;
+ }
+ }
+ long newTimerID = OS.SetTimer (hwndMessage, timerId, milliseconds, 0);
+ if (newTimerID != 0) {
+ timerList [index] = runnable;
+ timerIds [index] = newTimerID;
+ }
+}
+
+boolean translateAccelerator (MSG msg, Control control) {
+ accelKeyHit = true;
+ boolean result = control.translateAccelerator (msg);
+ accelKeyHit = false;
+ return result;
+}
+
+static int translateKey (int key) {
+ for (int i=0; i
+ *
+ *
+ * @see #sleep
+ */
+public void wake () {
+ synchronized (Device.class) {
+ if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+ if (thread == Thread.currentThread ()) return;
+ wakeThread ();
+ }
+}
+
+void wakeThread () {
+ OS.PostThreadMessage (threadId, OS.WM_NULL, 0, 0);
+}
+
+long windowProc (long hwnd, long msg, long wParam, long lParam) {
+ if (lastControl != null && lastHwnd == hwnd) {
+ return lastControl.windowProc (hwnd, (int)msg, wParam, lParam);
+ }
+ int index = (int)OS.GetProp (hwnd, SWT_OBJECT_INDEX) - 1;
+ if (0 <= index && index < controlTable.length) {
+ Control control = controlTable [index];
+ if (control != null) {
+ lastHwnd = hwnd;
+ lastControl = control;
+ return control.windowProc (hwnd, (int)msg, wParam, lParam);
+ }
+ }
+ return OS.DefWindowProc (hwnd, (int)msg, wParam, lParam);
+}
+
+int textWidth (String text, long handle) {
+ long oldFont = 0;
+ RECT rect = new RECT ();
+ long hDC = OS.GetDC (handle);
+ long newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
+ char [] buffer = text.toCharArray ();
+ OS.DrawText (hDC, buffer, buffer.length, rect, flags);
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ return (rect.right - rect.left);
+}
+
+String wrapText (String text, long handle, int width) {
+ String Lf = "\r\n"; //$NON-NLS-1$
+ text = withCrLf (text);
+ int length = text.length ();
+ if (width <= 0 || length == 0 || length == 1) return text;
+ StringBuilder result = new StringBuilder ();
+ int lineStart = 0, lineEnd = 0;
+ while (lineStart < length) {
+ lineEnd = text.indexOf (Lf, lineStart);
+ boolean noLf = lineEnd == -1;
+ if (noLf) lineEnd = length;
+ int nextStart = lineEnd + Lf.length ();
+ while (lineEnd > lineStart + 1 && Character.isWhitespace (text.charAt (lineEnd - 1))) {
+ lineEnd--;
+ }
+ int wordStart = lineStart, wordEnd = lineStart;
+ int i = lineStart;
+ while (i < lineEnd) {
+ int lastStart = wordStart, lastEnd = wordEnd;
+ wordStart = i;
+ while (i < lineEnd && !Character.isWhitespace (text.charAt (i))) {
+ i++;
+ }
+ wordEnd = i - 1;
+ String line = text.substring (lineStart, wordEnd + 1);
+ int lineWidth = textWidth (line, handle);
+ while (i < lineEnd && Character.isWhitespace (text.charAt (i))) {
+ i++;
+ }
+ if (lineWidth > width) {
+ if (lastStart == wordStart) {
+ while (wordStart < wordEnd) {
+ line = text.substring (lineStart, wordStart + 1);
+ lineWidth = textWidth (line, handle);
+ if (lineWidth >= width) break;
+ wordStart++;
+ }
+ if (wordStart == lastStart) wordStart++;
+ lastEnd = wordStart - 1;
+ }
+ line = text.substring (lineStart, lastEnd + 1);
+ result.append (line); result.append (Lf);
+ i = wordStart; lineStart = wordStart; wordEnd = wordStart;
+ }
+ }
+ if (lineStart < lineEnd) {
+ result.append (text.substring (lineStart, lineEnd));
+ }
+ if (!noLf) {
+ result.append (Lf);
+ }
+ lineStart = nextStart;
+ }
+ return result.toString ();
+}
+
+static String withCrLf (String string) {
+
+ /* If the string is empty, return the string. */
+ int length = string.length ();
+ if (length == 0) return string;
+
+ /*
+ * Check for an LF or CR/LF and assume the rest of
+ * the string is formated that way. This will not
+ * work if the string contains mixed delimiters.
+ */
+ int i = string.indexOf ('\n', 0);
+ if (i == -1) return string;
+ if (i > 0 && string.charAt (i - 1) == '\r') {
+ return string;
+ }
+
+ /*
+ * The string is formatted with LF. Compute the
+ * number of lines and the size of the buffer
+ * needed to hold the result
+ */
+ i++;
+ int count = 1;
+ while (i < length) {
+ if ((i = string.indexOf ('\n', i)) == -1) break;
+ count++; i++;
+ }
+ count += length;
+
+ /* Create a new string with the CR/LF line terminator. */
+ i = 0;
+ StringBuilder result = new StringBuilder (count);
+ while (i < length) {
+ int j = string.indexOf ('\n', i);
+ if (j == -1) j = length;
+ result.append (string.substring (i, j));
+ if ((i = j) < length) {
+ result.append ("\r\n"); //$NON-NLS-1$
+ i++;
+ }
+ }
+ return result.toString ();
+}
+
+static char [] withCrLf (char [] string) {
+ /* If the string is empty, return the string. */
+ int length = string.length;
+ if (length == 0) return string;
+
+ /*
+ * Check for an LF or CR/LF and assume the rest of
+ * the string is formated that way. This will not
+ * work if the string contains mixed delimiters.
+ * Also, compute the number of lines.
+ */
+ int count = 0;
+ for (int i = 0; i < string.length; i++) {
+ if (string [i] == '\n') {
+ count++;
+ if (count == 1 && i > 0 && string [i - 1] == '\r') return string;
+ }
+ }
+ if (count == 0) return string;
+
+ /*
+ * The string is formatted with LF.
+ */
+ count += length;
+
+ /* Create a new string with the CR/LF line terminator. */
+ char [] result = new char [count];
+ for (int i = 0, j = 0; i < length && j < count; i++) {
+ if (string [i] == '\n') {
+ result [j++] = '\r';
+ }
+ result [j++] = string [i];
+ }
+
+ return result;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Event.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Event.java
new file mode 100644
index 000000000..a6181d683
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Event.java
@@ -0,0 +1,323 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+
+/**
+ * Instances of this class provide a description of a particular
+ * event which occurred within SWT. The SWT untyped listener
+ * API uses these instances for all event dispatching.
+ * SWT
+ *
+ * @see org.eclipse.swt.SWT
+ */
+ public int type;
+
+ /**
+ * the event specific detail field, as defined by the detail constants
+ * in class SWT
+ *
+ * @see org.eclipse.swt.SWT
+ */
+ public int detail;
+
+ /**
+ * the item that the event occurred in (can be null)
+ */
+ public Widget item;
+
+ /**
+ * the index of the item where the event occurred
+ *
+ * @since 3.2
+ */
+ public int index;
+
+ /**
+ * the graphics context to use when painting
+ * that is configured to use the colors, font and
+ * damaged region of the control. It is valid
+ * only during the paint and must not be disposed
+ */
+ public GC gc;
+
+ /**
+ * depending on the event type, the x offset of the bounding
+ * rectangle of the region that requires painting or the
+ * widget-relative, x coordinate of the pointer at the
+ * time the mouse button was pressed or released
+ */
+ public int x;
+
+ /**
+ * depending on the event type, the y offset of the bounding
+ * rectangle of the region that requires painting or the
+ * widget-relative, y coordinate of the pointer at the
+ * time the mouse button was pressed or released
+ */
+ public int y;
+
+ /**
+ * the width of the bounding rectangle of the
+ * region that requires painting
+ */
+ public int width;
+
+ /**
+ * the height of the bounding rectangle of the
+ * region that requires painting
+ */
+ public int height;
+
+ /**
+ * depending on the event type, the number of following
+ * paint events that are pending which may always be zero
+ * on some platforms, or the number of lines or pages to
+ * scroll using the mouse wheel, or the number of times the
+ * mouse has been clicked
+ */
+ public int count;
+
+ /**
+ * the time that the event occurred.
+ *
+ * NOTE: This field is an unsigned integer and should
+ * be AND'ed with 0xFFFFFFFFL so that it can be treated
+ * as a signed long.
+ */
+ public int time;
+
+ /**
+ * the button that was pressed or released; 1 for the
+ * first button, 2 for the second button, and 3 for the
+ * third button, etc.
+ */
+ public int button;
+
+ /**
+ * depending on the event, the character represented by the key
+ * that was typed. This is the final character that results
+ * after all modifiers have been applied. For example, when the
+ * user types Ctrl+A, the character value is 0x01 (ASCII SOH).
+ * It is important that applications do not attempt to modify the
+ * character value based on a stateMask (such as SWT.CTRL) or the
+ * resulting character will not be correct.
+ */
+ public char character;
+
+ /**
+ * depending on the event, the key code of the key that was typed,
+ * as defined by the key code constants in class SWT
.
+ * When the character field of the event is ambiguous, this field
+ * contains the unaffected value of the original character. For
+ * example, typing Ctrl+M or Enter both result in the character '\r'
+ * but the keyCode field will also contain '\r' when Enter was typed
+ * and 'm' when Ctrl+M was typed.
+ *
+ * @see org.eclipse.swt.SWT
+ */
+ public int keyCode;
+
+ /**
+ * depending on the event, the location of key specified by the
+ * keyCode or character. The possible values for this field are
+ * SWT.LEFT
, SWT.RIGHT
, SWT.KEYPAD
,
+ * or SWT.NONE
representing the main keyboard area.
+ * ExpandItem
.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#V_SCROLL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ExpandBar (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when an item in the receiver is expanded or collapsed
+ * by sending it one of the messages defined in the ExpandListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ExpandListener
+ * @see #removeExpandListener
+ */
+public void addExpandListener (ExpandListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Expand, typedListener);
+ addListener (SWT.Collapse, typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+static int checkStyle (int style) {
+ style &= ~SWT.H_SCROLL;
+ return style | SWT.NO_BACKGROUND;
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ int height = 0, width = 0;
+ if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
+ if (itemCount > 0) {
+ long hDC = OS.GetDC (handle);
+ long hTheme = 0;
+ if (isAppThemed ()) {
+ hTheme = display.hExplorerBarTheme ();
+ }
+ long hCurrentFont = 0, oldFont = 0;
+ if (hTheme == 0) {
+ if (hFont != 0) {
+ hCurrentFont = hFont;
+ } else {
+ NONCLIENTMETRICS info = new NONCLIENTMETRICS ();
+ info.cbSize = NONCLIENTMETRICS.sizeof;
+ if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) {
+ LOGFONT logFont = info.lfCaptionFont;
+ hCurrentFont = OS.CreateFontIndirect (logFont);
+ }
+ }
+ if (hCurrentFont != 0) {
+ oldFont = OS.SelectObject (hDC, hCurrentFont);
+ }
+ }
+ height += spacing;
+ for (int i = 0; i < itemCount; i++) {
+ ExpandItem item = items [i];
+ height += item.getHeaderHeightInPixels ();
+ if (item.expanded) height += item.height;
+ height += spacing;
+ width = Math.max (width, item.getPreferredWidth (hTheme, hDC));
+ }
+ if (hCurrentFont != 0) {
+ OS.SelectObject (hDC, oldFont);
+ if (hCurrentFont != hFont) OS.DeleteObject (hCurrentFont);
+ }
+ OS.ReleaseDC (handle, hDC);
+ }
+ }
+ if (width == 0) width = DEFAULT_WIDTH;
+ if (height == 0) height = DEFAULT_HEIGHT;
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ Rectangle trim = computeTrimInPixels (0, 0, width, height);
+ return new Point (trim.width, trim.height);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state &= ~CANVAS;
+ state |= TRACK_MOUSE;
+}
+
+void createItem (ExpandItem item, int style, int index) {
+ if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ if (itemCount == items.length) {
+ ExpandItem [] newItems = new ExpandItem [itemCount + 4];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ System.arraycopy (items, index, items, index + 1, itemCount - index);
+ items [index] = item;
+ itemCount++;
+ if (focusItem == null) focusItem = item;
+
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ item.width = Math.max (0, rect.right - rect.left - spacing * 2);
+ layoutItems (index, true);
+}
+
+@Override
+void createWidget () {
+ super.createWidget ();
+ items = new ExpandItem [4];
+ if (!isAppThemed ()) {
+ backgroundMode = SWT.INHERIT_DEFAULT;
+ }
+}
+
+@Override
+int defaultBackground() {
+ if (!isAppThemed ()) {
+ return OS.GetSysColor (OS.COLOR_WINDOW);
+ }
+ return super.defaultBackground();
+}
+
+void destroyItem (ExpandItem item) {
+ int index = 0;
+ while (index < itemCount) {
+ if (items [index] == item) break;
+ index++;
+ }
+ if (index == itemCount) return;
+ if (item == focusItem) {
+ int focusIndex = index > 0 ? index - 1 : 1;
+ if (focusIndex < itemCount) {
+ focusItem = items [focusIndex];
+ focusItem.redraw (true);
+ } else {
+ focusItem = null;
+ }
+ }
+ System.arraycopy (items, index + 1, items, index, --itemCount - index);
+ items [itemCount] = null;
+ item.redraw (true);
+ layoutItems (index, true);
+}
+
+@Override
+void drawThemeBackground (long hDC, long hwnd, RECT rect) {
+ RECT rect2 = new RECT ();
+ OS.GetClientRect (handle, rect2);
+ OS.MapWindowPoints (handle, hwnd, rect2, 2);
+ OS.DrawThemeBackground (display.hExplorerBarTheme (), hDC, OS.EBP_NORMALGROUPBACKGROUND, 0, rect2, null);
+}
+
+void drawWidget (GC gc, RECT clipRect) {
+ long hTheme = 0;
+ if (isAppThemed ()) {
+ hTheme = display.hExplorerBarTheme ();
+ }
+ if (hTheme != 0) {
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ OS.DrawThemeBackground (hTheme, gc.handle, OS.EBP_HEADERBACKGROUND, 0, rect, clipRect);
+ } else {
+ drawBackground (gc.handle);
+ }
+ boolean drawFocus = false;
+ if (handle == OS.GetFocus ()) {
+ int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
+ drawFocus = (uiState & OS.UISF_HIDEFOCUS) == 0;
+ }
+ long hCurrentFont = 0, oldFont = 0;
+ if (hTheme == 0) {
+ if (hFont != 0) {
+ hCurrentFont = hFont;
+ } else {
+ NONCLIENTMETRICS info = new NONCLIENTMETRICS ();
+ info.cbSize = NONCLIENTMETRICS.sizeof;
+ if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) {
+ LOGFONT logFont = info.lfCaptionFont;
+ hCurrentFont = OS.CreateFontIndirect (logFont);
+ }
+ }
+ if (hCurrentFont != 0) {
+ oldFont = OS.SelectObject (gc.handle, hCurrentFont);
+ }
+ if (foreground != -1) {
+ OS.SetTextColor (gc.handle, foreground);
+ }
+ }
+ for (int i = 0; i < itemCount; i++) {
+ ExpandItem item = items[i];
+ item.drawItem (gc, hTheme, clipRect, item == focusItem && drawFocus);
+ }
+ if (hCurrentFont != 0) {
+ OS.SelectObject (gc.handle, oldFont);
+ if (hCurrentFont != hFont) OS.DeleteObject (hCurrentFont);
+ }
+}
+
+@Override
+Control findBackgroundControl () {
+ Control control = super.findBackgroundControl ();
+ if (!isAppThemed ()) {
+ if (control == null) control = this;
+ }
+ return control;
+}
+
+@Override
+Control findThemeControl () {
+ return isAppThemed () ? this : super.findThemeControl ();
+}
+
+int getBandHeight () {
+ long hDC = OS.GetDC (handle);
+ long oldHFont = OS.SelectObject (hDC, hFont == 0 ? defaultFont () : hFont);
+ TEXTMETRIC lptm = new TEXTMETRIC ();
+ OS.GetTextMetrics (hDC, lptm);
+ OS.SelectObject (hDC, oldHFont);
+ OS.ReleaseDC (handle, hDC);
+ return Math.max (ExpandItem.CHEVRON_SIZE, lptm.tmHeight + 4);
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public ExpandItem getItem (int index) {
+ checkWidget ();
+ if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
+ return items [index];
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemCount () {
+ checkWidget ();
+ return itemCount;
+}
+
+/**
+ * Returns an array of ExpandItem
s which are the items
+ * in the receiver.
+ *
+ *
+ */
+public ExpandItem [] getItems () {
+ checkWidget ();
+ ExpandItem [] result = new ExpandItem [itemCount];
+ System.arraycopy (items, 0, result, 0, itemCount);
+ return result;
+}
+
+/**
+ * Returns the receiver's spacing.
+ *
+ * @return the spacing
+ *
+ * @exception SWTException
+ *
+ */
+public int getSpacing () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getSpacingInPixels ());
+}
+
+int getSpacingInPixels () {
+ return spacing;
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public int indexOf (ExpandItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i = 0; i < itemCount; i++) {
+ if (items [i] == item) return i;
+ }
+ return -1;
+}
+
+boolean isAppThemed () {
+ if (background != -1) return false;
+ if (foreground != -1) return false;
+ if (hFont != 0) return false;
+ return OS.IsAppThemed ();
+}
+
+void layoutItems (int index, boolean setScrollbar) {
+ if (index < itemCount) {
+ int y = spacing - yCurrentScroll;
+ for (int i = 0; i < index; i++) {
+ ExpandItem item = items [i];
+ if (item.expanded) y += item.height;
+ y += item.getHeaderHeightInPixels () + spacing;
+ }
+ for (int i = index; i < itemCount; i++) {
+ ExpandItem item = items [i];
+ item.setBoundsInPixels (spacing, y, 0, 0, true, false);
+ if (item.expanded) y += item.height;
+ y += item.getHeaderHeightInPixels () + spacing;
+ }
+ }
+ if (setScrollbar) setScrollbar ();
+}
+
+@Override
+void releaseChildren (boolean destroy) {
+ if (items != null) {
+ for (int i=0; i
+ *
+ *
+ * @see ExpandListener
+ * @see #addExpandListener
+ */
+public void removeExpandListener (ExpandListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Expand, listener);
+ eventTable.unhook (SWT.Collapse, listener);
+}
+
+@Override
+void reskinChildren (int flags) {
+ if (items != null) {
+ for (int i=0; i
+ *
+ */
+public void setSpacing (int spacing) {
+ checkWidget ();
+ setSpacingInPixels(DPIUtil.autoScaleUp(spacing));
+}
+
+void setSpacingInPixels (int spacing) {
+ if (spacing < 0) return;
+ if (spacing == this.spacing) return;
+ this.spacing = spacing;
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ int width = Math.max (0, (rect.right - rect.left) - spacing * 2);
+ for (int i = 0; i < itemCount; i++) {
+ ExpandItem item = items[i];
+ if (item.width != width) item.setBoundsInPixels (0, 0, width, item.height, false, true);
+ }
+ layoutItems (0, true);
+ OS.InvalidateRect (handle, null, true);
+}
+
+@Override
+boolean updateTextDirection(int textDirection) {
+ if (super.updateTextDirection(textDirection)) {
+ for (int i = 0, n = items.length; i < n; i++) {
+ if (items[i] != null) {
+ items[i].updateTextDirection(textDirection == AUTO_TEXT_DIRECTION ? AUTO_TEXT_DIRECTION : style & SWT.FLIP_TEXT_DIRECTION);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+void showItem (ExpandItem item) {
+ Control control = item.control;
+ if (control != null && !control.isDisposed ()) {
+ control.setVisible (item.expanded);
+ }
+ item.redraw (true);
+ int index = indexOf (item);
+ layoutItems (index + 1, true);
+}
+
+void showFocus (boolean up) {
+ RECT rect = new RECT();
+ OS.GetClientRect (handle, rect);
+ int height = rect.bottom - rect.top;
+ int updateY = 0;
+ if (up) {
+ if (focusItem.y < 0) {
+ updateY = Math.min (yCurrentScroll, -focusItem.y);
+ }
+ } else {
+ int itemHeight = focusItem.y + getBandHeight ();
+ if (focusItem.expanded) {
+ if (height >= getBandHeight () + focusItem.height) {
+ itemHeight += focusItem.height;
+ }
+ }
+ if (itemHeight > height) {
+ updateY = height - itemHeight;
+ }
+ }
+ if (updateY != 0) {
+ yCurrentScroll = Math.max (0, yCurrentScroll - updateY);
+ if ((style & SWT.V_SCROLL) != 0) {
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_POS;
+ info.nPos = yCurrentScroll;
+ OS.SetScrollInfo (handle, OS.SB_VERT, info, true);
+ }
+ OS.ScrollWindowEx (handle, 0, updateY, null, null, 0, null, OS.SW_SCROLLCHILDREN | OS.SW_INVALIDATE);
+ for (int i = 0; i < itemCount; i++) {
+ items [i].y += updateY;
+ }
+ }
+}
+
+@Override
+TCHAR windowClass () {
+ return display.windowClass;
+}
+
+@Override
+long windowProc () {
+ return display.windowProc;
+}
+
+@Override
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_KEYDOWN (wParam, lParam);
+ if (result != null) return result;
+ if (focusItem == null) return result;
+ switch ((int)wParam) {
+ case OS.VK_SPACE:
+ case OS.VK_RETURN:
+ Event event = new Event ();
+ event.item = focusItem;
+ sendEvent (focusItem.expanded ? SWT.Collapse : SWT.Expand, event);
+ focusItem.expanded = !focusItem.expanded;
+ showItem (focusItem);
+ return LRESULT.ZERO;
+ case OS.VK_UP: {
+ int focusIndex = indexOf (focusItem);
+ if (focusIndex > 0) {
+ focusItem.redraw (true);
+ focusItem = items [focusIndex - 1];
+ focusItem.redraw (true);
+ showFocus (true);
+ return LRESULT.ZERO;
+ }
+ break;
+ }
+ case OS.VK_DOWN: {
+ int focusIndex = indexOf (focusItem);
+ if (focusIndex < itemCount - 1) {
+ focusItem.redraw (true);
+ focusItem = items [focusIndex + 1];
+ focusItem.redraw (true);
+ showFocus (false);
+ return LRESULT.ZERO;
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_KILLFOCUS (long wParam, long lParam) {
+ LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
+ if (focusItem != null) focusItem.redraw (true);
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
+ if (result == LRESULT.ZERO) return result;
+ int x = OS.GET_X_LPARAM (lParam);
+ int y = OS.GET_Y_LPARAM (lParam);
+ for (int i = 0; i < itemCount; i++) {
+ ExpandItem item = items[i];
+ boolean hover = item.isHover (x, y);
+ if (hover && focusItem != item) {
+ focusItem.redraw (true);
+ focusItem = item;
+ focusItem.redraw (true);
+ forceFocus ();
+ break;
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONUP (long wParam, long lParam) {
+ LRESULT result = super.WM_LBUTTONUP (wParam, lParam);
+ if (result == LRESULT.ZERO) return result;
+ if (focusItem == null) return result;
+ int x = OS.GET_X_LPARAM (lParam);
+ int y = OS.GET_Y_LPARAM (lParam);
+ boolean hover = focusItem.isHover (x, y);
+ if (hover) {
+ Event event = new Event ();
+ event.item = focusItem;
+ sendEvent (focusItem.expanded ? SWT.Collapse : SWT.Expand, event);
+ focusItem.expanded = !focusItem.expanded;
+ showItem (focusItem);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_MOUSELEAVE (long wParam, long lParam) {
+ LRESULT result = super.WM_MOUSELEAVE (wParam, lParam);
+ if (result != null) return result;
+ for (int i = 0; i < itemCount; i++) {
+ ExpandItem item = items [i];
+ if (item.hover) {
+ item.hover = false;
+ item.redraw (false);
+ break;
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_MOUSEMOVE (long wParam, long lParam) {
+ LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
+ if (result == LRESULT.ZERO) return result;
+ int x = OS.GET_X_LPARAM (lParam);
+ int y = OS.GET_Y_LPARAM (lParam);
+ for (int i = 0; i < itemCount; i++) {
+ ExpandItem item = items [i];
+ boolean hover = item.isHover (x, y);
+ if (item.hover != hover) {
+ item.hover = hover;
+ item.redraw (false);
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_MOUSEWHEEL (long wParam, long lParam) {
+ return wmScrollWheel (true, wParam, lParam);
+}
+
+@Override
+LRESULT WM_PAINT (long wParam, long lParam) {
+ if ((state & DISPOSE_SENT) != 0) return LRESULT.ZERO;
+
+ PAINTSTRUCT ps = new PAINTSTRUCT ();
+ GCData data = new GCData ();
+ data.ps = ps;
+ data.hwnd = handle;
+ GC gc = new_GC (data);
+ if (gc != null) {
+ int width = ps.right - ps.left;
+ int height = ps.bottom - ps.top;
+ if (width != 0 && height != 0) {
+ RECT rect = new RECT ();
+ OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
+ drawWidget (gc, rect);
+ if (hooks (SWT.Paint) || filters (SWT.Paint)) {
+ Event event = new Event ();
+ event.gc = gc;
+ event.setBoundsInPixels(new Rectangle(rect.left, rect.top, width, height));
+ sendEvent (SWT.Paint, event);
+ event.gc = null;
+ }
+ }
+ gc.dispose ();
+ }
+ return LRESULT.ZERO;
+}
+
+@Override
+LRESULT WM_PRINTCLIENT (long wParam, long lParam) {
+ LRESULT result = super.WM_PRINTCLIENT (wParam, lParam);
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ GCData data = new GCData ();
+ data.device = display;
+ data.foreground = getForegroundPixel ();
+ GC gc = GC.win32_new (wParam, data);
+ drawWidget (gc, rect);
+ gc.dispose ();
+ return result;
+}
+
+@Override
+LRESULT WM_SETCURSOR (long wParam, long lParam) {
+ LRESULT result = super.WM_SETCURSOR (wParam, lParam);
+ if (result != null) return result;
+ int hitTest = (short) OS.LOWORD (lParam);
+ if (hitTest == OS.HTCLIENT) {
+ for (int i = 0; i < itemCount; i++) {
+ ExpandItem item = items [i];
+ if (item.hover) {
+ long hCursor = OS.LoadCursor (0, OS.IDC_HAND);
+ OS.SetCursor (hCursor);
+ return LRESULT.ONE;
+ }
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_SETFOCUS (long wParam, long lParam) {
+ LRESULT result = super.WM_SETFOCUS (wParam, lParam);
+ if (focusItem != null) focusItem.redraw (true);
+ return result;
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ int width = Math.max (0, (rect.right - rect.left) - spacing * 2);
+ for (int i = 0; i < itemCount; i++) {
+ ExpandItem item = items[i];
+ if (item.width != width) item.setBoundsInPixels (0, 0, width, item.height, false, true);
+ }
+ setScrollbar ();
+ OS.InvalidateRect (handle, null, true);
+ return result;
+}
+
+@Override
+LRESULT wmScroll (ScrollBar bar, boolean update, long hwnd, int msg, long wParam, long lParam) {
+ LRESULT result = super.wmScroll (bar, true, hwnd, msg, wParam, lParam);
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_POS;
+ OS.GetScrollInfo (handle, OS.SB_VERT, info);
+ int updateY = yCurrentScroll - info.nPos;
+ OS.ScrollWindowEx (handle, 0, updateY, null, null, 0, null, OS.SW_SCROLLCHILDREN | OS.SW_INVALIDATE);
+ yCurrentScroll = info.nPos;
+ if (updateY != 0) {
+ for (int i = 0; i < itemCount; i++) {
+ items [i].y += updateY;
+ }
+ }
+ return result;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ExpandItem.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ExpandItem.java
new file mode 100644
index 000000000..a092e4109
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ExpandItem.java
@@ -0,0 +1,523 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2013 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent a selectable user interface object
+ * that represents a expandable item in a expand bar.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ExpandItem (ExpandBar parent, int style) {
+ this (parent, style, checkNull (parent).getItemCount ());
+}
+
+/**
+ * Constructs a new instance of this class given its parent, a
+ * style value describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ExpandItem (ExpandBar parent, int style, int index) {
+ super (parent, style);
+ this.parent = parent;
+ parent.createItem (this, style, index);
+}
+
+static ExpandBar checkNull (ExpandBar control) {
+ if (control == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return control;
+}
+
+private void drawChevron (long hDC, RECT rect) {
+ long oldBrush = OS.SelectObject (hDC, OS.GetSysColorBrush (OS.COLOR_BTNFACE));
+ OS.PatBlt (hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY);
+ OS.SelectObject (hDC, oldBrush);
+ rect.left += 4;
+ rect.top += 4;
+ rect.right -= 4;
+ rect.bottom -= 4;
+ long hPen = OS.CreatePen (OS.PS_SOLID, 1, parent.getForegroundPixel ());
+ long oldPen = OS.SelectObject (hDC, hPen);
+ int [] polyline1, polyline2;
+ if (expanded) {
+ int px = rect.left + 5;
+ int py = rect.top + 7;
+ polyline1 = new int [] {
+ px,py, px+1,py, px+1,py-1, px+2,py-1, px+2,py-2, px+3,py-2, px+3,py-3,
+ px+3,py-2, px+4,py-2, px+4,py-1, px+5,py-1, px+5,py, px+7,py};
+ py += 4;
+ polyline2 = new int [] {
+ px,py, px+1,py, px+1,py-1, px+2,py-1, px+2,py-2, px+3,py-2, px+3,py-3,
+ px+3,py-2, px+4,py-2, px+4,py-1, px+5,py-1, px+5,py, px+7,py};
+ } else {
+ int px = rect.left + 5;
+ int py = rect.top + 4;
+ polyline1 = new int[] {
+ px,py, px+1,py, px+1,py+1, px+2,py+1, px+2,py+2, px+3,py+2, px+3,py+3,
+ px+3,py+2, px+4,py+2, px+4,py+1, px+5,py+1, px+5,py, px+7,py};
+ py += 4;
+ polyline2 = new int [] {
+ px,py, px+1,py, px+1,py+1, px+2,py+1, px+2,py+2, px+3,py+2, px+3,py+3,
+ px+3,py+2, px+4,py+2, px+4,py+1, px+5,py+1, px+5,py, px+7,py};
+ }
+ OS.Polyline (hDC, polyline1, polyline1.length / 2);
+ OS.Polyline (hDC, polyline2, polyline2.length / 2);
+ if (hover) {
+ long whitePen = OS.CreatePen (OS.PS_SOLID, 1, OS.GetSysColor (OS.COLOR_3DHILIGHT));
+ long darkGrayPen = OS.CreatePen (OS.PS_SOLID, 1, OS.GetSysColor (OS.COLOR_3DSHADOW));
+ OS.SelectObject (hDC, whitePen);
+ int [] points1 = {
+ rect.left, rect.bottom,
+ rect.left, rect.top,
+ rect.right, rect.top};
+ OS.Polyline (hDC, points1, points1.length / 2);
+ OS.SelectObject (hDC, darkGrayPen);
+ int [] points2 = {
+ rect.right, rect.top,
+ rect.right, rect.bottom,
+ rect.left, rect.bottom};
+ OS.Polyline (hDC, points2, points2.length / 2);
+ OS.SelectObject (hDC, oldPen);
+ OS.DeleteObject (whitePen);
+ OS.DeleteObject (darkGrayPen);
+ } else {
+ OS.SelectObject (hDC, oldPen);
+ }
+ OS.DeleteObject (hPen);
+}
+
+void drawItem (GC gc, long hTheme, RECT clipRect, boolean drawFocus) {
+ long hDC = gc.handle;
+ int headerHeight = parent.getBandHeight ();
+ RECT rect = new RECT ();
+ OS.SetRect (rect, x, y, x + width, y + headerHeight);
+ if (hTheme != 0) {
+ OS.DrawThemeBackground (hTheme, hDC, OS.EBP_NORMALGROUPHEAD, 0, rect, clipRect);
+ } else {
+ long oldBrush = OS.SelectObject (hDC, OS.GetSysColorBrush (OS.COLOR_BTNFACE));
+ OS.PatBlt (hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY);
+ OS.SelectObject (hDC, oldBrush);
+ }
+ if (image != null) {
+ rect.left += ExpandItem.TEXT_INSET;
+ if (imageHeight > headerHeight) {
+ gc.drawImage (image, DPIUtil.autoScaleDown(rect.left), DPIUtil.autoScaleDown(rect.top + headerHeight - imageHeight));
+ } else {
+ gc.drawImage (image, DPIUtil.autoScaleDown(rect.left), DPIUtil.autoScaleDown(rect.top + (headerHeight - imageHeight) / 2));
+ }
+ rect.left += imageWidth;
+ }
+ if (text.length () > 0) {
+ rect.left += ExpandItem.TEXT_INSET;
+ char [] buffer;
+ if ((style & SWT.FLIP_TEXT_DIRECTION) != 0) {
+ int bits = OS.GetWindowLong (parent.handle, OS.GWL_EXSTYLE);
+ if ((bits & OS.WS_EX_LAYOUTRTL) != 0) {
+ buffer = (LRE + text).toCharArray ();
+ } else {
+ buffer = (RLE + text).toCharArray ();
+ }
+ }
+ else {
+ buffer = text.toCharArray ();
+ }
+ if (hTheme != 0) {
+ OS.DrawThemeText (hTheme, hDC, OS.EBP_NORMALGROUPHEAD, 0, buffer, buffer.length, OS.DT_VCENTER | OS.DT_SINGLELINE, 0, rect);
+ } else {
+ int oldBkMode = OS.SetBkMode (hDC, OS.TRANSPARENT);
+ OS.DrawText (hDC, buffer, buffer.length, rect, OS.DT_VCENTER | OS.DT_SINGLELINE);
+ OS.SetBkMode (hDC, oldBkMode);
+ }
+ }
+ int chevronSize = ExpandItem.CHEVRON_SIZE;
+ rect.left = rect.right - chevronSize;
+ rect.top = y + (headerHeight - chevronSize) / 2;
+ rect.bottom = rect.top + chevronSize;
+ if (hTheme != 0) {
+ int partID = expanded ? OS.EBP_NORMALGROUPCOLLAPSE : OS.EBP_NORMALGROUPEXPAND;
+ int stateID = hover ? OS.EBNGC_HOT : OS.EBNGC_NORMAL;
+ OS.DrawThemeBackground (hTheme, hDC, partID, stateID, rect, clipRect);
+ } else {
+ drawChevron (hDC, rect);
+ }
+ if (drawFocus) {
+ OS.SetRect (rect, x + 1, y + 1, x + width - 2, y + headerHeight - 2);
+ OS.DrawFocusRect (hDC, rect);
+ }
+ if (expanded) {
+ if (!parent.isAppThemed ()) {
+ long pen = OS.CreatePen (OS.PS_SOLID, 1, OS.GetSysColor (OS.COLOR_BTNFACE));
+ long oldPen = OS.SelectObject (hDC, pen);
+ int [] points = {
+ x, y + headerHeight,
+ x, y + headerHeight + height,
+ x + width - 1, y + headerHeight + height,
+ x + width - 1, y + headerHeight - 1};
+ OS.Polyline (hDC, points, points.length / 2);
+ OS.SelectObject (hDC, oldPen);
+ OS.DeleteObject (pen);
+ }
+ }
+}
+
+@Override
+void destroyWidget () {
+ parent.destroyItem (this);
+ releaseHandle ();
+}
+
+/**
+ * Returns the control that is shown when the item is expanded.
+ * If no control has been set, return null
.
+ *
+ * @return the control
+ *
+ * @exception SWTException
+ *
+ */
+public Control getControl () {
+ checkWidget ();
+ return control;
+}
+
+/**
+ * Returns true
if the receiver is expanded,
+ * and false otherwise.
+ *
+ * @return the expanded state
+ *
+ * @exception SWTException
+ *
+ */
+public boolean getExpanded () {
+ checkWidget ();
+ return expanded;
+}
+
+/**
+ * Returns the height of the receiver's header
+ *
+ * @return the height of the header
+ *
+ * @exception SWTException
+ *
+ */
+public int getHeaderHeight () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getHeaderHeightInPixels());
+}
+
+int getHeaderHeightInPixels () {
+ return Math.max (parent.getBandHeight (), imageHeight);
+}
+
+/**
+ * Gets the height of the receiver.
+ *
+ * @return the height
+ *
+ * @exception SWTException
+ *
+ */
+public int getHeight () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getHeightInPixels());
+}
+
+int getHeightInPixels () {
+ return height;
+}
+
+/**
+ * Returns the receiver's parent, which must be a ExpandBar
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException
+ *
+ */
+public ExpandBar getParent () {
+ checkWidget ();
+ return parent;
+}
+
+int getPreferredWidth (long hTheme, long hDC) {
+ int width = ExpandItem.TEXT_INSET * 2 + ExpandItem.CHEVRON_SIZE;
+ if (image != null) {
+ width += ExpandItem.TEXT_INSET + imageWidth;
+ }
+ if (text.length() > 0) {
+ RECT rect = new RECT ();
+ char [] buffer = text.toCharArray ();
+ if (hTheme != 0) {
+ OS.GetThemeTextExtent (hTheme, hDC, OS.EBP_NORMALGROUPHEAD, 0, buffer, buffer.length, OS.DT_SINGLELINE, null, rect);
+ } else {
+ OS.DrawText (hDC, buffer, buffer.length, rect, OS.DT_CALCRECT);
+ }
+ width += (rect.right - rect.left);
+ }
+ return width;
+}
+
+boolean isHover (int x, int y) {
+ int bandHeight = parent.getBandHeight ();
+ return this.x < x && x < (this.x + width) && this.y < y && y < (this.y + bandHeight);
+}
+
+void redraw (boolean all) {
+ long parentHandle = parent.handle;
+ int headerHeight = parent.getBandHeight ();
+ RECT rect = new RECT ();
+ int left = all ? x : x + width - headerHeight;
+ OS.SetRect (rect, left, y, x + width, y + headerHeight);
+ OS.InvalidateRect (parentHandle, rect, true);
+ if (imageHeight > headerHeight) {
+ OS.SetRect (rect, x + ExpandItem.TEXT_INSET, y + headerHeight - imageHeight, x + ExpandItem.TEXT_INSET + imageWidth, y);
+ OS.InvalidateRect (parentHandle, rect, true);
+ }
+ if (!parent.isAppThemed ()) {
+ OS.SetRect (rect, x, y + headerHeight, x + width, y + headerHeight + height + 1);
+ OS.InvalidateRect (parentHandle, rect, true);
+ }
+}
+
+@Override
+void releaseHandle () {
+ super.releaseHandle ();
+ parent = null;
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ control = null;
+}
+
+void setBoundsInPixels (int x, int y, int width, int height, boolean move, boolean size) {
+ redraw (true);
+ int headerHeight = parent.getBandHeight ();
+ if (move) {
+ if (imageHeight > headerHeight) {
+ y += (imageHeight - headerHeight);
+ }
+ this.x = x;
+ this.y = y;
+ redraw (true);
+ }
+ if (size) {
+ this.width = width;
+ this.height = height;
+ redraw (true);
+ }
+ if (control != null && !control.isDisposed ()) {
+ if (!parent.isAppThemed ()) {
+ x += BORDER;
+ width = Math.max (0, width - BORDER * 2);
+ height = Math.max (0, height - BORDER);
+ }
+ if (move && size) control.setBoundsInPixels (x, y + headerHeight, width, height);
+ if (move && !size) control.setLocationInPixels (x, y + headerHeight);
+ if (!move && size) control.setSizeInPixels (width, height);
+ }
+}
+
+/**
+ * Sets the control that is shown when the item is expanded.
+ *
+ * @param control the new control (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setControl (Control control) {
+ checkWidget ();
+ if (control != null) {
+ if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (control.parent != parent) error (SWT.ERROR_INVALID_PARENT);
+ }
+ this.control = control;
+ if (control != null) {
+ int headerHeight = parent.getBandHeight ();
+ control.setVisible (expanded);
+ if (!parent.isAppThemed ()) {
+ int width = Math.max (0, this.width - BORDER * 2);
+ int height = Math.max (0, this.height - BORDER);
+ control.setBoundsInPixels (x + BORDER, y + headerHeight, width, height);
+ } else {
+ control.setBoundsInPixels (x, y + headerHeight, width, height);
+ }
+ }
+}
+
+/**
+ * Sets the expanded state of the receiver.
+ *
+ * @param expanded the new expanded state
+ *
+ * @exception SWTException
+ *
+ */
+public void setExpanded (boolean expanded) {
+ checkWidget ();
+ this.expanded = expanded;
+ parent.showItem (this);
+}
+
+/**
+ * Sets the height of the receiver. This is height of the item when it is expanded,
+ * excluding the height of the header.
+ *
+ * @param height the new height
+ *
+ * @exception SWTException
+ *
+ */
+public void setHeight (int height) {
+ checkWidget ();
+ setHeightInPixels(DPIUtil.autoScaleUp(height));
+}
+
+void setHeightInPixels (int height) {
+ if (height < 0) return;
+ setBoundsInPixels (0, 0, width, height, false, true);
+ if (expanded) parent.layoutItems (parent.indexOf (this) + 1, true);
+}
+
+@Override
+public void setImage (Image image) {
+ super.setImage (image);
+ int oldImageHeight = imageHeight;
+ if (image != null) {
+ Rectangle bounds = image.getBoundsInPixels ();
+ imageHeight = bounds.height;
+ imageWidth = bounds.width;
+ } else {
+ imageHeight = imageWidth = 0;
+ }
+ if (oldImageHeight != imageHeight) {
+ parent.layoutItems (parent.indexOf (this), true);
+ } else {
+ redraw (true);
+ }
+}
+
+@Override
+public void setText (String string) {
+ super.setText (string);
+ if ((state & HAS_AUTO_DIRECTION) != 0) {
+ updateTextDirection (AUTO_TEXT_DIRECTION);
+ }
+ redraw (true);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/FileDialog.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/FileDialog.java
new file mode 100644
index 000000000..7bac8a065
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/FileDialog.java
@@ -0,0 +1,598 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class allow the user to navigate
+ * the file system and select or enter a file name.
+ *
+ *
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public FileDialog (Shell parent) {
+ this (parent, SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#SAVE
+ * @see SWT#OPEN
+ * @see SWT#MULTI
+ */
+public FileDialog (Shell parent, int style) {
+ super (parent, checkStyle (parent, style));
+ checkSubclass ();
+}
+
+/**
+ * Returns the path of the first file that was
+ * selected in the dialog relative to the filter path, or an
+ * empty string if no such file has been selected.
+ *
+ * @return the relative path of the file
+ */
+public String getFileName () {
+ return fileName;
+}
+
+/**
+ * Returns a (possibly empty) array with the paths of all files
+ * that were selected in the dialog relative to the filter path.
+ *
+ * @return the relative paths of the files
+ */
+public String [] getFileNames () {
+ return fileNames;
+}
+
+/**
+ * Returns the file extensions which the dialog will
+ * use to filter the files it shows.
+ *
+ * @return the file extensions filter
+ */
+public String [] getFilterExtensions () {
+ return filterExtensions;
+}
+
+/**
+ * Get the 0-based index of the file extension filter
+ * which was selected by the user, or -1 if no filter
+ * was selected.
+ *
+ *
+ */
+public String open () {
+ long hHeap = OS.GetProcessHeap ();
+
+ /* Get the owner HWND for the dialog */
+ long hwndOwner = parent.handle;
+ long hwndParent = parent.handle;
+
+ /*
+ * Feature in Windows. There is no API to set the orientation of a
+ * file dialog. It is always inherited from the parent. The fix is
+ * to create a hidden parent and set the orientation in the hidden
+ * parent for the dialog to inherit.
+ */
+ boolean enabled = false;
+ int dialogOrientation = style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+ int parentOrientation = parent.style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+ if (dialogOrientation != parentOrientation) {
+ int exStyle = OS.WS_EX_NOINHERITLAYOUT;
+ if (dialogOrientation == SWT.RIGHT_TO_LEFT) exStyle |= OS.WS_EX_LAYOUTRTL;
+ hwndOwner = OS.CreateWindowEx (
+ exStyle,
+ Shell.DialogClass,
+ null,
+ 0,
+ OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
+ hwndParent,
+ 0,
+ OS.GetModuleHandle (null),
+ null);
+ enabled = OS.IsWindowEnabled (hwndParent);
+ if (enabled) OS.EnableWindow (hwndParent, false);
+ }
+
+ /* Convert the title and copy it into lpstrTitle */
+ if (title == null) title = "";
+ /* Use the character encoding for the default locale */
+ TCHAR buffer3 = new TCHAR (0, title, true);
+ int byteCount3 = buffer3.length () * TCHAR.sizeof;
+ long lpstrTitle = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount3);
+ OS.MoveMemory (lpstrTitle, buffer3, byteCount3);
+
+ /* Compute filters and copy into lpstrFilter */
+ String strFilter = "";
+ if (filterNames == null) filterNames = new String [0];
+ if (filterExtensions == null) filterExtensions = new String [0];
+ for (int i=0; inames
array must
+ * be the same length as the extensions
array.
+ *
+ *
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public FontDialog (Shell parent) {
+ this (parent, SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public FontDialog (Shell parent, int style) {
+ super (parent, checkStyle (parent, style));
+ checkSubclass ();
+}
+
+/**
+ * Returns true
if the dialog's effects selection controls
+ * are visible, and false
otherwise.
+ * true
if the dialog's effects selection controls
+ * are visible and false
otherwise
+ *
+ * @since 3.8
+ */
+public boolean getEffectsVisible () {
+ return effectsVisible;
+}
+
+/**
+ * Returns a FontData object describing the font that was
+ * selected in the dialog, or null if none is available.
+ *
+ * @return the FontData for the selected font, or null
+ * @deprecated use #getFontList ()
+ */
+@Deprecated
+public FontData getFontData () {
+ return fontData;
+}
+
+/**
+ * Returns a FontData set describing the font that was
+ * selected in the dialog, or null if none is available.
+ *
+ * @return the FontData for the selected font, or null
+ * @since 2.1.1
+ */
+public FontData [] getFontList () {
+ if (fontData == null) return null;
+ FontData [] result = new FontData [1];
+ result [0] = fontData;
+ return result;
+}
+
+/**
+ * Returns an RGB describing the color that was selected
+ * in the dialog, or null if none is available.
+ *
+ * @return the RGB value for the selected color, or null
+ *
+ * @see PaletteData#getRGBs
+ *
+ * @since 2.1
+ */
+public RGB getRGB () {
+ return rgb;
+}
+
+/**
+ * Makes the dialog visible and brings it to the front
+ * of the display.
+ *
+ * @return a FontData object describing the font that was selected,
+ * or null if the dialog was cancelled or an error occurred
+ *
+ * @exception SWTException
+ *
+ */
+public FontData open () {
+ /* Get the owner HWND for the dialog */
+ long hwndOwner = parent.handle;
+ long hwndParent = parent.handle;
+
+ /*
+ * Feature in Windows. There is no API to set the orientation of a
+ * font dialog. It is always inherited from the parent. The fix is
+ * to create a hidden parent and set the orientation in the hidden
+ * parent for the dialog to inherit.
+ */
+ boolean enabled = false;
+ int dialogOrientation = style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+ int parentOrientation = parent.style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+ if (dialogOrientation != parentOrientation) {
+ int exStyle = OS.WS_EX_NOINHERITLAYOUT;
+ if (dialogOrientation == SWT.RIGHT_TO_LEFT) exStyle |= OS.WS_EX_LAYOUTRTL;
+ hwndOwner = OS.CreateWindowEx (
+ exStyle,
+ Shell.DialogClass,
+ null,
+ 0,
+ OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
+ hwndParent,
+ 0,
+ OS.GetModuleHandle (null),
+ null);
+ enabled = OS.IsWindowEnabled (hwndParent);
+ if (enabled) OS.EnableWindow (hwndParent, false);
+ }
+
+ /* Open the dialog */
+ long hHeap = OS.GetProcessHeap ();
+ CHOOSEFONT lpcf = new CHOOSEFONT ();
+ lpcf.lStructSize = CHOOSEFONT.sizeof;
+ lpcf.hwndOwner = hwndOwner;
+ lpcf.Flags = OS.CF_SCREENFONTS;
+ if (effectsVisible) {
+ lpcf.Flags |= OS.CF_EFFECTS;
+ }
+
+ long lpLogFont = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, LOGFONT.sizeof);
+ if (fontData != null && fontData.data != null) {
+ LOGFONT logFont = fontData.data;
+ int lfHeight = logFont.lfHeight;
+ long hDC = OS.GetDC (0);
+ int pixels = -(int)(0.5f + (fontData.height * OS.GetDeviceCaps(hDC, OS.LOGPIXELSY) / 72));
+ OS.ReleaseDC (0, hDC);
+ logFont.lfHeight = pixels;
+ lpcf.Flags |= OS.CF_INITTOLOGFONTSTRUCT;
+ OS.MoveMemory (lpLogFont, logFont, LOGFONT.sizeof);
+ logFont.lfHeight = lfHeight;
+ }
+ lpcf.lpLogFont = lpLogFont;
+ if (rgb != null) {
+ int red = rgb.red & 0xFF;
+ int green = (rgb.green << 8) & 0xFF00;
+ int blue = (rgb.blue << 16) & 0xFF0000;
+ lpcf.rgbColors = red | green | blue;
+ }
+
+ /* Make the parent shell be temporary modal */
+ Dialog oldModal = null;
+ Display display = parent.getDisplay ();
+ if ((style & (SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) {
+ oldModal = display.getModalDialog ();
+ display.setModalDialog (this);
+ }
+
+ display.externalEventLoop = true;
+ display.sendPreExternalEventDispatchEvent ();
+ /* Open the dialog */
+ boolean success = OS.ChooseFont (lpcf);
+ display.externalEventLoop = false;
+ display.sendPostExternalEventDispatchEvent ();
+
+ /* Clear the temporary dialog modal parent */
+ if ((style & (SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) {
+ display.setModalDialog (oldModal);
+ }
+
+ /* Compute the result */
+ if (success) {
+ LOGFONT logFont = new LOGFONT ();
+ OS.MoveMemory (logFont, lpLogFont, LOGFONT.sizeof);
+
+ /*
+ * This will not work on multiple screens or
+ * for printing. Should use DC for the proper device.
+ */
+ long hDC = OS.GetDC(0);
+ int logPixelsY = OS.GetDeviceCaps(hDC, OS.LOGPIXELSY);
+ int pixels = 0;
+ if (logFont.lfHeight > 0) {
+ /*
+ * Feature in Windows. If the lfHeight of the LOGFONT structure
+ * is positive, the lfHeight measures the height of the entire
+ * cell, including internal leading, in logical units. Since the
+ * height of a font in points does not include the internal leading,
+ * we must subtract the internal leading, which requires a TEXTMETRIC,
+ * which in turn requires font creation.
+ */
+ long hFont = OS.CreateFontIndirect(logFont);
+ long oldFont = OS.SelectObject(hDC, hFont);
+ TEXTMETRIC lptm = new TEXTMETRIC ();
+ OS.GetTextMetrics(hDC, lptm);
+ OS.SelectObject(hDC, oldFont);
+ OS.DeleteObject(hFont);
+ pixels = logFont.lfHeight - lptm.tmInternalLeading;
+ } else {
+ pixels = -logFont.lfHeight;
+ }
+ OS.ReleaseDC(0, hDC);
+
+ float points = pixels * 72f /logPixelsY;
+ fontData = FontData.win32_new (logFont, points);
+ if (effectsVisible) {
+ int red = lpcf.rgbColors & 0xFF;
+ int green = (lpcf.rgbColors >> 8) & 0xFF;
+ int blue = (lpcf.rgbColors >> 16) & 0xFF;
+ rgb = new RGB (red, green, blue);
+ }
+ }
+
+ /* Free the OS memory */
+ if (lpLogFont != 0) OS.HeapFree (hHeap, 0, lpLogFont);
+
+ /* Destroy the BIDI orientation window */
+ if (hwndParent != hwndOwner) {
+ if (enabled) OS.EnableWindow (hwndParent, true);
+ OS.SetActiveWindow (hwndParent);
+ OS.DestroyWindow (hwndOwner);
+ }
+
+ /*
+ * This code is intentionally commented. On some
+ * platforms, the owner window is repainted right
+ * away when a dialog window exits. This behavior
+ * is currently unspecified.
+ */
+// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner);
+
+ if (!success) return null;
+ return fontData;
+}
+
+/**
+ * Sets the effects selection controls in the dialog visible if the
+ * argument is true
, and invisible otherwise.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#SHADOW_ETCHED_IN
+ * @see SWT#SHADOW_ETCHED_OUT
+ * @see SWT#SHADOW_IN
+ * @see SWT#SHADOW_OUT
+ * @see SWT#SHADOW_NONE
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Group (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ /*
+ * Feature in Windows. When the user clicks on the group
+ * box label, the group box takes focus. This is unwanted.
+ * The fix is to avoid calling the group box window proc.
+ */
+ switch (msg) {
+ case OS.WM_LBUTTONDOWN:
+ case OS.WM_LBUTTONDBLCLK:
+ return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+ }
+ return OS.CallWindowProc (GroupProc, hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ style |= SWT.NO_FOCUS;
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ Point size = super.computeSizeInPixels (wHint, hHint, changed);
+ int length = text.length ();
+ if (length != 0) {
+ String string = fixText (false);
+
+ /*
+ * If the group has text, and the text is wider than the
+ * client area, pad the width so the text is not clipped.
+ */
+ char [] buffer = (string == null ? text : string).toCharArray ();
+ long newFont, oldFont = 0;
+ long hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ RECT rect = new RECT ();
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE;
+ OS.DrawText (hDC, buffer, buffer.length, rect, flags);
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ int offsetY = OS.IsAppThemed () ? 0 : 1;
+ size.x = Math.max (size.x, rect.right - rect.left + CLIENT_INSET * 6 + offsetY);
+ }
+ return size;
+}
+
+@Override Rectangle computeTrimInPixels (int x, int y, int width, int height) {
+ checkWidget ();
+ Rectangle trim = super.computeTrimInPixels (x, y, width, height);
+ long newFont, oldFont = 0;
+ long hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ TEXTMETRIC tm = new TEXTMETRIC ();
+ OS.GetTextMetrics (hDC, tm);
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ int offsetY = OS.IsAppThemed () ? 0 : 1;
+ trim.x -= CLIENT_INSET;
+ trim.y -= tm.tmHeight + offsetY;
+ trim.width += CLIENT_INSET * 2;
+ trim.height += tm.tmHeight + CLIENT_INSET + offsetY;
+ return trim;
+}
+
+@Override
+void createHandle () {
+ /*
+ * Feature in Windows. When a button is created,
+ * it clears the UI state for all controls in the
+ * shell by sending WM_CHANGEUISTATE with UIS_SET,
+ * UISF_HIDEACCEL and UISF_HIDEFOCUS to the parent.
+ * This is undocumented and unexpected. The fix
+ * is to ignore the WM_CHANGEUISTATE, when sent
+ * from CreateWindowEx().
+ */
+ parent.state |= IGNORE_WM_CHANGEUISTATE;
+ super.createHandle ();
+ parent.state &= ~IGNORE_WM_CHANGEUISTATE;
+ state |= DRAW_BACKGROUND;
+ state &= ~CANVAS;
+}
+
+@Override
+void enableWidget (boolean enabled) {
+ super.enableWidget (enabled);
+ /*
+ * Bug in Windows. When a group control is right-to-left and
+ * is disabled, the first pixel of the text is clipped. The
+ * fix is to add a space to both sides of the text.
+ */
+ String string = fixText (enabled);
+ if (string != null) {
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ OS.SetWindowText (handle, buffer);
+ }
+ if (enabled && hasCustomForeground()) {
+ OS.InvalidateRect (handle, null, true);
+ }
+}
+
+String fixText (boolean enabled) {
+ /*
+ * Bug in Windows. When a group control is right-to-left and
+ * is disabled, the first pixel of the text is clipped. The
+ * fix is to add a space to both sides of the text.
+ */
+ if (text.length() == 0) return null;
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ String string = null;
+ if (!enabled && !OS.IsAppThemed ()) {
+ string = " " + text + " ";
+ }
+ return (style & SWT.FLIP_TEXT_DIRECTION) == 0 ? string : string != null ? LRE + string : LRE + text;
+ } else if ((style & SWT.FLIP_TEXT_DIRECTION) != 0) {
+ return RLE + text;
+ }
+ return null;
+}
+
+@Override Rectangle getClientAreaInPixels () {
+ checkWidget ();
+ forceResize ();
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ long newFont, oldFont = 0;
+ long hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ TEXTMETRIC tm = new TEXTMETRIC ();
+ OS.GetTextMetrics (hDC, tm);
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ int offsetY = OS.IsAppThemed () ? 0 : 1;
+ int x = CLIENT_INSET, y = tm.tmHeight + offsetY;
+ int width = Math.max (0, rect.right - CLIENT_INSET * 2);
+ int height = Math.max (0, rect.bottom - y - CLIENT_INSET);
+ return new Rectangle (x, y, width, height);
+}
+
+@Override
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns the receiver's text, which is the string that the
+ * is used as the title. If the text has not previously
+ * been set, returns an empty string.
+ *
+ * @return the text
+ *
+ * @exception SWTException
+ *
+ */
+public String getText () {
+ checkWidget ();
+ return text;
+}
+
+@Override
+boolean mnemonicHit (char key) {
+ return setFocus ();
+}
+
+@Override
+boolean mnemonicMatch (char key) {
+ char mnemonic = findMnemonic (getText ());
+ if (mnemonic == '\0') return false;
+ return Character.toUpperCase (key) == Character.toUpperCase (mnemonic);
+}
+
+@Override
+void printWidget (long hwnd, long hdc, GC gc) {
+ /*
+ * Bug in Windows. For some reason, PrintWindow()
+ * returns success but does nothing when it is called
+ * on a printer. The fix is to just go directly to
+ * WM_PRINT in this case.
+ */
+ boolean success = false;
+ if (!(OS.GetDeviceCaps(gc.handle, OS.TECHNOLOGY) == OS.DT_RASPRINTER)) {
+ int bits = OS.GetWindowLong (hwnd, OS.GWL_STYLE);
+ if ((bits & OS.WS_VISIBLE) == 0) {
+ OS.ShowWindow (hwnd, OS.SW_SHOW);
+ }
+ success = OS.PrintWindow (hwnd, hdc, 0);
+ if ((bits & OS.WS_VISIBLE) == 0) {
+ OS.ShowWindow (hwnd, OS.SW_HIDE);
+ }
+ }
+
+ /*
+ * Bug in Windows. For some reason, PrintWindow() fails
+ * when it is called on a push button. The fix is to
+ * detect the failure and use WM_PRINT instead. Note
+ * that WM_PRINT cannot be used all the time because it
+ * fails for browser controls when the browser has focus.
+ */
+ if (!success) {
+ /*
+ * Bug in Windows. For some reason, WM_PRINT when called
+ * with PRF_CHILDREN will not draw the tool bar divider
+ * for tool bar children that do not have CCS_NODIVIDER.
+ * The fix is to draw the group box and iterate through
+ * the children, drawing each one.
+ */
+ int flags = OS.PRF_CLIENT | OS.PRF_NONCLIENT | OS.PRF_ERASEBKGND;
+ OS.SendMessage (hwnd, OS.WM_PRINT, hdc, flags);
+ int nSavedDC = OS.SaveDC (hdc);
+ Control [] children = _getChildren ();
+ Rectangle rect = getBoundsInPixels ();
+ OS.IntersectClipRect (hdc, 0, 0, rect.width, rect.height);
+ for (int i=children.length - 1; i>=0; --i) {
+ Point location = children [i].getLocationInPixels ();
+ int graphicsMode = OS.GetGraphicsMode(hdc);
+ if (graphicsMode == OS.GM_ADVANCED) {
+ float [] lpXform = {1, 0, 0, 1, location.x, location.y};
+ OS.ModifyWorldTransform(hdc, lpXform, OS.MWT_LEFTMULTIPLY);
+ } else {
+ OS.SetWindowOrgEx (hdc, -location.x, -location.y, null);
+ }
+ long topHandle = children [i].topHandle();
+ int bits = OS.GetWindowLong (topHandle, OS.GWL_STYLE);
+ if ((bits & OS.WS_VISIBLE) != 0) {
+ children [i].printWidget (topHandle, hdc, gc);
+ }
+ if (graphicsMode == OS.GM_ADVANCED) {
+ float [] lpXform = {1, 0, 0, 1, -location.x, -location.y};
+ OS.ModifyWorldTransform(hdc, lpXform, OS.MWT_LEFTMULTIPLY);
+ }
+ }
+ OS.RestoreDC (hdc, nSavedDC);
+ }
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ text = null;
+}
+
+@Override
+int resolveTextDirection () {
+ return BidiUtil.resolveTextDirection (text);
+}
+
+@Override
+public void setFont (Font font) {
+ checkWidget ();
+ Rectangle oldRect = getClientAreaInPixels ();
+ super.setFont (font);
+ Rectangle newRect = getClientAreaInPixels ();
+ if (!oldRect.equals (newRect)) sendResize ();
+}
+
+/**
+ * Sets the receiver's text, which is the string that will
+ * be displayed as the receiver's title, to the argument,
+ * which may not be null. The string may include the mnemonic character.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ text = string;
+ if ((state & HAS_AUTO_DIRECTION) == 0 || !updateTextDirection (AUTO_TEXT_DIRECTION)) {
+ string = fixText (OS.IsWindowEnabled (handle));
+ TCHAR buffer = new TCHAR (getCodePage (), string == null ? text : string, true);
+ OS.SetWindowText (handle, buffer);
+ }
+}
+
+@Override
+boolean updateTextDirection(int textDirection) {
+ if (super.updateTextDirection(textDirection)) {
+ String string = fixText (OS.IsWindowEnabled (handle));
+ TCHAR buffer = new TCHAR (getCodePage (), string == null ? text : string, true);
+ OS.SetWindowText (handle, buffer);
+ return true;
+ }
+ return false;
+}
+
+@Override
+int widgetStyle () {
+ /*
+ * Bug in Windows. When GetDCEx() is called with DCX_INTERSECTUPDATE,
+ * the HDC that is returned does not include the current update region.
+ * This was confirmed under DEBUG Windows when GetDCEx() complained about
+ * invalid flags. Therefore, it is not easily possible to get an HDC from
+ * outside of WM_PAINT that includes the current damage and clips children.
+ * Because the receiver has children and draws a frame and label, it is
+ * necessary that the receiver always draw clipped, in the current damaged
+ * area. The fix is to force the receiver to be fully clipped by including
+ * WS_CLIPCHILDREN and WS_CLIPSIBLINGS in the default style bits.
+ */
+ return super.widgetStyle () | OS.BS_GROUPBOX | OS.WS_CLIPCHILDREN | OS.WS_CLIPSIBLINGS;
+}
+
+@Override
+TCHAR windowClass () {
+ return GroupClass;
+}
+
+@Override
+long windowProc () {
+ return GroupProc;
+}
+
+@Override
+LRESULT WM_ERASEBKGND (long wParam, long lParam) {
+ LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. Group boxes do not erase
+ * the background before drawing. The fix is to
+ * fill the background.
+ */
+ drawBackground (wParam);
+ return LRESULT.ONE;
+}
+
+@Override
+LRESULT WM_NCHITTEST (long wParam, long lParam) {
+ LRESULT result = super.WM_NCHITTEST (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. The window proc for the group box
+ * returns HTTRANSPARENT indicating that mouse messages
+ * should not be delivered to the receiver and any children.
+ * Normally, group boxes in Windows do not have children and
+ * this is the correct behavior for this case. Because we
+ * allow children, answer HTCLIENT to allow mouse messages
+ * to be delivered to the children.
+ */
+ long code = callWindowProc (handle, OS.WM_NCHITTEST, wParam, lParam);
+ if (code == OS.HTTRANSPARENT) code = OS.HTCLIENT;
+ return new LRESULT (code);
+}
+
+@Override
+LRESULT WM_MOUSEMOVE (long wParam, long lParam) {
+ LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. In version 6.00 of COMCTL32.DLL,
+ * every time the mouse moves, the group title redraws.
+ * This only happens when WM_NCHITTEST returns HTCLIENT.
+ * The fix is to avoid calling the group window proc.
+ */
+ return LRESULT.ZERO;
+}
+
+@Override
+LRESULT WM_PAINT (long wParam, long lParam) {
+ LRESULT result = super.WM_PAINT(wParam, lParam);
+
+ if (hasCustomForeground() && text.length () != 0) {
+ String string = fixText (false);
+ char [] buffer = (string == null ? text : string).toCharArray ();
+
+ // We cannot use BeginPaint and EndPaint, because that removes the group border
+ long hDC = OS.GetDC(handle);
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ rect.left += 3*CLIENT_INSET;
+
+ long newFont, oldFont = 0;
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+
+ OS.DrawText(hDC, buffer, buffer.length, rect, OS.DT_SINGLELINE | OS.DT_LEFT | OS.DT_TOP | OS.DT_CALCRECT);
+ // The calculated rectangle is a little bit too small. Italic fonts would show some small part in the default color.
+ rect.right += CLIENT_INSET;
+ drawBackground(hDC, rect);
+ OS.SetBkMode(hDC, OS.TRANSPARENT);
+ OS.SetTextColor(hDC, getForegroundPixel());
+ OS.DrawText(hDC, buffer, buffer.length, rect, OS.DT_SINGLELINE | OS.DT_LEFT | OS.DT_TOP);
+
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC(handle, hDC);
+ // Without validating the drawn area it would be overdrawn by windows
+ OS.ValidateRect(handle, rect);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_PRINTCLIENT (long wParam, long lParam) {
+ LRESULT result = super.WM_PRINTCLIENT (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. In version 6.00 of COMCTL32.DLL,
+ * when WM_PRINTCLIENT is sent from a child BS_GROUP
+ * control to a parent BS_GROUP, the parent BS_GROUP
+ * clears the font from the HDC. Normally, group boxes
+ * in Windows do not have children so this behavior is
+ * undefined. When the parent of a BS_GROUP is not a
+ * BS_GROUP, there is no problem. The fix is to save
+ * and restore the current font.
+ */
+ if (OS.IsAppThemed ()) {
+ int nSavedDC = OS.SaveDC (wParam);
+ long code = callWindowProc (handle, OS.WM_PRINTCLIENT, wParam, lParam);
+ OS.RestoreDC (wParam, nSavedDC);
+ return new LRESULT (code);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_UPDATEUISTATE (long wParam, long lParam) {
+ LRESULT result = super.WM_UPDATEUISTATE (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. When WM_UPDATEUISTATE is sent to
+ * a group, it sends WM_CTLCOLORBTN to get the foreground
+ * and background. If drawing happens in WM_CTLCOLORBTN,
+ * it will overwrite the contents of the control. The
+ * fix is draw the group without drawing the background
+ * and avoid the group window proc.
+ */
+ boolean redraw = findImageControl () != null;
+ if (!redraw) {
+ if ((state & THEME_BACKGROUND) != 0) {
+ if (OS.IsAppThemed ()) {
+ redraw = findThemeControl () != null;
+ }
+ }
+ if (!redraw) redraw = findBackgroundControl () != null;
+ }
+ if (redraw) {
+ OS.InvalidateRect (handle, null, false);
+ long code = OS.DefWindowProc (handle, OS.WM_UPDATEUISTATE, wParam, lParam);
+ return new LRESULT (code);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_WINDOWPOSCHANGING (long wParam, long lParam) {
+ LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Invalidate the portion of the group widget that needs to
+ * be redrawn. Note that for some reason, invalidating the
+ * group from inside WM_SIZE causes pixel corruption for
+ * radio button children.
+ */
+ if (!OS.IsWindowVisible (handle)) return result;
+ WINDOWPOS lpwp = new WINDOWPOS ();
+ OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
+ if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) != 0) {
+ return result;
+ }
+ RECT rect = new RECT ();
+ OS.SetRect (rect, 0, 0, lpwp.cx, lpwp.cy);
+ OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, rect);
+ int newWidth = rect.right - rect.left;
+ int newHeight = rect.bottom - rect.top;
+ OS.GetClientRect (handle, rect);
+ int oldWidth = rect.right - rect.left;
+ int oldHeight = rect.bottom - rect.top;
+ if (newWidth == oldWidth && newHeight == oldHeight) {
+ return result;
+ }
+ if (newWidth != oldWidth) {
+ int left = oldWidth;
+ if (newWidth < oldWidth) left = newWidth;
+ OS.SetRect (rect, left - CLIENT_INSET, 0, newWidth, newHeight);
+ OS.InvalidateRect (handle, rect, true);
+ }
+ if (newHeight != oldHeight) {
+ int bottom = oldHeight;
+ if (newHeight < oldHeight) bottom = newHeight;
+ if (newWidth < oldWidth) oldWidth -= CLIENT_INSET;
+ OS.SetRect (rect, 0, bottom - CLIENT_INSET, oldWidth, newHeight);
+ OS.InvalidateRect (handle, rect, true);
+ }
+ return result;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/IME.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/IME.java
new file mode 100644
index 000000000..846805091
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/IME.java
@@ -0,0 +1,589 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2014 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent input method editors.
+ * These are typically in-line pre-edit text areas that allow
+ * the user to compose characters from Far Eastern languages
+ * such as Japanese, Chinese or Korean.
+ *
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public IME (Canvas parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ createWidget ();
+}
+
+void createWidget () {
+ text = ""; //$NON-NLS-1$
+ startOffset = -1;
+ if (parent.getIME () == null) {
+ parent.setIME (this);
+ }
+}
+
+/**
+ * Returns the offset of the caret from the start of the document.
+ * -1 means that there is currently no active composition.
+ * The caret is within the current composition.
+ *
+ * @return the caret offset
+ *
+ * @exception SWTException
+ *
+ */
+public int getCaretOffset () {
+ checkWidget ();
+ return startOffset + caretOffset;
+}
+
+/**
+ * Returns the commit count of the composition. This is the
+ * number of characters that have been composed. When the
+ * commit count is equal to the length of the composition
+ * text, then the in-line edit operation is complete.
+ *
+ * @return the commit count
+ *
+ * @exception SWTException
+ *
+ *
+ * @see IME#getText
+ */
+public int getCommitCount () {
+ checkWidget ();
+ return commitCount;
+}
+
+/**
+ * Returns the offset of the composition from the start of the document.
+ * This is the start offset of the composition within the document and
+ * in not changed by the input method editor itself during the in-line edit
+ * session.
+ *
+ * @return the offset of the composition
+ *
+ * @exception SWTException
+ *
+ */
+public int getCompositionOffset () {
+ checkWidget ();
+ return startOffset;
+}
+
+TF_DISPLAYATTRIBUTE getDisplayAttribute (short langid, int attInfo) {
+ long [] ppv = new long [1];
+ int hr = COM.CoCreateInstance (COM.CLSID_TF_InputProcessorProfiles, 0, COM.CLSCTX_INPROC_SERVER, COM.IID_ITfInputProcessorProfiles, ppv);
+ TF_DISPLAYATTRIBUTE pda = null;
+ if (hr == OS.S_OK) {
+ ITfInputProcessorProfiles pProfiles = new ITfInputProcessorProfiles (ppv [0]);
+ GUID pclsid = new GUID ();
+ GUID pguidProfile = new GUID ();
+ hr = pProfiles.GetDefaultLanguageProfile (langid, COM.GUID_TFCAT_TIP_KEYBOARD, pclsid, pguidProfile);
+ if (hr == OS.S_OK) {
+ hr = COM.CoCreateInstance (pclsid, 0, COM.CLSCTX_INPROC_SERVER, COM.IID_ITfDisplayAttributeProvider, ppv);
+ if (hr == OS.S_OK) {
+ ITfDisplayAttributeProvider pProvider = new ITfDisplayAttributeProvider (ppv [0]);
+ hr = pProvider.EnumDisplayAttributeInfo (ppv);
+ if (hr == OS.S_OK) {
+ IEnumTfDisplayAttributeInfo pEnum = new IEnumTfDisplayAttributeInfo (ppv [0]);
+ TF_DISPLAYATTRIBUTE tempPda = new TF_DISPLAYATTRIBUTE ();
+ while ((hr = pEnum.Next (1, ppv, null)) == OS.S_OK) {
+ ITfDisplayAttributeInfo pDispInfo = new ITfDisplayAttributeInfo (ppv [0]);
+ pDispInfo.GetAttributeInfo (tempPda);
+ pDispInfo.Release ();
+ if (tempPda.bAttr == attInfo) {
+ pda = tempPda;
+ break;
+ }
+ }
+ pEnum.Release ();
+ }
+ pProvider.Release ();
+ }
+ }
+ pProfiles.Release ();
+ }
+ if (pda == null) {
+ pda = new TF_DISPLAYATTRIBUTE ();
+ switch (attInfo) {
+ case OS.TF_ATTR_INPUT:
+ pda.lsStyle = OS.TF_LS_SQUIGGLE;
+ break;
+ case OS.TF_ATTR_CONVERTED:
+ case OS.TF_ATTR_TARGET_CONVERTED:
+ pda.lsStyle = OS.TF_LS_SOLID;
+ pda.fBoldLine = attInfo == OS.TF_ATTR_TARGET_CONVERTED;
+ break;
+ }
+ }
+ return pda;
+}
+
+/**
+ * Returns the ranges for the style that should be applied during the
+ * in-line edit session.
+ * getStyles()
.
+ *
+ *
+ *
+ * @see IME#getStyles
+ */
+public int [] getRanges () {
+ checkWidget ();
+ if (ranges == null) return new int [0];
+ int [] result = new int [ranges.length];
+ for (int i = 0; i < result.length; i++) {
+ result [i] = ranges [i] + startOffset;
+ }
+ return result;
+}
+
+/**
+ * Returns the styles for the ranges.
+ *
+ *
+ *
+ * @see IME#getRanges
+ */
+public TextStyle [] getStyles () {
+ checkWidget ();
+ if (styles == null) return new TextStyle [0];
+ TextStyle [] result = new TextStyle [styles.length];
+ System.arraycopy (styles, 0, result, 0, styles.length);
+ return result;
+}
+
+/**
+ * Returns the composition text.
+ *
+ *
+ */
+public String getText () {
+ checkWidget ();
+ return text;
+}
+
+/**
+ * Returns true
if the caret should be wide, and
+ * false
otherwise. In some languages, for example
+ * Korean, the caret is typically widened to the width of the
+ * current character in the in-line edit session.
+ *
+ * @return the wide caret state
+ *
+ * @exception SWTException
+ *
+ */
+public boolean getWideCaret() {
+ checkWidget ();
+ long layout = OS.GetKeyboardLayout (0);
+ short langID = (short)OS.LOWORD (layout);
+ return OS.PRIMARYLANGID (langID) == OS.LANG_KOREAN;
+}
+
+boolean isInlineEnabled () {
+ return OS.IsDBLocale && hooks (SWT.ImeComposition);
+}
+
+@Override
+void releaseParent () {
+ super.releaseParent ();
+ if (this == parent.getIME ()) parent.setIME (null);
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ parent = null;
+ text = null;
+ styles = null;
+ ranges = null;
+}
+
+/**
+ * Sets the offset of the composition from the start of the document.
+ * This is the start offset of the composition within the document and
+ * in not changed by the input method editor itself during the in-line edit
+ * session but may need to be changed by clients of the IME. For example,
+ * if during an in-line edit operation, a text editor inserts characters
+ * above the IME, then the IME must be informed that the composition
+ * offset has changed.
+ *
+ * @param offset the offset of the composition
+ *
+ * @exception SWTException
+ *
+ */
+public void setCompositionOffset (int offset) {
+ checkWidget ();
+ if (offset < 0) return;
+ if (startOffset != -1) {
+ startOffset = offset;
+ }
+}
+
+LRESULT WM_IME_COMPOSITION (long wParam, long lParam) {
+ if (!isInlineEnabled ()) return null;
+ ranges = null;
+ styles = null;
+ caretOffset = commitCount = 0;
+ long hwnd = parent.handle;
+ long hIMC = OS.ImmGetContext (hwnd);
+ if (hIMC != 0) {
+ char [] buffer = null;
+ if ((lParam & OS.GCS_RESULTSTR) != 0) {
+ int length = OS.ImmGetCompositionString (hIMC, OS.GCS_RESULTSTR, (char [])null, 0);
+ if (length > 0) {
+ buffer = new char [length / TCHAR.sizeof];
+ OS.ImmGetCompositionString (hIMC, OS.GCS_RESULTSTR, buffer, length);
+ if (startOffset == -1) {
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_SELECTION;
+ sendEvent (SWT.ImeComposition, event);
+ startOffset = event.start;
+ }
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_CHANGED;
+ event.start = startOffset;
+ event.end = startOffset + text.length();
+ event.text = text = buffer != null ? new String (buffer) : ""; //$NON-NLS-1$
+ commitCount = text.length ();
+ sendEvent (SWT.ImeComposition, event);
+ String chars = text;
+ text = ""; //$NON-NLS-1$
+ startOffset = -1;
+ commitCount = 0;
+ if (event.doit) {
+ Display display = this.display;
+ display.lastKey = 0;
+ display.lastVirtual = display.lastNull = display.lastDead = false;
+ length = chars.length ();
+ for (int i = 0; i < length; i++) {
+ char c = chars.charAt (i);
+ display.lastAscii = c;
+ event = new Event ();
+ event.character = c;
+ parent.sendEvent (SWT.KeyDown, event);
+ }
+ }
+ }
+ if ((lParam & OS.GCS_COMPSTR) == 0) return LRESULT.ONE;
+ }
+ buffer = null;
+ if ((lParam & OS.GCS_COMPSTR) != 0) {
+ int length = OS.ImmGetCompositionString (hIMC, OS.GCS_COMPSTR, (char [])null, 0);
+ if (length > 0) {
+ buffer = new char [length / TCHAR.sizeof];
+ OS.ImmGetCompositionString (hIMC, OS.GCS_COMPSTR, buffer, length);
+ if ((lParam & OS.GCS_CURSORPOS) != 0) {
+ caretOffset = OS.ImmGetCompositionString (hIMC, OS.GCS_CURSORPOS, (char [])null, 0);
+ }
+ int [] clauses = null;
+ if ((lParam & OS.GCS_COMPCLAUSE) != 0) {
+ length = OS.ImmGetCompositionString (hIMC, OS.GCS_COMPCLAUSE, (int [])null, 0);
+ if (length > 0) {
+ clauses = new int [length / 4];
+ OS.ImmGetCompositionString (hIMC, OS.GCS_COMPCLAUSE, clauses, length);
+ }
+ }
+ if ((lParam & OS.GCS_COMPATTR) != 0 && clauses != null) {
+ length = OS.ImmGetCompositionString (hIMC, OS.GCS_COMPATTR, (byte [])null, 0);
+ if (length > 0) {
+ byte [] attrs = new byte [length];
+ OS.ImmGetCompositionString (hIMC, OS.GCS_COMPATTR, attrs, length);
+ length = clauses.length - 1;
+ ranges = new int [length * 2];
+ styles = new TextStyle [length];
+ long layout = OS.GetKeyboardLayout (0);
+ short langID = (short)OS.LOWORD (layout);
+ TF_DISPLAYATTRIBUTE attr = null;
+ TextStyle style = null;
+ for (int i = 0; i < length; i++) {
+ ranges [i * 2] = clauses [i];
+ ranges [i * 2 + 1] = clauses [i + 1] - 1;
+ styles [i] = style = new TextStyle ();
+ /* Added length check to avoid possibility of AIOOB, bug 444926 */
+ if (clauses [i] >= 0 && clauses [i] < attrs.length) {
+ attr = getDisplayAttribute (langID, attrs [clauses [i]]);
+ if (attr != null) {
+ switch (attr.crText.type) {
+ case OS.TF_CT_COLORREF:
+ style.foreground = Color.win32_new (display, attr.crText.cr);
+ break;
+ case OS.TF_CT_SYSCOLOR:
+ int colorRef = OS.GetSysColor (attr.crText.cr);
+ style.foreground = Color.win32_new (display, colorRef);
+ break;
+ }
+ switch (attr.crBk.type) {
+ case OS.TF_CT_COLORREF:
+ style.background = Color.win32_new (display, attr.crBk.cr);
+ break;
+ case OS.TF_CT_SYSCOLOR:
+ int colorRef = OS.GetSysColor (attr.crBk.cr);
+ style.background = Color.win32_new (display, colorRef);
+ break;
+ }
+ switch (attr.crLine.type) {
+ case OS.TF_CT_COLORREF:
+ style.underlineColor = Color.win32_new (display, attr.crLine.cr);
+ break;
+ case OS.TF_CT_SYSCOLOR:
+ int colorRef = OS.GetSysColor (attr.crLine.cr);
+ style.underlineColor = Color.win32_new (display, colorRef);
+ break;
+ }
+ style.underline = attr.lsStyle != OS.TF_LS_NONE;
+ switch (attr.lsStyle) {
+ case OS.TF_LS_SQUIGGLE:
+ style.underlineStyle = SWT.UNDERLINE_SQUIGGLE;
+ break;
+ case OS.TF_LS_DASH:
+ style.underlineStyle = UNDERLINE_IME_DASH;
+ break;
+ case OS.TF_LS_DOT:
+ style.underlineStyle = UNDERLINE_IME_DOT;
+ break;
+ case OS.TF_LS_SOLID:
+ style.underlineStyle = attr.fBoldLine ? UNDERLINE_IME_THICK : SWT.UNDERLINE_SINGLE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ OS.ImmReleaseContext (hwnd, hIMC);
+ }
+ int end = startOffset + text.length();
+ if (startOffset == -1) {
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_SELECTION;
+ sendEvent (SWT.ImeComposition, event);
+ startOffset = event.start;
+ end = event.end;
+ }
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_CHANGED;
+ event.start = startOffset;
+ event.end = end;
+ event.text = text = buffer != null ? new String (buffer) : ""; //$NON-NLS-1$
+ sendEvent (SWT.ImeComposition, event);
+ if (text.length() == 0) {
+ startOffset = -1;
+ ranges = null;
+ styles = null;
+ }
+ }
+ return LRESULT.ONE;
+}
+
+LRESULT WM_IME_COMPOSITION_START (long wParam, long lParam) {
+ return isInlineEnabled () ? LRESULT.ONE : null;
+}
+
+LRESULT WM_IME_ENDCOMPOSITION (long wParam, long lParam) {
+ // Reset defaults. Otherwise the next composition overwrites the previous one.
+ startOffset = -1;
+ caretOffset = 0;
+ return isInlineEnabled () ? LRESULT.ONE : null;
+}
+
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ if (wParam == OS.VK_HANJA) {
+ long hKL = OS.GetKeyboardLayout (0);
+ short langID = (short)OS.LOWORD (hKL);
+ if (OS.PRIMARYLANGID (langID) == OS.LANG_KOREAN) {
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_SELECTION;
+ sendEvent (SWT.ImeComposition, event);
+ if (event.start == event.end) {
+ event.text = null;
+ event.end = event.start + 1;
+ sendEvent (SWT.ImeComposition, event);
+ }
+ if (event.text != null && event.text.length() > 0) {
+ int length = event.text.length();
+ if (length > 1) {
+ event.end = event.start + 1;
+ }
+ long hwnd = parent.handle;
+ long hIMC = OS.ImmGetContext (hwnd);
+ TCHAR buffer = new TCHAR (0, event.text, true);
+ long rc = OS.ImmEscape(hKL, hIMC, OS.IME_ESC_HANJA_MODE, buffer);
+ if (rc != 0) {
+ sendEvent (SWT.ImeComposition, event);
+ }
+ }
+ }
+ }
+ return null;
+}
+
+LRESULT WM_KILLFOCUS (long wParam, long lParam) {
+ if (!isInlineEnabled ()) return null;
+ long hwnd = parent.handle;
+ long hIMC = OS.ImmGetContext (hwnd);
+ if (hIMC != 0) {
+ if (OS.ImmGetOpenStatus (hIMC)) {
+ OS.ImmNotifyIME (hIMC, OS.NI_COMPOSITIONSTR, OS.CPS_COMPLETE, 0);
+ }
+ OS.ImmReleaseContext (hwnd, hIMC);
+ }
+ return null;
+}
+
+LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
+ if (!isInlineEnabled ()) return null;
+ long hwnd = parent.handle;
+ long hIMC = OS.ImmGetContext (hwnd);
+ if (hIMC != 0) {
+ if (OS.ImmGetOpenStatus (hIMC)) {
+ if (OS.ImmGetCompositionString (hIMC, OS.GCS_COMPSTR, (char [])null, 0) > 0) {
+ Event event = new Event ();
+ event.detail = SWT.COMPOSITION_OFFSET;
+ event.setLocationInPixels(OS.GET_X_LPARAM (lParam), OS.GET_Y_LPARAM (lParam));
+ sendEvent (SWT.ImeComposition, event);
+ int offset = event.index;
+ int length = text.length();
+ if (offset != -1 && startOffset != -1 && startOffset <= offset && offset < startOffset + length) {
+ long imeWnd = OS.ImmGetDefaultIMEWnd (hwnd);
+ offset = event.index + event.count - startOffset;
+ int trailing = event.count > 0 ? 1 : 2;
+ long param = OS.MAKEWPARAM (OS.MAKEWORD (OS.IMEMOUSE_LDOWN, trailing), offset);
+ OS.SendMessage (imeWnd, WM_MSIME_MOUSE, param, hIMC);
+ } else {
+ OS.ImmNotifyIME (hIMC, OS.NI_COMPOSITIONSTR, OS.CPS_COMPLETE, 0);
+ }
+ }
+ }
+ OS.ImmReleaseContext (hwnd, hIMC);
+ }
+ return null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Item.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Item.java
new file mode 100644
index 000000000..304424156
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Item.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+
+/**
+ * This class is the abstract superclass of all non-windowed
+ * user interface objects that occur within specific controls.
+ * For example, a tree will contain tree items.
+ *
+ *
+ *
+ * @see Sample code and further information
+ */
+
+public abstract class Item extends Widget {
+ String text;
+ Image image;
+ /**
+ * Maximum number of characters Windows can reliably display in one line.
+ * Mac and Linux can display more but we are limited by windows here.
+ */
+ static final int TEXT_LIMIT = 8192;
+
+ static final String ELLIPSIS = "...";
+
+
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * The item is added to the end of the items maintained by its parent.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#getStyle
+ */
+public Item (Widget parent, int style) {
+ super (parent, style);
+ text = "";
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance,
+ * and the index at which to place it in the items maintained
+ * by its parent.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#getStyle
+ */
+public Item (Widget parent, int style, int index) {
+ this (parent, style);
+}
+
+@Override
+protected void checkSubclass () {
+ /* Do Nothing - Subclassing is allowed */
+}
+
+/**
+ * Returns the receiver's image if it has one, or null
+ * if it does not.
+ *
+ * @return the receiver's image
+ *
+ * @exception SWTException
+ *
+ */
+public Image getImage () {
+ checkWidget ();
+ return image;
+}
+
+@Override
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns the receiver's text, which will be an empty
+ * string if it has never been set.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException
+ *
+ */
+public String getText () {
+ checkWidget();
+ return text;
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ text = null;
+ image = null;
+}
+
+/**
+ * Sets the receiver's image to the argument, which may be
+ * null indicating that no image should be displayed.
+ *
+ * @param image the image to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setImage (Image image) {
+ checkWidget ();
+ if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ this.image = image;
+}
+
+/**
+ * Sets the receiver's text.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ text = string;
+ if ((state & HAS_AUTO_DIRECTION) != 0) {
+ updateTextDirection (AUTO_TEXT_DIRECTION);
+ }
+}
+
+boolean updateTextDirection(int textDirection) {
+ /*
+ * textDirection argument passed here is either (1) AUTO_TEXT_DIRECTION, or
+ * (2) 0 (i.e. match orientation) or FLIP_TEXT_DIRECTION (mismatch orientation).
+ */
+ if (textDirection == AUTO_TEXT_DIRECTION) {
+ state |= HAS_AUTO_DIRECTION;
+ textDirection = (style ^ BidiUtil.resolveTextDirection (text)) == 0 ? 0 : SWT.FLIP_TEXT_DIRECTION;
+ } else {
+ state &= ~HAS_AUTO_DIRECTION;
+ }
+ if (((style & SWT.FLIP_TEXT_DIRECTION) ^ textDirection) != 0) {
+ style ^= SWT.FLIP_TEXT_DIRECTION;
+ return true;
+ }
+ return textDirection == AUTO_TEXT_DIRECTION;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Label.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Label.java
new file mode 100644
index 000000000..e15b7da73
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Label.java
@@ -0,0 +1,620 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Paul Pazderski - Bug 205199: setImage(null) on Label overrides text
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent a non-selectable
+ * user interface object that displays a string or image.
+ * When SEPARATOR is specified, displays a single
+ * vertical or horizontal line.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#SEPARATOR
+ * @see SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see SWT#SHADOW_IN
+ * @see SWT#SHADOW_OUT
+ * @see SWT#SHADOW_NONE
+ * @see SWT#CENTER
+ * @see SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#WRAP
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Label (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ /*
+ * Feature in Windows 7. When the user double clicks
+ * on the label, the text of the label is copied to the
+ * clipboard. This is unwanted. The fix is to avoid
+ * calling the label window proc.
+ */
+ if (OS.WIN32_VERSION >= OS.VERSION(6, 1)) {
+ switch (msg) {
+ case OS.WM_LBUTTONDBLCLK: return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+ }
+ }
+ return OS.CallWindowProc (LabelProc, hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ style |= SWT.NO_FOCUS;
+ if ((style & SWT.SEPARATOR) != 0) {
+ style = checkBits (style, SWT.VERTICAL, SWT.HORIZONTAL, 0, 0, 0, 0);
+ return checkBits (style, SWT.SHADOW_OUT, SWT.SHADOW_IN, SWT.SHADOW_NONE, 0, 0, 0);
+ }
+ return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0, border = getBorderWidthInPixels ();
+ if ((style & SWT.SEPARATOR) != 0) {
+ int lineWidth = OS.GetSystemMetrics (OS.SM_CXBORDER);
+ if ((style & SWT.HORIZONTAL) != 0) {
+ width = DEFAULT_WIDTH; height = lineWidth * 2;
+ } else {
+ width = lineWidth * 2; height = DEFAULT_HEIGHT;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ width += border * 2; height += border * 2;
+ return new Point (width, height);
+ }
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ boolean drawText = true;
+ boolean drawImage = (bits & OS.SS_OWNERDRAW) == OS.SS_OWNERDRAW;
+ if (drawImage) {
+ if (image != null) {
+ Rectangle rect = image.getBoundsInPixels();
+ width += rect.width;
+ height += rect.height;
+ if (IMAGE_AND_TEXT) {
+ if (text.length () != 0) width += MARGIN;
+ } else {
+ drawText = false;
+ }
+ }
+ }
+ if (drawText) {
+ long hDC = OS.GetDC (handle);
+ long newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ long oldFont = OS.SelectObject (hDC, newFont);
+ int length = OS.GetWindowTextLength (handle);
+ if (length == 0) {
+ TEXTMETRIC tm = new TEXTMETRIC ();
+ OS.GetTextMetrics (hDC, tm);
+ height = Math.max (height, tm.tmHeight);
+ } else {
+ RECT rect = new RECT ();
+ int flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_EXPANDTABS;
+ if ((style & SWT.WRAP) != 0 && wHint != SWT.DEFAULT) {
+ flags |= OS.DT_WORDBREAK;
+ rect.right = Math.max (0, wHint - width);
+ }
+ char [] buffer = new char [length + 1];
+ OS.GetWindowText (handle, buffer, length + 1);
+ OS.DrawText (hDC, buffer, length, rect, flags);
+ width += rect.right - rect.left;
+ height = Math.max (height, rect.bottom - rect.top);
+ }
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ width += border * 2;
+ height += border * 2;
+ return new Point (width, height);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state |= THEME_BACKGROUND;
+}
+
+/**
+ * Returns a value which describes the position of the
+ * text or image in the receiver. The value will be one of
+ * LEFT
, RIGHT
or CENTER
+ * unless the receiver is a SEPARATOR
label, in
+ * which case, NONE
is returned.
+ *
+ * @return the alignment
+ *
+ * @exception SWTException
+ *
+ */
+public int getAlignment () {
+ checkWidget ();
+ if ((style & SWT.SEPARATOR) != 0) return 0;
+ if ((style & SWT.LEFT) != 0) return SWT.LEFT;
+ if ((style & SWT.CENTER) != 0) return SWT.CENTER;
+ if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
+ return SWT.LEFT;
+}
+
+/**
+ * Returns the receiver's image if it has one, or null
+ * if it does not.
+ *
+ * @return the receiver's image
+ *
+ * @exception SWTException
+ *
+ */
+public Image getImage () {
+ checkWidget ();
+ return image;
+}
+
+@Override
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns the receiver's text, which will be an empty
+ * string if it has never been set or if the receiver is
+ * a SEPARATOR
label.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException
+ *
+ */
+public String getText () {
+ checkWidget ();
+ if ((style & SWT.SEPARATOR) != 0) return "";
+ return text;
+}
+
+@Override
+boolean mnemonicHit (char key) {
+ Control control = this;
+ while (control.parent != null) {
+ Control [] children = control.parent._getChildren ();
+ int index = 0;
+ while (index < children.length) {
+ if (children [index] == control) break;
+ index++;
+ }
+ index++;
+ if (index < children.length) {
+ if (children [index].setFocus ()) return true;
+ }
+ control = control.parent;
+ }
+ return false;
+}
+
+@Override
+boolean mnemonicMatch (char key) {
+ char mnemonic = findMnemonic (getText ());
+ if (mnemonic == '\0') return false;
+ return Character.toUpperCase (key) == Character.toUpperCase (mnemonic);
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ text = null;
+ image = null;
+}
+
+@Override
+int resolveTextDirection() {
+ return (style & SWT.SEPARATOR) != 0 ? SWT.NONE : BidiUtil.resolveTextDirection (text);
+}
+
+/**
+ * Controls how text and images will be displayed in the receiver.
+ * The argument should be one of LEFT
, RIGHT
+ * or CENTER
. If the receiver is a SEPARATOR
+ * label, the argument is ignored and the alignment is not changed.
+ *
+ * @param alignment the new alignment
+ *
+ * @exception SWTException
+ *
+ */
+public void setAlignment (int alignment) {
+ checkWidget ();
+ if ((style & SWT.SEPARATOR) != 0) return;
+ if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
+ style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.SS_OWNERDRAW) != OS.SS_OWNERDRAW) {
+ bits &= ~(OS.SS_LEFTNOWORDWRAP | OS.SS_CENTER | OS.SS_RIGHT);
+ if ((style & SWT.LEFT) != 0) {
+ if ((style & SWT.WRAP) != 0) {
+ bits |= OS.SS_LEFT;
+ } else {
+ bits |= OS.SS_LEFTNOWORDWRAP;
+ }
+ }
+ if ((style & SWT.CENTER) != 0) bits |= OS.SS_CENTER;
+ if ((style & SWT.RIGHT) != 0) bits |= OS.SS_RIGHT;
+ OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+ }
+ OS.InvalidateRect (handle, null, true);
+}
+
+/**
+ * Sets the receiver's image to the argument, which may be
+ * null indicating that no image should be displayed.
+ *
+ * @param image the image to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setImage (Image image) {
+ checkWidget ();
+ if ((style & SWT.SEPARATOR) != 0) return;
+ if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ this.image = image;
+ updateStyleBits(image == null);
+ OS.InvalidateRect (handle, null, true);
+}
+
+/**
+ * Sets the receiver's text.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((style & SWT.SEPARATOR) != 0) return;
+ updateStyleBits(true);
+ /*
+ * Feature in Windows. For some reason, SetWindowText() for
+ * static controls redraws the control, even when the text has
+ * has not changed. The fix is to check for this case and do
+ * nothing.
+ */
+ if (string.equals (text)) return;
+ text = string;
+ string = Display.withCrLf (string);
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ OS.SetWindowText (handle, buffer);
+ if ((state & HAS_AUTO_DIRECTION) != 0) {
+ updateTextDirection (AUTO_TEXT_DIRECTION);
+ }
+}
+
+/**
+ * Update the control's static style bits to reflect the changed image vs. text
+ * situation.
+ *
+ * @param showText if true
set required style bits to render text
+ * otherwise to render the image
+ */
+void updateStyleBits(boolean showText) {
+ if (showText) {
+ int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
+ newBits &= ~OS.SS_OWNERDRAW;
+ if ((style & SWT.LEFT) != 0) {
+ if ((style & SWT.WRAP) != 0) {
+ newBits |= OS.SS_LEFT;
+ } else {
+ newBits |= OS.SS_LEFTNOWORDWRAP;
+ }
+ }
+ if ((style & SWT.CENTER) != 0) newBits |= OS.SS_CENTER;
+ if ((style & SWT.RIGHT) != 0) newBits |= OS.SS_RIGHT;
+ if (oldBits != newBits) OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
+ } else {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.SS_OWNERDRAW) != OS.SS_OWNERDRAW) {
+ bits &= ~(OS.SS_LEFTNOWORDWRAP | OS.SS_CENTER | OS.SS_RIGHT);
+ bits |= OS.SS_OWNERDRAW;
+ OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+ }
+ }
+}
+
+@Override
+int widgetExtStyle () {
+ int bits = super.widgetExtStyle () & ~OS.WS_EX_CLIENTEDGE;
+ if ((style & SWT.BORDER) != 0) return bits | OS.WS_EX_STATICEDGE;
+ return bits;
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle () | OS.SS_NOTIFY;
+ if ((style & SWT.SEPARATOR) != 0) return bits | OS.SS_OWNERDRAW;
+ if ((style & SWT.WRAP) != 0) bits |= OS.SS_EDITCONTROL;
+ if ((style & SWT.CENTER) != 0) return bits | OS.SS_CENTER;
+ if ((style & SWT.RIGHT) != 0) return bits | OS.SS_RIGHT;
+ if ((style & SWT.WRAP) != 0) return bits | OS.SS_LEFT;
+ return bits | OS.SS_LEFTNOWORDWRAP;
+}
+
+@Override
+TCHAR windowClass () {
+ return LabelClass;
+}
+
+@Override
+long windowProc () {
+ return LabelProc;
+}
+
+@Override
+LRESULT WM_ERASEBKGND (long wParam, long lParam) {
+ LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
+ if (result != null) return result;
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.SS_OWNERDRAW) == OS.SS_OWNERDRAW) {
+ return LRESULT.ONE;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ if (isDisposed ()) return result;
+ if ((style & SWT.SEPARATOR) != 0) {
+ OS.InvalidateRect (handle, null, true);
+ return result;
+ }
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.SS_OWNERDRAW) == OS.SS_OWNERDRAW) {
+ OS.InvalidateRect (handle, null, true);
+ return result;
+ }
+ /*
+ * Bug in Windows. For some reason, a label with
+ * style SS_LEFT, SS_CENTER or SS_RIGHT does not
+ * redraw the text in the new position when resized.
+ * Note that SS_LEFTNOWORDWRAP does not have the
+ * problem. The fix is to force the redraw.
+ */
+ if ((bits & OS.SS_LEFTNOWORDWRAP) != OS.SS_LEFTNOWORDWRAP) {
+ OS.InvalidateRect (handle, null, true);
+ return result;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_UPDATEUISTATE (long wParam, long lParam) {
+ LRESULT result = super.WM_UPDATEUISTATE (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. When WM_UPDATEUISTATE is sent to
+ * a static control, it sends WM_CTLCOLORSTATIC to get the
+ * foreground and background. If any drawing happens in
+ * WM_CTLCOLORSTATIC, it overwrites the contents of the control.
+ * The fix is draw the static without drawing the background
+ * and avoid the static window proc.
+ */
+ boolean redraw = findImageControl () != null;
+ if (!redraw) {
+ if ((state & THEME_BACKGROUND) != 0) {
+ if (OS.IsAppThemed ()) {
+ redraw = findThemeControl () != null;
+ }
+ }
+ }
+ if (redraw) {
+ OS.InvalidateRect (handle, null, false);
+ long code = OS.DefWindowProc (handle, OS.WM_UPDATEUISTATE, wParam, lParam);
+ return new LRESULT (code);
+ }
+ return result;
+}
+
+@Override
+LRESULT wmDrawChild (long wParam, long lParam) {
+ DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
+ OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
+ drawBackground (struct.hDC);
+ if ((style & SWT.SEPARATOR) != 0) {
+ if ((style & SWT.SHADOW_NONE) != 0) return null;
+ RECT rect = new RECT ();
+ int lineWidth = OS.GetSystemMetrics (OS.SM_CXBORDER);
+ int flags = (style & SWT.SHADOW_IN) != 0 ? OS.EDGE_SUNKEN : OS.EDGE_ETCHED;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ int bottom = struct.top + Math.max (lineWidth * 2, (struct.bottom - struct.top) / 2);
+ OS.SetRect (rect, struct.left, struct.top, struct.right, bottom);
+ OS.DrawEdge (struct.hDC, rect, flags, OS.BF_BOTTOM);
+ } else {
+ int right = struct.left + Math.max (lineWidth * 2, (struct.right - struct.left) / 2);
+ OS.SetRect (rect, struct.left, struct.top, right, struct.bottom);
+ OS.DrawEdge (struct.hDC, rect, flags, OS.BF_RIGHT);
+ }
+ } else {
+ int width = struct.right - struct.left;
+ int height = struct.bottom - struct.top;
+ if (width != 0 && height != 0) {
+ boolean drawImage = image != null;
+ boolean drawText = IMAGE_AND_TEXT && text.length () != 0;
+ int margin = drawText && drawImage ? MARGIN : 0;
+ int imageWidth = 0, imageHeight = 0;
+ if (drawImage) {
+ Rectangle rect = image.getBoundsInPixels ();
+ imageWidth = rect.width;
+ imageHeight = rect.height;
+ }
+ RECT rect = null;
+ char [] buffer = null;
+ int textWidth = 0, textHeight = 0, flags = 0;
+ if (drawText) {
+ rect = new RECT ();
+ flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_EXPANDTABS;
+ if ((style & SWT.LEFT) != 0) flags |= OS.DT_LEFT;
+ if ((style & SWT.CENTER) != 0) flags |= OS.DT_CENTER;
+ if ((style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT;
+ if ((style & SWT.WRAP) != 0) {
+ flags |= OS.DT_WORDBREAK;
+ rect.right = Math.max (0, width - imageWidth - margin);
+ }
+ buffer = text.toCharArray ();
+ OS.DrawText (struct.hDC, buffer, buffer.length, rect, flags);
+ textWidth = rect.right - rect.left;
+ textHeight = rect.bottom - rect.top;
+ }
+ int x = 0;
+ if ((style & SWT.CENTER) != 0) {
+ x = Math.max (0, (width - imageWidth - textWidth - margin) / 2);
+ } else {
+ if ((style & SWT.RIGHT) != 0) {
+ x = width - imageWidth - textWidth - margin;
+ }
+ }
+ if (drawImage) {
+ GCData data = new GCData();
+ data.device = display;
+ GC gc = GC.win32_new (struct.hDC, data);
+ Image image = getEnabled () ? this.image : new Image (display, this.image, SWT.IMAGE_DISABLE);
+ gc.drawImage (image, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(Math.max (0, (height - imageHeight) / 2)));
+ if (image != this.image) image.dispose ();
+ gc.dispose ();
+ x += imageWidth + margin;
+ }
+ if (drawText) {
+ flags &= ~OS.DT_CALCRECT;
+ rect.left = x;
+ rect.right += rect.left;
+ rect.top = Math.max (0, (height - textHeight) / 2);
+ rect.bottom += rect.top;
+ OS.DrawText (struct.hDC, buffer, buffer.length, rect, flags);
+ }
+ }
+ }
+ return null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Layout.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Layout.java
new file mode 100644
index 000000000..980c701f4
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Layout.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.graphics.*;
+
+/**
+ * A layout controls the position and size
+ * of the children of a composite widget.
+ * This class is the abstract base class for
+ * layouts.
+ *
+ * @see Composite#setLayout(Layout)
+ * @see Sample code and further information
+ */
+public abstract class Layout {
+
+/**
+ * Computes and returns the size of the specified
+ * composite's client area according to this layout.
+ * SWT.DEFAULT
for preferred size)
+ * @param hHint height (SWT.DEFAULT
for preferred size)
+ * @param flushCache true
means flush cached layout values
+ * @return a point containing the computed size (width, height)
+ *
+ * @see #layout
+ * @see Control#getBorderWidth
+ * @see Control#getBounds
+ * @see Control#getSize
+ * @see Control#pack(boolean)
+ * @see "computeTrim, getClientArea for controls that implement them"
+ */
+protected abstract Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache);
+
+/**
+ * Instruct the layout to flush any cached values
+ * associated with the control specified in the argument
+ * control
.
+ *
+ * @param control a control managed by this layout
+ * @return true if the Layout has flushed all cached information associated with control
+ *
+ * @since 3.1
+ */
+protected boolean flushCache (Control control) {
+ return false;
+}
+
+/**
+ * Lays out the children of the specified composite
+ * according to this layout.
+ * true
means flush cached layout values
+ */
+protected abstract void layout (Composite composite, boolean flushCache);
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Link.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Link.java
new file mode 100644
index 000000000..12af3a09c
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Link.java
@@ -0,0 +1,741 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Conrad Groth - Bug 401015 - [CSS] Add support for styling hyperlinks in Links
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import java.util.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent a selectable
+ * user interface object that displays a text with
+ * links.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Link (Composite parent, int style) {
+ super (parent, style);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the control is selected by the user, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called when the control is selected by the user.
+ * widgetDefaultSelected
is not called.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection, typedListener);
+ addListener (SWT.DefaultSelection, typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ /*
+ * Feature in Windows. By convention, native Windows controls
+ * check for a non-NULL wParam, assume that it is an HDC and
+ * paint using that device. The SysLink control does not.
+ * The fix is to check for an HDC and use WM_PRINTCLIENT.
+ */
+ switch (msg) {
+ case OS.WM_PAINT:
+ if (wParam != 0) {
+ OS.SendMessage (hwnd, OS.WM_PRINTCLIENT, wParam, 0);
+ return 0;
+ }
+ break;
+ }
+ return OS.CallWindowProc (LinkProc, hwnd, msg, wParam, lParam);
+}
+
+@Override
+Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width, height;
+ /*
+ * When the text is empty, LM_GETIDEALSIZE returns zero width and height,
+ * but SWT convention is to return zero width and line height.
+ */
+ if (text.isEmpty()) {
+ long hDC = OS.GetDC (handle);
+ long newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ long oldFont = OS.SelectObject (hDC, newFont);
+ TEXTMETRIC lptm = new TEXTMETRIC ();
+ OS.GetTextMetrics (hDC, lptm);
+ width = 0;
+ height = lptm.tmHeight;
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ } else {
+ SIZE size = new SIZE ();
+ int maxWidth = (wHint == SWT.DEFAULT) ? 0x7fffffff : wHint;
+ OS.SendMessage (handle, OS.LM_GETIDEALSIZE, maxWidth, size);
+ width = size.cx;
+ height = size.cy;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ int border = getBorderWidthInPixels ();
+ width += border * 2;
+ height += border * 2;
+ return new Point (width, height);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state |= THEME_BACKGROUND;
+}
+
+@Override
+void createWidget () {
+ super.createWidget ();
+ text = "";
+ ids = new String[0];
+ mnemonics = new char[0];
+}
+
+@Override
+void enableWidget (boolean enabled) {
+ super.enableWidget (enabled);
+ /*
+ * Feature in Windows. SysLink32 control doesn't natively
+ * provide disabled state. Emulate it with custom draw.
+ */
+ OS.InvalidateRect (handle, null, true);
+}
+
+int getFocusItem () {
+ LITEM item = new LITEM ();
+ item.mask = OS.LIF_ITEMINDEX | OS.LIF_STATE;
+ item.stateMask = OS.LIS_FOCUSED;
+ while (OS.SendMessage (handle, OS.LM_GETITEM, 0, item) != 0) {
+ if ((item.state & OS.LIS_FOCUSED) != 0) {
+ return item.iLink;
+ }
+ item.iLink++;
+ }
+ return -1;
+}
+
+/**
+ * Returns the link foreground color.
+ *
+ * @return the receiver's link foreground color.
+ *
+ * @exception SWTException
+ *
+ * @since 3.105
+ */
+public Color getLinkForeground () {
+ checkWidget ();
+ if (linkForeground != -1) {
+ return Color.win32_new (display, linkForeground);
+ }
+ return Color.win32_new (display, OS.GetSysColor (OS.COLOR_HOTLIGHT));
+}
+
+@Override
+String getNameText () {
+ return getText ();
+}
+
+/**
+ * Returns the receiver's text, which will be an empty
+ * string if it has never been set.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException
+ *
+ */
+public String getText () {
+ checkWidget ();
+ return text;
+}
+
+@Override
+boolean mnemonicHit (char key) {
+ char uckey = Character.toUpperCase (key);
+ for (int i = 0; i < mnemonics.length; i++) {
+ if (uckey == mnemonics[i]) {
+ nextFocusItem = i;
+ return setFocus () && setFocusItem (i);
+ }
+ }
+ return false;
+}
+
+@Override
+boolean mnemonicMatch (char key) {
+ char uckey = Character.toUpperCase (key);
+ for (int i = 0; i < mnemonics.length; i++) {
+ if (uckey == mnemonics[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void parse (String string) {
+ int length = string.length ();
+ // The shortest link length is 7 characters ().
+ ids = new String [length / 7];
+ mnemonics = new char [length / 7];
+ int index = 0, state = 0, linkIndex = 0;
+ int linkStart = 0, linkEnd = 0, refStart = 0, refEnd = 0;
+ char mnemonic = 0;
+ while (index < length) {
+ char c = Character.toLowerCase (string.charAt (index));
+ switch (state) {
+ case 0:
+ if (c == '<') {
+ state++;
+ } else if (c == '&') {
+ state = 16;
+ }
+ break;
+ case 1:
+ if (c == 'a') state++;
+ break;
+ case 2:
+ switch (c) {
+ case 'h':
+ state = 7;
+ break;
+ case '>':
+ linkStart = index + 1;
+ state++;
+ break;
+ default:
+ if (Character.isWhitespace(c)) break;
+ else state = 13;
+ }
+ break;
+ case 3:
+ if (c == '<') {
+ linkEnd = index;
+ state++;
+ }
+ break;
+ case 4:
+ state = c == '/' ? state + 1 : 3;
+ break;
+ case 5:
+ state = c == 'a' ? state + 1 : 3;
+ break;
+ case 6:
+ if (c == '>') {
+ if (refStart == 0) {
+ refStart = linkStart;
+ refEnd = linkEnd;
+ }
+ ids [linkIndex] = string.substring(refStart, refEnd);
+ if (mnemonic != 0) {
+ mnemonics [linkIndex] = mnemonic;
+ }
+ linkIndex++;
+ linkStart = linkEnd = refStart = refEnd = mnemonic = 0;
+ state = 0;
+ } else {
+ state = 3;
+ }
+ break;
+ case 7:
+ state = c == 'r' ? state + 1 : 0;
+ break;
+ case 8:
+ state = c == 'e' ? state + 1 : 0;
+ break;
+ case 9:
+ state = c == 'f' ? state + 1 : 0;
+ break;
+ case 10:
+ state = c == '=' ? state + 1 : 0;
+ break;
+ case 11:
+ if (c == '"') {
+ state++;
+ refStart = index + 1;
+ } else {
+ state = 0;
+ }
+ break;
+ case 12:
+ if (c == '"') {
+ refEnd = index;
+ state = 2;
+ }
+ break;
+ case 13:
+ if (Character.isWhitespace (c)) {
+ state = 0;
+ } else if (c == '='){
+ state++;
+ }
+ break;
+ case 14:
+ state = c == '"' ? state + 1 : 0;
+ break;
+ case 15:
+ if (c == '"') state = 2;
+ break;
+ case 16:
+ if (c == '<') {
+ state = 1;
+ } else {
+ state = 0;
+ if (c != '&') mnemonic = Character.toUpperCase (c);
+ }
+ break;
+ default:
+ state = 0;
+ break;
+ }
+ index++;
+ }
+ ids = Arrays.copyOf(ids, linkIndex);
+ mnemonics = Arrays.copyOf(mnemonics, linkIndex);
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ ids = null;
+ mnemonics = null;
+ text = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection, listener);
+}
+
+boolean setFocusItem (int index) {
+ int bits = 0;
+ if (index > 0) {
+ bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ }
+ LITEM item = new LITEM ();
+ item.mask = OS.LIF_ITEMINDEX | OS.LIF_STATE;
+ item.stateMask = OS.LIS_FOCUSED;
+ int activeIndex = getFocusItem ();
+ if (activeIndex == index) return true;
+ if (activeIndex >= 0) {
+ /* Feature in Windows. Unfocus any element unfocus all elements.
+ * For example if item 2 is focused and we set unfocus (state = 0)
+ * for item 0 Windows will remove the focus state for item 2
+ * (getFocusItem() == -1) but fail to remove the focus border around
+ * the link. The fix is to only unfocus the element which has focus.
+ */
+ item.iLink = activeIndex;
+ OS.SendMessage (handle, OS.LM_SETITEM, 0, item);
+ }
+ item.iLink = index;
+ item.state = OS.LIS_FOCUSED;
+ long result = OS.SendMessage (handle, OS.LM_SETITEM, 0, item);
+
+ if (index > 0) {
+ /* Feature in Windows. For some reason, setting the focus to
+ * any item but first causes the control to clear the WS_TABSTOP
+ * bit. The fix is always to reset the bit.
+ */
+ OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+ }
+ return result != 0;
+}
+
+/**
+ * Sets the link foreground color to the color specified
+ * by the argument, or to the default system color for the link
+ * if the argument is null.
+ *
+ *
+ * @exception SWTException
+ *
+ * @since 3.105
+ */
+public void setLinkForeground (Color color) {
+ checkWidget ();
+ int pixel = -1;
+ if (color != null) {
+ if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ pixel = color.handle;
+ }
+ if (pixel == linkForeground) return;
+ linkForeground = pixel;
+ OS.InvalidateRect (handle, null, true);
+}
+
+/**
+ * Sets the receiver's text.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (string.equals (text)) return;
+ text = string;
+ if ((state & HAS_AUTO_DIRECTION) != 0) {
+ updateTextDirection (AUTO_TEXT_DIRECTION);
+ }
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ OS.SetWindowText (handle, buffer);
+ parse(string);
+}
+
+@Override
+int resolveTextDirection() {
+ return BidiUtil.resolveTextDirection(text);
+}
+
+@Override
+boolean updateTextDirection(int textDirection) {
+ if (super.updateTextDirection(textDirection)) {
+ int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT;
+ style &= ~SWT.MIRRORED;
+ style &= ~flags;
+ style |= textDirection & flags;
+ updateOrientation ();
+ checkMirrored ();
+ return true;
+ }
+ return false;
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle ();
+ return bits | OS.WS_TABSTOP;
+}
+
+@Override
+TCHAR windowClass () {
+ return LinkClass;
+}
+
+@Override
+long windowProc () {
+ return LinkProc;
+}
+
+@Override
+LRESULT WM_CHAR (long wParam, long lParam) {
+ LRESULT result = super.WM_CHAR (wParam, lParam);
+ if (result != null) return result;
+ switch ((int)wParam) {
+ case SWT.SPACE:
+ case SWT.CR:
+ case SWT.TAB:
+ /*
+ * NOTE: Call the window proc with WM_KEYDOWN rather than WM_CHAR
+ * so that the key that was ignored during WM_KEYDOWN is processed.
+ * This allows the application to cancel an operation that is normally
+ * performed in WM_KEYDOWN from WM_CHAR.
+ */
+ long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam);
+ return new LRESULT (code);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_GETDLGCODE (long wParam, long lParam) {
+ long code = callWindowProc (handle, OS.WM_GETDLGCODE, wParam, lParam);
+ int count = ids.length;
+ if (count == 0) {
+ code |= OS.DLGC_STATIC;
+ } else if (count > 1) {
+ int limit = (OS.GetKeyState (OS.VK_SHIFT) < 0) ? 0 : count - 1;
+ if (getFocusItem() != limit) {
+ code |= OS.DLGC_WANTTAB;
+ }
+ }
+ return new LRESULT (code);
+}
+
+@Override
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_KEYDOWN (wParam, lParam);
+ if (result != null) return result;
+ switch ((int)wParam) {
+ case OS.VK_SPACE:
+ case OS.VK_RETURN:
+ case OS.VK_TAB:
+ /*
+ * Ensure that the window proc does not process VK_SPACE,
+ * VK_RETURN or VK_TAB so that it can be handled in WM_CHAR.
+ * This allows the application to cancel an operation that
+ * is normally performed in WM_KEYDOWN from WM_CHAR.
+ */
+ return LRESULT.ZERO;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_KILLFOCUS (long wParam, long lParam) {
+ nextFocusItem = getFocusItem();
+ return super.WM_KILLFOCUS(wParam, lParam);
+}
+
+@Override
+LRESULT WM_NCHITTEST (long wParam, long lParam) {
+ LRESULT result = super.WM_NCHITTEST (wParam, lParam);
+ if (result != null) return result;
+
+ /*
+ * Feature in Windows. For WM_NCHITTEST, the Syslink window proc
+ * returns HTTRANSPARENT when mouse is over plain text. As a result,
+ * mouse events are not delivered. The fix is to always return HTCLIENT.
+ */
+ return new LRESULT (OS.HTCLIENT);
+}
+
+@Override
+LRESULT WM_SETCURSOR(long wParam, long lParam) {
+ LRESULT result = super.WM_SETCURSOR (wParam, lParam);
+ if (result != null) return result;
+ long fDone = callWindowProc (handle, OS.WM_SETCURSOR, wParam, lParam);
+ /* Take responsibility for cursor over plain text after overriding WM_NCHITTEST. */
+ if (fDone == 0) OS.DefWindowProc (handle, OS.WM_SETCURSOR, wParam, lParam);
+ return LRESULT.ONE;
+}
+
+@Override
+LRESULT WM_SETFOCUS (long wParam, long lParam) {
+ /*
+ * Feature in Windows. Upon receiving focus, SysLink control
+ * always activates the first link. This leads to surprising
+ * behavior in multi-link controls.
+ */
+ if (ids.length > 1) {
+ if (OS.GetKeyState (OS.VK_TAB) < 0) {
+ if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
+ // reverse tab; focus on last item
+ setFocusItem(ids.length - 1);
+ }
+ } else if (nextFocusItem > 0) {
+ setFocusItem(nextFocusItem);
+ }
+ }
+ return super.WM_SETFOCUS (wParam, lParam);
+}
+
+@Override
+LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
+ switch (hdr.code) {
+ case OS.NM_RETURN:
+ case OS.NM_CLICK:
+ NMLINK item = new NMLINK ();
+ OS.MoveMemory (item, lParam, NMLINK.sizeof);
+ Event event = new Event ();
+ event.text = ids [item.iLink];
+ sendSelectionEvent (SWT.Selection, event, true);
+ break;
+ case OS.NM_CUSTOMDRAW:
+ NMCUSTOMDRAW nmcd = new NMCUSTOMDRAW ();
+ OS.MoveMemory (nmcd, lParam, NMCUSTOMDRAW.sizeof);
+ switch (nmcd.dwDrawStage) {
+ case OS.CDDS_PREPAINT:
+ if (!OS.IsWindowEnabled (handle) || linkForeground != -1) {
+ return new LRESULT(OS.CDRF_NOTIFYITEMDRAW);
+ }
+ break;
+ case OS.CDDS_ITEMPREPAINT:
+ /*
+ * Feature in Windows. SysLink32 control doesn't natively
+ * provide disabled state. Emulate it with custom draw.
+ */
+ if (!OS.IsWindowEnabled (handle)) {
+ OS.SetTextColor (nmcd.hdc, OS.GetSysColor (OS.COLOR_GRAYTEXT));
+ }
+ else if (linkForeground != -1 && nmcd.dwItemSpec != -1) {
+ OS.SetTextColor(nmcd.hdc, linkForeground);
+ }
+ break;
+ }
+ break;
+ }
+ return super.wmNotifyChild (hdr, wParam, lParam);
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/List.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/List.java
new file mode 100644
index 000000000..604da205e
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/List.java
@@ -0,0 +1,1852 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent a selectable user interface
+ * object that displays a list of strings and issues notification
+ * when a string is selected. A list may be single or multi select.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#SINGLE
+ * @see SWT#MULTI
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public List (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+/**
+ * Adds the argument to the end of the receiver's list.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #add(String,int)
+ */
+public void add (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ int result = (int)OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer);
+ if (result == OS.LB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
+ if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer.chars, true);
+}
+/**
+ * Adds the argument to the receiver's list at the given
+ * zero-relative index.
+ * getItemCount()
as the
+ * index or use add(String)
.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #add(String)
+ */
+public void add (String string, int index) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (index == -1) error (SWT.ERROR_INVALID_RANGE);
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ int result = (int)OS.SendMessage (handle, OS.LB_INSERTSTRING, index, buffer);
+ if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
+ if (result == OS.LB_ERR) {
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (0 <= index && index <= count) {
+ error (SWT.ERROR_ITEM_NOT_ADDED);
+ } else {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ }
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer.chars, true);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called when the selection changes.
+ * widgetDefaultSelected
is typically called when an item is double-clicked.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ boolean redraw = false;
+ switch (msg) {
+ case OS.WM_HSCROLL:
+ case OS.WM_VSCROLL: {
+ redraw = findImageControl () != null && getDrawing() && OS.IsWindowVisible (handle);
+ if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
+ break;
+ }
+ }
+ long code = OS.CallWindowProc (ListProc, hwnd, msg, wParam, lParam);
+ switch (msg) {
+ case OS.WM_HSCROLL:
+ case OS.WM_VSCROLL: {
+ if (redraw) {
+ OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
+ OS.InvalidateRect (handle, null, true);
+ }
+ break;
+ }
+ }
+ return code;
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0;
+ if (wHint == SWT.DEFAULT) {
+ if ((style & SWT.H_SCROLL) != 0) {
+ width = (int)OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0);
+ width -= INSET;
+ } else {
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ long newFont, oldFont = 0;
+ long hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ RECT rect = new RECT ();
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
+ char [] buffer = new char [64 + 1];
+ for (int i=0; i
+ *
+ * @exception SWTException
+ *
+ */
+public void deselect (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (indices.length == 0) return;
+ if ((style & SWT.SINGLE) != 0) {
+ int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
+ if (oldIndex == OS.LB_ERR) return;
+ for (int i=0; i
+ *
+ */
+public void deselect (int start, int end) {
+ checkWidget ();
+ if (start > end) return;
+ if ((style & SWT.SINGLE) != 0) {
+ int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
+ if (oldIndex == OS.LB_ERR) return;
+ if (start <= oldIndex && oldIndex <= end) {
+ OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
+ }
+ return;
+ }
+ /*
+ * Ensure that at least one item is contained in
+ * the range from start to end. Note that when
+ * start = end, LB_SELITEMRANGEEX deselects the
+ * item.
+ */
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (start < 0 && end < 0) return;
+ if (start >= count && end >= count) return;
+ start = Math.min (count - 1, Math.max (0, start));
+ end = Math.min (count - 1, Math.max (0, end));
+ OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, end, start);
+}
+
+/**
+ * Deselects all selected items in the receiver.
+ *
+ * @exception SWTException
+ *
+ */
+public void deselectAll () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
+ } else {
+ OS.SendMessage (handle, OS.LB_SETSEL, 0, -1);
+ }
+}
+
+/**
+ * Returns the zero-relative index of the item which currently
+ * has the focus in the receiver, or -1 if no item has focus.
+ *
+ * @return the index of the selected item
+ *
+ * @exception SWTException
+ *
+ */
+public int getFocusIndex () {
+ checkWidget ();
+ int result = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
+ if (result == 0) {
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (count == 0) return -1;
+ }
+ return result;
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public String getItem (int index) {
+ checkWidget ();
+ int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
+ if (length != OS.LB_ERR) {
+ char [] buffer = new char [length + 1];
+ int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
+ if (result != OS.LB_ERR) return ((state & HAS_AUTO_DIRECTION) != 0) ? new String (buffer, 1, length - 1) : new String (buffer, 0, length);
+ }
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (0 <= index && index < count) error (SWT.ERROR_CANNOT_GET_ITEM);
+ error (SWT.ERROR_INVALID_RANGE);
+ return "";
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemCount () {
+ checkWidget ();
+ int result = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
+ return result;
+}
+
+/**
+ * Returns the height of the area which would be used to
+ * display one of the items in the list.
+ *
+ * @return the height of one item
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemHeight () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getItemHeightInPixels());
+}
+
+int getItemHeightInPixels () {
+ int result = (int)OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
+ if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
+ return result;
+}
+
+/**
+ * Returns a (possibly empty) array of String
s which
+ * are the items in the receiver.
+ *
+ *
+ */
+public String [] getItems () {
+ checkWidget ();
+ int count = getItemCount ();
+ String [] result = new String [count];
+ for (int i=0; i
+ *
+ */
+public String [] getSelection () {
+ checkWidget ();
+ int [] indices = getSelectionIndices ();
+ String [] result = new String [indices.length];
+ for (int i=0; i
+ *
+ */
+public int getSelectionIndex () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ return (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
+ }
+ int count = (int)OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
+ if (count == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
+ if (count == 0) return -1;
+ int index = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
+ int result = (int)OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
+ if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
+ if (result != 0) return index;
+ int [] buffer = new int[1];
+ result = (int)OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, buffer);
+ if (result != 1) error (SWT.ERROR_CANNOT_GET_SELECTION);
+ return buffer [0];
+}
+
+/**
+ * Returns the zero-relative indices of the items which are currently
+ * selected in the receiver. The order of the indices is unspecified.
+ * The array is empty if no items are selected.
+ *
+ *
+ */
+public int [] getSelectionIndices () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) {
+ int result = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
+ if (result == OS.LB_ERR) return new int [0];
+ return new int [] {result};
+ }
+ int length = (int)OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
+ if (length == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
+ int [] indices = new int [length];
+ int result = (int)OS.SendMessage (handle, OS.LB_GETSELITEMS, length, indices);
+ if (result != length) error (SWT.ERROR_CANNOT_GET_SELECTION);
+ return indices;
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * at the top of the receiver. This index can change when items are
+ * scrolled or new items are added or removed.
+ *
+ * @return the index of the top item
+ *
+ * @exception SWTException
+ *
+ */
+public int getTopIndex () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+}
+
+/**
+ * Gets the index of an item.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public int indexOf (String string) {
+ return indexOf (string, 0);
+}
+
+/**
+ * Searches the receiver's list starting at the given,
+ * zero-relative index until an item is found that is equal
+ * to the argument, and returns the index of that item. If
+ * no item is found or the starting index is out of range,
+ * returns -1.
+ *
+ * @param string the search item
+ * @param start the zero-relative index at which to start the search
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public int indexOf (String string, int start) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+
+ /*
+ * Bug in Windows. For some reason, LB_FINDSTRINGEXACT
+ * will not find empty strings even though it is legal
+ * to insert an empty string into a list. The fix is
+ * to search the list, an item at a time.
+ */
+ if (string.length () == 0) {
+ int count = getItemCount ();
+ for (int i=start; ifalse
otherwise. Indices out of
+ * range are ignored.
+ *
+ * @param index the index of the item
+ * @return the selection state of the item at the index
+ *
+ * @exception SWTException
+ *
+ */
+public boolean isSelected (int index) {
+ checkWidget ();
+ int result = (int)OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
+ return (result != 0) && (result != OS.LB_ERR);
+}
+
+/**
+ * Removes the items from the receiver at the given
+ * zero-relative indices.
+ *
+ * @param indices the array of indices of the items
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void remove (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (indices.length == 0) return;
+ int [] newIndices = new int [indices.length];
+ System.arraycopy (indices, 0, newIndices, 0, indices.length);
+ sort (newIndices);
+ int start = newIndices [newIndices.length - 1], end = newIndices [0];
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (!(0 <= start && start <= end && end < count)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+ RECT rect = null;
+ long hDC = 0, oldFont = 0, newFont = 0;
+ int newWidth = 0;
+ if ((style & SWT.H_SCROLL) != 0) {
+ rect = new RECT ();
+ hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ }
+ int i = 0, topCount = 0, last = -1;
+ while (i < newIndices.length) {
+ int index = newIndices [i];
+ if (index != last) {
+ char [] buffer = null;
+ int length = 0;
+ if ((style & SWT.H_SCROLL) != 0) {
+ length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
+ if (length == OS.LB_ERR) break;
+ buffer = new char [length + 1];
+ int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
+ if (result == OS.LB_ERR) break;
+ }
+ int result = (int)OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0);
+ if (result == OS.LB_ERR) break;
+ if ((style & SWT.H_SCROLL) != 0) {
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
+ OS.DrawText (hDC, buffer, length, rect, flags);
+ newWidth = Math.max (newWidth, rect.right - rect.left);
+ }
+ if (index < topIndex) topCount++;
+ last = index;
+ }
+ i++;
+ }
+ if ((style & SWT.H_SCROLL) != 0) {
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ setScrollWidth (newWidth, false);
+ }
+ if (topCount > 0) {
+ topIndex -= topCount;
+ }
+ OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
+ if (i < newIndices.length) error (SWT.ERROR_ITEM_NOT_REMOVED);
+}
+
+/**
+ * Removes the item from the receiver at the given
+ * zero-relative index.
+ *
+ * @param index the index for the item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void remove (int index) {
+ checkWidget ();
+ char [] buffer = null;
+ if ((style & SWT.H_SCROLL) != 0) {
+ int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
+ if (length == OS.LB_ERR) {
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ buffer = new char [length + 1];
+ int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
+ if (result == OS.LB_ERR) {
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ }
+ int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+ int result = (int)OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0);
+ if (result == OS.LB_ERR) {
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, false);
+ if (index < topIndex) {
+ topIndex -= 1;
+ }
+ OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
+}
+
+/**
+ * Removes the items from the receiver which are
+ * between the given zero-relative start and end
+ * indices (inclusive).
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void remove (int start, int end) {
+ checkWidget ();
+ if (start > end) return;
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (!(0 <= start && start <= end && end < count)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ if (start == 0 && end == count - 1) {
+ removeAll ();
+ return;
+ }
+ int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+ RECT rect = null;
+ long hDC = 0, oldFont = 0, newFont = 0;
+ int newWidth = 0;
+ if ((style & SWT.H_SCROLL) != 0) {
+ rect = new RECT ();
+ hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ }
+ int index = start;
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
+ while (index <= end) {
+ char [] buffer = null;
+ int length = 0;
+ if ((style & SWT.H_SCROLL) != 0) {
+ length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, start, 0);
+ if (length == OS.LB_ERR) break;
+ buffer = new char [length + 1];
+ int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, start, buffer);
+ if (result == OS.LB_ERR) break;
+ }
+ int result = (int)OS.SendMessage (handle, OS.LB_DELETESTRING, start, 0);
+ if (result == OS.LB_ERR) break;
+ if ((style & SWT.H_SCROLL) != 0) {
+ OS.DrawText (hDC, buffer, length, rect, flags);
+ newWidth = Math.max (newWidth, rect.right - rect.left);
+ }
+ index++;
+ }
+ if ((style & SWT.H_SCROLL) != 0) {
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ setScrollWidth (newWidth, false);
+ }
+ if (end < topIndex) {
+ topIndex -= end - start + 1;
+ }
+ OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
+ if (index <= end) error (SWT.ERROR_ITEM_NOT_REMOVED);
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * until an item is found that is equal to the argument,
+ * and removes that item from the list.
+ *
+ * @param string the item to remove
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void remove (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int index = indexOf (string, 0);
+ if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT);
+ remove (index);
+}
+
+/**
+ * Removes all of the items from the receiver.
+ *
+ * @exception SWTException
+ *
+ */
+public void removeAll () {
+ checkWidget ();
+ OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0);
+ if ((style & SWT.H_SCROLL) != 0) {
+ OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0);
+ }
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+/**
+ * Selects the items at the given zero-relative indices in the receiver.
+ * The current selection is not cleared before the new items are selected.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see List#setSelection(int[])
+ */
+public void select (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int length = indices.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ select (indices, false);
+}
+
+void select (int [] indices, boolean scroll) {
+ int i = 0;
+ while (i < indices.length) {
+ int index = indices [i];
+ if (index != -1) {
+ select (index, false);
+ }
+ i++;
+ }
+ if (scroll) showSelection ();
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver's
+ * list. If the item at the index was already selected, it remains
+ * selected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException
+ *
+ */
+public void select (int index) {
+ checkWidget ();
+ select (index, false);
+}
+
+void select (int index, boolean scroll) {
+ if (index < 0) return;
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (index >= count) return;
+ if (scroll) {
+ if ((style & SWT.SINGLE) != 0) {
+ OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0);
+ } else {
+ OS.SendMessage (handle, OS.LB_SETSEL, 1, index);
+ }
+ return;
+ }
+ int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+ RECT itemRect = new RECT (), selectedRect = null;
+ OS.SendMessage (handle, OS.LB_GETITEMRECT, index, itemRect);
+ boolean redraw = getDrawing () && OS.IsWindowVisible (handle);
+ if (redraw) {
+ OS.UpdateWindow (handle);
+ OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
+ }
+ int focusIndex = -1;
+ if ((style & SWT.SINGLE) != 0) {
+ int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
+ if (oldIndex != -1) {
+ selectedRect = new RECT ();
+ OS.SendMessage (handle, OS.LB_GETITEMRECT, oldIndex, selectedRect);
+ }
+ OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0);
+ } else {
+ focusIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
+ OS.SendMessage (handle, OS.LB_SETSEL, 1, index);
+ }
+ if ((style & SWT.MULTI) != 0) {
+ if (focusIndex != -1) {
+ OS.SendMessage (handle, OS.LB_SETCARETINDEX, focusIndex, 0);
+ }
+ }
+ OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
+ if (redraw) {
+ OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
+ OS.ValidateRect (handle, null);
+ OS.InvalidateRect (handle, itemRect, true);
+ if (selectedRect != null) {
+ OS.InvalidateRect (handle, selectedRect, true);
+ }
+ }
+}
+
+/**
+ * Selects the items in the range specified by the given zero-relative
+ * indices in the receiver. The range of indices is inclusive.
+ * The current selection is not cleared before the new items are selected.
+ *
+ *
+ *
+ * @see List#setSelection(int,int)
+ */
+public void select (int start, int end) {
+ checkWidget ();
+ if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (count == 0 || start >= count) return;
+ start = Math.max (0, start);
+ end = Math.min (end, count - 1);
+ if ((style & SWT.SINGLE) != 0) {
+ select (start, false);
+ } else {
+ select (start, end, false);
+ }
+}
+
+void select (int start, int end, boolean scroll) {
+ /*
+ * Note that when start = end, LB_SELITEMRANGEEX
+ * deselects the item.
+ */
+ if (start == end) {
+ select (start, scroll);
+ return;
+ }
+ OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, start, end);
+ if (scroll) showSelection ();
+}
+
+/**
+ * Selects all of the items in the receiver.
+ *
+ *
+ */
+public void selectAll () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return;
+ OS.SendMessage (handle, OS.LB_SETSEL, 1, -1);
+}
+
+void setFocusIndex (int index) {
+// checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (!(0 <= index && index < count)) return;
+ OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0);
+}
+
+@Override
+public void setFont (Font font) {
+ checkWidget ();
+ super.setFont (font);
+ if ((style & SWT.H_SCROLL) != 0) setScrollWidth ();
+}
+
+/**
+ * Sets the text of the item in the receiver's list at the given
+ * zero-relative index to the string argument.
+ *
+ * @param index the index for the item
+ * @param string the new text for the item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setItem (int index, String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int topIndex = getTopIndex ();
+ boolean isSelected = isSelected (index);
+ remove (index);
+ add (string, index);
+ if (isSelected) select (index, false);
+ setTopIndex (topIndex);
+}
+
+/**
+ * Sets the receiver's items to be the given array of items.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setItems (String... items) {
+ checkWidget ();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i
+ *
+ * @exception SWTException
+ *
+ *
+ * @see List#deselectAll()
+ * @see List#select(int[])
+ */
+public void setSelection(int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ deselectAll ();
+ int length = indices.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ select (indices, true);
+ if ((style & SWT.MULTI) != 0) {
+ int focusIndex = indices [0];
+ if (focusIndex >= 0) setFocusIndex (focusIndex);
+ }
+}
+
+/**
+ * Sets the receiver's selection to be the given array of items.
+ * The current selection is cleared before the new items are selected,
+ * and if necessary the receiver is scrolled to make the new selection visible.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see List#deselectAll()
+ * @see List#select(int[])
+ * @see List#setSelection(int[])
+ */
+public void setSelection (String [] items) {
+ checkWidget ();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ deselectAll ();
+ int length = items.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ int focusIndex = -1;
+ for (int i=length-1; i>=0; --i) {
+ String string = items [i];
+ int index = 0;
+ if (string != null) {
+ int localFocus = -1;
+ while ((index = indexOf (string, index)) != -1) {
+ if (localFocus == -1) localFocus = index;
+ select (index, false);
+ if ((style & SWT.SINGLE) != 0 && isSelected (index)) {
+ showSelection ();
+ return;
+ }
+ index++;
+ }
+ if (localFocus != -1) focusIndex = localFocus;
+ }
+ }
+ if ((style & SWT.MULTI) != 0) {
+ if (focusIndex >= 0) setFocusIndex (focusIndex);
+ }
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver.
+ * If the item at the index was already selected, it remains selected.
+ * The current selection is first cleared, then the new item is selected,
+ * and if necessary the receiver is scrolled to make the new selection visible.
+ * Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException
+ *
+ * @see List#deselectAll()
+ * @see List#select(int)
+ */
+public void setSelection (int index) {
+ checkWidget ();
+ deselectAll ();
+ select (index, true);
+ if ((style & SWT.MULTI) != 0) {
+ if (index >= 0) setFocusIndex (index);
+ }
+}
+
+/**
+ * Selects the items in the range specified by the given zero-relative
+ * indices in the receiver. The range of indices is inclusive.
+ * The current selection is cleared before the new items are selected,
+ * and if necessary the receiver is scrolled to make the new selection visible.
+ *
+ *
+ *
+ * @see List#deselectAll()
+ * @see List#select(int,int)
+ */
+public void setSelection (int start, int end) {
+ checkWidget ();
+ deselectAll ();
+ if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (count == 0 || start >= count) return;
+ start = Math.max (0, start);
+ end = Math.min (end, count - 1);
+ if ((style & SWT.SINGLE) != 0) {
+ select (start, true);
+ } else {
+ select (start, end, true);
+ setFocusIndex (start);
+ }
+}
+
+/**
+ * Sets the zero-relative index of the item which is currently
+ * at the top of the receiver. This index can change when items
+ * are scrolled or new items are added and removed.
+ *
+ * @param index the index of the top item
+ *
+ * @exception SWTException
+ *
+ */
+public void setTopIndex (int index) {
+ checkWidget ();
+ int result = (int)OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0);
+ if (result == OS.LB_ERR) {
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ index = Math.min (count - 1, Math.max (0, index));
+ OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0);
+ }
+}
+
+/**
+ * Shows the selection. If the selection is already showing in the receiver,
+ * this method simply returns. Otherwise, the items are scrolled until
+ * the selection is visible.
+ *
+ * @exception SWTException
+ *
+ */
+public void showSelection () {
+ checkWidget ();
+ int index;
+ if ((style & SWT.SINGLE) != 0) {
+ index = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
+ } else {
+ int [] indices = new int [1];
+ int result = (int)OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, indices);
+ index = indices [0];
+ if (result != 1) index = -1;
+ }
+ if (index == -1) return;
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (count == 0) return;
+ int height = (int)OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
+ forceResize ();
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+ int visibleCount = Math.max (rect.bottom / height, 1);
+ int bottomIndex = Math.min (topIndex + visibleCount, count) - 1;
+ if (topIndex <= index && index <= bottomIndex) return;
+ int newTop = Math.min (Math.max (index - (visibleCount / 2), 0), count - 1);
+ OS.SendMessage (handle, OS.LB_SETTOPINDEX, newTop, 0);
+}
+
+@Override
+void updateMenuLocation (Event event) {
+ Rectangle clientArea = getClientAreaInPixels ();
+ int x = clientArea.x, y = clientArea.y;
+ int focusIndex = getFocusIndex();
+ if (focusIndex != -1) {
+ RECT rect = new RECT ();
+ long newFont, oldFont = 0;
+ long hDC = OS.GetDC (handle);
+ newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
+ char [] buffer = new char [64 + 1];
+ int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, focusIndex, 0);
+ if (length != OS.LB_ERR) {
+ if (length + 1 > buffer.length) {
+ buffer = new char [length + 1];
+ }
+ int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, focusIndex, buffer);
+ if (result != OS.LB_ERR) {
+ OS.DrawText (hDC, buffer, length, rect, flags);
+ }
+ }
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+ x = Math.max (x, rect.right / 2);
+ x = Math.min (x, clientArea.x + clientArea.width);
+
+ OS.SendMessage (handle, OS.LB_GETITEMRECT, focusIndex, rect);
+ y = Math.max (y, rect.bottom);
+ y = Math.min (y, clientArea.y + clientArea.height);
+ }
+ Point pt = toDisplayInPixels (x, y);
+ event.setLocationInPixels(pt.x, pt.y);
+}
+
+@Override
+boolean updateTextDirection (int textDirection) {
+ if (textDirection == AUTO_TEXT_DIRECTION) {
+ /* If auto is already in effect, there's nothing to do. */
+ if ((state & HAS_AUTO_DIRECTION) != 0) return false;
+ state |= HAS_AUTO_DIRECTION;
+ } else {
+ state &= ~HAS_AUTO_DIRECTION;
+ if (!addedUCC /*(state & HAS_AUTO_DIRECTION) == 0*/) {
+ return super.updateTextDirection (textDirection);
+ }
+ }
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (count == OS.LB_ERR) return false;
+ int selection = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
+ addedUCC = false;
+ while (count-- > 0) {
+ int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, count, 0);
+ if (length == OS.LB_ERR) break;
+ if (length == 0) continue;
+ char [] buffer = new char [length + 1];
+ if (OS.SendMessage (handle, OS.LB_GETTEXT, count, buffer) == OS.LB_ERR) break;
+ if (OS.SendMessage (handle, OS.LB_DELETESTRING, count, 0) == OS.LB_ERR) break;
+ if ((state & HAS_AUTO_DIRECTION) == 0) {
+ /* Should remove UCC */
+ System.arraycopy(buffer, 1, buffer, 0, length);
+ }
+ /* Adding UCC is handled in OS.LB_INSERTSTRING */
+ if (OS.SendMessage (handle, OS.LB_INSERTSTRING, count, buffer) == OS.LB_ERR) break;
+ }
+ if (selection != OS.LB_ERR) {
+ OS.SendMessage (handle, OS.LB_SETCURSEL, selection, 0);
+ }
+ return textDirection == AUTO_TEXT_DIRECTION || super.updateTextDirection (textDirection);
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle () | OS.LBS_NOTIFY | OS.LBS_NOINTEGRALHEIGHT;
+ if ((style & SWT.SINGLE) != 0) return bits;
+ if ((style & SWT.MULTI) != 0) {
+ if ((style & SWT.SIMPLE) != 0) return bits | OS.LBS_MULTIPLESEL;
+ return bits | OS.LBS_EXTENDEDSEL;
+ }
+ return bits;
+}
+
+@Override
+TCHAR windowClass () {
+ return ListClass;
+}
+
+@Override
+long windowProc () {
+ return ListProc;
+}
+
+@Override
+long windowProc (long hwnd, int msg, long wParam, long lParam) {
+ /* Below code is to support auto text direction. */
+ if (handle != 0 && lParam != 0 && (state & HAS_AUTO_DIRECTION) != 0) {
+ switch (msg) {
+ case OS.LB_ADDSTRING:
+ case OS.LB_INSERTSTRING:
+ case OS.LB_FINDSTRINGEXACT:
+ int length = OS.wcslen (lParam); // we are always Unicode here
+ int cp = getCodePage ();
+ TCHAR buffer = new TCHAR (cp, length);
+ OS.MoveMemory (buffer, lParam, buffer.length () * TCHAR.sizeof);
+ String string = buffer.toString (0, length);
+ int direction = BidiUtil.resolveTextDirection (string);
+ if (direction == SWT.NONE) {
+ /*
+ * Force adding a UCC even when no strong characters are found.
+ * Otherwise, the List items would retain the old direction,
+ * which might be inappropriate for the new text.
+ */
+ direction = (style & SWT.RIGHT_TO_LEFT) != 0 ? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT;
+ }
+ string = (direction == SWT.RIGHT_TO_LEFT ? RLE : LRE) + string;
+ buffer = new TCHAR (cp, string, true);
+ long hHeap = OS.GetProcessHeap ();
+ length = buffer.length() * TCHAR.sizeof;
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, length);
+ OS.MoveMemory (pszText, buffer, length);
+ long code = super.windowProc (hwnd, msg, wParam, pszText);
+ OS.HeapFree (hHeap, 0, pszText);
+ addedUCC = true;
+ return code;
+ }
+ }
+ return super.windowProc (hwnd, msg, wParam, lParam);
+}
+
+@Override
+LRESULT WM_CHAR (long wParam, long lParam) {
+ LRESULT result = super.WM_CHAR (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. The Windows list box does not implement
+ * the control key interface for multi-select list boxes, making
+ * it inaccessible from the keyboard. The fix is to implement
+ * the key processing.
+ */
+ if (OS.GetKeyState (OS.VK_CONTROL) < 0 && OS.GetKeyState (OS.VK_SHIFT) >= 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.LBS_EXTENDEDSEL) != 0) {
+ switch ((int)wParam) {
+ case OS.VK_SPACE: {
+ int index = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
+ int code = (int)OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
+ if (code == OS.LB_ERR) break;
+ OS.SendMessage (handle, OS.LB_SETSEL, code != 0 ? 0 : 1, index);
+ OS.SendMessage (handle, OS.LB_SETANCHORINDEX, index, 0);
+ sendSelectionEvent (SWT.Selection);
+ return LRESULT.ZERO;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_KEYDOWN (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. The Windows list box does not implement
+ * the control key interface for multi-select list boxes, making
+ * it inaccessible from the keyboard. The fix is to implement
+ * the key processing.
+ */
+ if (OS.GetKeyState (OS.VK_CONTROL) < 0 && OS.GetKeyState (OS.VK_SHIFT) >= 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.LBS_EXTENDEDSEL) != 0) {
+ int newIndex = -1;
+ switch ((int)wParam) {
+ case OS.VK_SPACE: {
+ /*
+ * Ensure that the window proc does not process VK_SPACE
+ * so that it can be handled in WM_CHAR. This allows the
+ * application to cancel an operation that is normally
+ * performed in WM_KEYDOWN from WM_CHAR.
+ */
+ return LRESULT.ZERO;
+ }
+ case OS.VK_UP:
+ case OS.VK_DOWN: {
+ int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
+ newIndex = Math.max (0, oldIndex + (((int)wParam) == OS.VK_UP ? -1 : 1));
+ break;
+ }
+ case OS.VK_PRIOR: {
+ int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+ int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
+ if (oldIndex != topIndex) {
+ newIndex = topIndex;
+ } else {
+ forceResize ();
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ int itemHeight = (int)OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
+ int pageSize = Math.max (2, (rect.bottom / itemHeight));
+ newIndex = Math.max (0, topIndex - (pageSize - 1));
+ }
+ break;
+ }
+ case OS.VK_NEXT: {
+ int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+ int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
+ forceResize ();
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ int itemHeight = (int)OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
+ int pageSize = Math.max (2, (rect.bottom / itemHeight));
+ int bottomIndex = topIndex + pageSize - 1;
+ if (oldIndex != bottomIndex) {
+ newIndex = bottomIndex;
+ } else {
+ newIndex = bottomIndex + pageSize - 1;
+ }
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (count != OS.LB_ERR) newIndex = Math.min (count - 1, newIndex);
+ break;
+ }
+ case OS.VK_HOME: {
+ newIndex = 0;
+ break;
+ }
+ case OS.VK_END: {
+ int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
+ if (count == OS.LB_ERR) break;
+ newIndex = count - 1;
+ break;
+ }
+ }
+ if (newIndex != -1) {
+ /*
+ * Feature in Windows. When the user changes focus using
+ * the keyboard, the focus indicator does not draw. The
+ * fix is to update the UI state for the control whenever
+ * the focus indicator changes as a result of something
+ * the user types.
+ */
+ int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
+ if ((uiState & OS.UISF_HIDEFOCUS) != 0) {
+ OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
+ /*
+ * Bug in Windows. When the WM_CHANGEUISTATE is used
+ * to update the UI state for a list that has been
+ * selected using Shift+Arrow, the focus indicator
+ * has pixel corruption. The fix is to redraw the
+ * control.
+ */
+ RECT itemRect = new RECT ();
+ int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
+ OS.SendMessage (handle, OS.LB_GETITEMRECT, oldIndex, itemRect);
+ OS.InvalidateRect (handle, itemRect, true);
+ }
+ OS.SendMessage (handle, OS.LB_SETCARETINDEX, newIndex, 0);
+ return LRESULT.ZERO;
+ }
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_SETREDRAW (long wParam, long lParam) {
+ LRESULT result = super.WM_SETREDRAW (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Bug in Windows. When WM_SETREDRAW is used to turn off
+ * redraw for a list, table or tree, the background of the
+ * control is drawn. The fix is to call DefWindowProc(),
+ * which stops all graphics output to the control.
+ */
+ OS.DefWindowProc (handle, OS.WM_SETREDRAW, wParam, lParam);
+ return result;
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ /*
+ * Bug in Windows. If the top index is changed while the
+ * list is being resized, Windows does not redraw properly
+ * when their is white space at the bottom of the control.
+ * The fix is to detect when the top index has changed and
+ * redraw the control.
+ *
+ * Bug in Windows. If the receiver is scrolled horizontally
+ * and is resized, the list does not redraw properly. The fix
+ * is to redraw the control when the horizontal scroll bar is
+ * not at the beginning.
+ */
+ int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ if (!isDisposed ()) {
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_POS;
+ if (OS.GetScrollInfo (handle, OS.SB_HORZ, info)) {
+ if (info.nPos != 0) OS.InvalidateRect (handle, null, true);
+ }
+ int newIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
+ if (oldIndex != newIndex) OS.InvalidateRect (handle, null, true);
+ }
+ return result;
+}
+
+@Override
+LRESULT wmCommandChild (long wParam, long lParam) {
+ int code = OS.HIWORD (wParam);
+ switch (code) {
+ case OS.LBN_SELCHANGE:
+ sendSelectionEvent (SWT.Selection);
+ break;
+ case OS.LBN_DBLCLK:
+ sendSelectionEvent (SWT.DefaultSelection);
+ break;
+ }
+ return super.wmCommandChild (wParam, lParam);
+}
+
+
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Listener.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Listener.java
new file mode 100644
index 000000000..37c5212c1
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Listener.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+/**
+ * Implementers of Listener
provide a simple
+ * handleEvent()
method that is used internally
+ * by SWT to dispatch events.
+ * addListener(int eventType, Listener handler)
method and
+ * removed using the
+ * removeListener (int eventType, Listener handler)
method.
+ * When the specified event occurs, handleEvent(...)
will
+ * be sent to the instance.
+ * java.util.EventListener
pattern.
+ *
+ *
+ * parent.setMenu(menu)
. In this case, the parent may
+ * be any control in the same widget tree as the parent.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#POP_UP
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Menu (Control parent) {
+ this (checkNull (parent).menuShell (), SWT.POP_UP);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a Decorations
) and a style value
+ * describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * parent.setMenu(menu)
or parent.setMenuBar(menuBar)
.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#BAR
+ * @see SWT#DROP_DOWN
+ * @see SWT#POP_UP
+ * @see SWT#NO_RADIO_GROUP
+ * @see SWT#LEFT_TO_RIGHT
+ * @see SWT#RIGHT_TO_LEFT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Menu (Decorations parent, int style) {
+ this (parent, checkStyle (style), 0);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a Menu
) and sets the style
+ * for the instance so that the instance will be a drop-down
+ * menu on the given parent's parent.
+ * parentMenu.setMenu(menu)
.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Menu (Menu parentMenu) {
+ this (checkNull (parentMenu).parent, SWT.DROP_DOWN);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a MenuItem
) and sets the style
+ * for the instance so that the instance will be a drop-down
+ * menu on the given parent's parent menu.
+ * parentItem.setMenu(menu)
.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#DROP_DOWN
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Menu (MenuItem parentItem) {
+ this (checkNull (parentItem).parent);
+}
+
+Menu (Decorations parent, int style, long handle) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+ this.handle = handle;
+ /*
+ * Bug in IBM JVM 1.3.1. For some reason, when the checkOrientation() is
+ * called from createWidget(), the JVM issues this error:
+ *
+ * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8)
+ *
+ * In addition, on Windows XP, a dialog appears with following error message,
+ * indicating that the problem may be in the JIT:
+ *
+ * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll
+ * ModVer: 0.0.0.0 Offset: 000b6912
+ *
+ * The fix is to call checkOrientation() from here.
+ */
+ checkOrientation (parent);
+ createWidget ();
+}
+
+void _setVisible (boolean visible) {
+ if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
+ long hwndParent = parent.handle;
+ if (visible) {
+ int flags = OS.TPM_LEFTBUTTON;
+ if (OS.GetKeyState (OS.VK_LBUTTON) >= 0) flags |= OS.TPM_RIGHTBUTTON;
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) flags |= OS.TPM_RIGHTALIGN;
+ if ((parent.style & SWT.MIRRORED) != 0) {
+ flags &= ~OS.TPM_RIGHTALIGN;
+ if ((style & SWT.LEFT_TO_RIGHT) != 0) flags |= OS.TPM_RIGHTALIGN;
+ }
+ int nX = x, nY = y;
+ if (!hasLocation) {
+ int pos = OS.GetMessagePos ();
+ nX = OS.GET_X_LPARAM (pos);
+ nY = OS.GET_Y_LPARAM (pos);
+ }
+ hasLocation = false;
+ Display display = this.display;
+ display.sendPreExternalEventDispatchEvent ();
+ /*
+ * Feature in Windows. It is legal use TrackPopupMenu()
+ * to display an empty menu as long as menu items are added
+ * inside of WM_INITPOPUPMENU. If no items are added, then
+ * TrackPopupMenu() fails and does not send an indication
+ * that the menu has been closed. This is not strictly a
+ * bug but leads to unwanted behavior when application code
+ * assumes that every WM_INITPOPUPMENU will eventually result
+ * in a WM_MENUSELECT, wParam=MAKEWPARAM (0, 0xFFFF), lParam=0 to
+ * indicate that the menu has been closed. The fix is to detect
+ * the case when TrackPopupMenu() fails and the number of items in
+ * the menu is zero and issue a fake WM_MENUSELECT.
+ */
+ boolean success = OS.TrackPopupMenu (handle, flags, nX, nY, 0, hwndParent, null);
+ // widget could be disposed at this point
+ display.sendPostExternalEventDispatchEvent ();
+ if (!success && OS.GetMenuItemCount (handle) == 0) {
+ OS.SendMessage (hwndParent, OS.WM_MENUSELECT, OS.MAKEWPARAM (0, 0xFFFF), 0);
+ }
+ } else {
+ OS.SendMessage (hwndParent, OS.WM_CANCELMODE, 0, 0);
+ }
+ /*
+ * Bug in Windows. After closing a popup menu, the accessibility focus
+ * is not returned to the focus control. This causes confusion for AT users.
+ * The fix is to explicitly set the accessibility focus back to the focus control.
+ */
+ long hFocus = OS.GetFocus();
+ if (hFocus != 0) {
+ OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, hFocus, OS.OBJID_CLIENT, 0);
+ }
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when help events are generated for the control,
+ * by sending it one of the messages defined in the
+ * HelpListener
interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see HelpListener
+ * @see #removeHelpListener
+ */
+public void addHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Help, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when menus are hidden or shown, by sending it
+ * one of the messages defined in the MenuListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MenuListener
+ * @see #removeMenuListener
+ */
+public void addMenuListener (MenuListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Hide,typedListener);
+ addListener (SWT.Show,typedListener);
+}
+
+static Control checkNull (Control control) {
+ if (control == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return control;
+}
+
+static Menu checkNull (Menu menu) {
+ if (menu == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return menu;
+}
+
+static MenuItem checkNull (MenuItem item) {
+ if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return item;
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.POP_UP, SWT.BAR, SWT.DROP_DOWN, 0, 0, 0);
+}
+
+void createHandle () {
+ if (handle != 0) return;
+ if ((style & SWT.BAR) != 0) {
+ handle = OS.CreateMenu ();
+ } else {
+ handle = OS.CreatePopupMenu ();
+ }
+ if (handle == 0) error (SWT.ERROR_NO_HANDLES);
+}
+
+void createItem (MenuItem item, int index) {
+ int count = OS.GetMenuItemCount (handle);
+ if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
+ display.addMenuItem (item);
+ /*
+ * Bug in Windows. For some reason, when InsertMenuItem()
+ * is used to insert an item without text, it is not possible
+ * to use SetMenuItemInfo() to set the text at a later time.
+ * The fix is to insert the item with some text.
+ *
+ * Feature in Windows. When an empty string is used instead
+ * of a space and InsertMenuItem() is used to set a submenu
+ * before setting text to a non-empty string, the menu item
+ * becomes unexpectedly disabled. The fix is to insert a
+ * space.
+ */
+ long hHeap = OS.GetProcessHeap ();
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, 4);
+ OS.MoveMemory (pszText, new char [] {' ', '\0'}, 4);
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA;
+ info.wID = item.id;
+ info.dwItemData = item.id;
+ info.fType = item.widgetStyle ();
+ info.dwTypeData = pszText;
+ boolean success = OS.InsertMenuItem (handle, index, true, info);
+ if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
+ if (!success) {
+ display.removeMenuItem (item);
+ error (SWT.ERROR_ITEM_NOT_ADDED);
+ }
+ redraw ();
+}
+
+void createWidget () {
+ /*
+ * Bug in IBM JVM 1.3.1. For some reason, when the following code is called
+ * from this method, the JVM issues this error:
+ *
+ * JVM Exception 0x2 (subcode 0x0) occurred in thread "main" (TID:0x9F19D8)
+ *
+ * In addition, on Windows XP, a dialog appears with following error message,
+ * indicating that the problem may be in the JIT:
+ *
+ * AppName: java.exe AppVer: 0.0.0.0 ModName: jitc.dll
+ * ModVer: 0.0.0.0 Offset: 000b6912
+ *
+ * The fix is to move the code to the caller of this method.
+ */
+// checkOrientation (parent);
+ createHandle ();
+ parent.addMenu (this);
+}
+
+int defaultBackground () {
+ return OS.GetSysColor (OS.COLOR_MENU);
+}
+
+int defaultForeground () {
+ return OS.GetSysColor (OS.COLOR_MENUTEXT);
+}
+
+void destroyAccelerators () {
+ parent.destroyAccelerators ();
+}
+
+void destroyItem (MenuItem item) {
+ if (!OS.DeleteMenu (handle, item.id, OS.MF_BYCOMMAND)) {
+ error (SWT.ERROR_ITEM_NOT_REMOVED);
+ }
+ redraw ();
+}
+
+@Override
+void destroyWidget () {
+ MenuItem cascade = this.cascade;
+ long hMenu = handle;
+ releaseHandle ();
+ if (cascade != null) {
+ cascade.setMenu (null, true);
+ } else {
+ if (hMenu != 0) OS.DestroyMenu (hMenu);
+ }
+}
+
+void fixMenus (Decorations newParent) {
+ if (isDisposed()) {
+ return;
+ }
+ MenuItem [] items = getItems ();
+ for (int i=0; i
+ *
+ *
+ * @since 3.3
+ */
+/*public*/ Image getBackgroundImage () {
+ checkWidget ();
+ return backgroundImage;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent (or its display if its parent is null),
+ * unless the receiver is a menu or a shell. In this case, the
+ * location is relative to the display.
+ *
+ *
+ *
+ * @since 3.1
+ */
+/*public*/ Rectangle getBounds () {
+ checkWidget ();
+ if ((style & SWT.BAR) != 0) {
+ if (parent.menuBar != this) {
+ return new Rectangle (0, 0, 0, 0);
+ }
+ long hwndShell = parent.handle;
+ MENUBARINFO info = new MENUBARINFO ();
+ info.cbSize = MENUBARINFO.sizeof;
+ if (OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, 0, info)) {
+ int width = info.right - info.left;
+ int height = info.bottom - info.top;
+ return new Rectangle (info.left, info.top, width, height);
+ }
+ } else {
+ int count = OS.GetMenuItemCount (handle);
+ if (count != 0) {
+ RECT rect1 = new RECT ();
+ if (OS.GetMenuItemRect (0, handle, 0, rect1)) {
+ RECT rect2 = new RECT ();
+ if (OS.GetMenuItemRect (0, handle, count - 1, rect2)) {
+ int x = rect1.left - 2, y = rect1.top - 2;
+ int width = (rect2.right - rect2.left) + 4;
+ int height = (rect2.bottom - rect1.top) + 4;
+ return new Rectangle (x, y, width, height);
+ }
+ }
+ }
+ }
+ return new Rectangle (0, 0, 0, 0);
+}
+
+/**
+ * Returns the default menu item or null if none has
+ * been previously set.
+ *
+ * @return the default menu item.
+ *
+ * @exception SWTException
+ *
+ */
+public MenuItem getDefaultItem () {
+ checkWidget ();
+ int id = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
+ if (id == -1) return null;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_ID;
+ if (OS.GetMenuItemInfo (handle, id, false, info)) {
+ return display.getMenuItem (info.wID);
+ }
+ return null;
+}
+
+/**
+ * Returns true
if the receiver is enabled, and
+ * false
otherwise. A disabled menu is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #isEnabled
+ */
+public boolean getEnabled () {
+ checkWidget ();
+ return (state & DISABLED) == 0;
+}
+
+/**
+ * Returns the foreground color that the receiver will use to draw.
+ *
+ * @return the receiver's foreground color
+ *
+ * @exception SWTException
+ *
+ */
+/*public*/ Color getForeground () {
+ checkWidget ();
+ return Color.win32_new (display, foreground != -1 ? foreground : defaultForeground ());
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public MenuItem getItem (int index) {
+ checkWidget ();
+ int id = 0;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_DATA;
+ if (!OS.GetMenuItemInfo (handle, index, true, info)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ id = (int)info.dwItemData;
+ return display.getMenuItem (id);
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemCount () {
+ checkWidget ();
+ return OS.GetMenuItemCount (handle);
+}
+
+/**
+ * Returns a (possibly empty) array of MenuItem
s which
+ * are the items in the receiver.
+ *
+ *
+ */
+public MenuItem [] getItems () {
+ checkWidget ();
+ int index = 0, count = 0;
+ int length = OS.GetMenuItemCount (handle);
+ if (length < 0) {
+ int error = OS.GetLastError();
+ SWT.error(SWT.ERROR_CANNOT_GET_COUNT, null, " [GetLastError=0x" + Integer.toHexString(error) + "]");//$NON-NLS-1$ $NON-NLS-2$
+ }
+ MenuItem [] items = new MenuItem [length];
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_DATA;
+ while (OS.GetMenuItemInfo (handle, index, true, info)) {
+ if (count == items.length) {
+ MenuItem [] newItems = new MenuItem [count + 4];
+ System.arraycopy (items, 0, newItems, 0, count);
+ items = newItems;
+ }
+ MenuItem item = display.getMenuItem ((int)info.dwItemData);
+ if (item != null) items [count++] = item;
+ index++;
+ }
+ if (count == items.length) return items;
+ MenuItem [] result = new MenuItem [count];
+ System.arraycopy (items, 0, result, 0, count);
+ return result;
+}
+
+@Override
+String getNameText () {
+ String result = "";
+ MenuItem [] items = getItems ();
+ int length = items.length;
+ if (length > 0) {
+ for (int i=0; i<=length-1; i++) {
+ result += (items [i] == null ? "null" : items [i].getNameText())
+ + (i < (length - 1) ? ", " : "");
+ }
+ }
+ return result;
+}
+
+/**
+ * Returns the orientation of the receiver, which will be one of the
+ * constants SWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
+ *
+ * @return the orientation style
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.7
+ */
+public int getOrientation () {
+ checkWidget ();
+ return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+}
+
+/**
+ * Returns the receiver's parent, which must be a Decorations
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException
+ *
+ */
+public Decorations getParent () {
+ checkWidget ();
+ return parent;
+}
+
+/**
+ * Returns the receiver's parent item, which must be a
+ * MenuItem
or null when the receiver is a
+ * root.
+ *
+ * @return the receiver's parent item
+ *
+ * @exception SWTException
+ *
+ */
+public MenuItem getParentItem () {
+ checkWidget ();
+ return cascade;
+}
+
+/**
+ * Returns the receiver's parent item, which must be a
+ * Menu
or null when the receiver is a
+ * root.
+ *
+ * @return the receiver's parent item
+ *
+ * @exception SWTException
+ *
+ */
+public Menu getParentMenu () {
+ checkWidget ();
+ if (cascade != null) return cascade.parent;
+ return null;
+}
+
+/**
+ * Returns the receiver's shell. For all controls other than
+ * shells, this simply returns the control's nearest ancestor
+ * shell. Shells return themselves, even if they are children
+ * of other shells. Returns null if receiver or its ancestor
+ * is the application menubar.
+ *
+ * @return the receiver's shell or null
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getParent
+ */
+public Shell getShell () {
+ checkWidget ();
+ return parent.getShell ();
+}
+
+/**
+ * Returns true
if the receiver is visible, and
+ * false
otherwise.
+ *
+ *
+ */
+public boolean getVisible () {
+ checkWidget ();
+ if ((style & SWT.BAR) != 0) {
+ return this == parent.menuShell ().menuBar;
+ }
+ if ((style & SWT.POP_UP) != 0) {
+ Menu [] popups = display.popups;
+ if (popups == null) return false;
+ for (int i=0; i
+ *
+ */
+public int indexOf (MenuItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if (item.parent != this) return -1;
+ int index = 0;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_DATA;
+ while (OS.GetMenuItemInfo (handle, index, true, info)) {
+ if (info.dwItemData == item.id) return index;
+ index++;
+ }
+ return -1;
+}
+
+/**
+ * Returns true
if the receiver is enabled and all
+ * of the receiver's ancestors are enabled, and false
+ * otherwise. A disabled menu is typically not selectable from the
+ * user interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getEnabled
+ */
+public boolean isEnabled () {
+ checkWidget ();
+ Menu parentMenu = getParentMenu ();
+ if (parentMenu == null) {
+ return getEnabled () && parent.isEnabled ();
+ }
+ return getEnabled () && parentMenu.isEnabled ();
+}
+
+/**
+ * Returns true
if the receiver is visible and all
+ * of the receiver's ancestors are visible and false
+ * otherwise.
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getVisible
+ */
+public boolean isVisible () {
+ checkWidget ();
+ return getVisible ();
+}
+
+void redraw () {
+ if (!isVisible ()) return;
+ if ((style & SWT.BAR) != 0) {
+ display.addBar (this);
+ } else {
+ update ();
+ }
+}
+
+@Override
+void releaseHandle () {
+ super.releaseHandle ();
+ handle = 0;
+ cascade = null;
+}
+
+@Override
+void releaseChildren (boolean destroy) {
+ MenuItem [] items = getItems ();
+ for (int i=0; i
+ *
+ *
+ * @see HelpListener
+ * @see #addHelpListener
+ */
+public void removeHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Help, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the menu events are generated for the control.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see MenuListener
+ * @see #addMenuListener
+ */
+public void removeMenuListener (MenuListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Hide, listener);
+ eventTable.unhook (SWT.Show, listener);
+}
+
+@Override
+void reskinChildren (int flags) {
+ MenuItem [] items = getItems ();
+ for (int i=0; i
+ *
+ *
+ * @since 3.3
+ */
+/*public*/ void setBackground (Color color) {
+ checkWidget ();
+ int pixel = -1;
+ if (color != null) {
+ if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ pixel = color.handle;
+ }
+ if (pixel == background) return;
+ background = pixel;
+ updateBackground ();
+}
+
+/**
+ * Sets the receiver's background image to the image specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null. The background image is tiled to fill
+ * the available space.
+ *
+ * @param image the new image (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.3
+ */
+/*public*/ void setBackgroundImage (Image image) {
+ checkWidget ();
+ if (image != null) {
+ if (image.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (image.type != SWT.BITMAP) error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (backgroundImage == image) return;
+ backgroundImage = image;
+ updateBackground ();
+}
+
+/**
+ * Sets the receiver's foreground color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ *
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.3
+ */
+/*public*/ void setForeground (Color color) {
+ checkWidget ();
+ int pixel = -1;
+ if (color != null) {
+ if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ pixel = color.handle;
+ }
+ if (pixel == foreground) return;
+ foreground = pixel;
+ updateForeground ();
+}
+
+/**
+ * Sets the default menu item to the argument or removes
+ * the default emphasis when the argument is null
.
+ *
+ * @param item the default menu item or null
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setDefaultItem (MenuItem item) {
+ checkWidget ();
+ int newID = -1;
+ if (item != null) {
+ if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if (item.parent != this) return;
+ newID = item.id;
+ }
+ int oldID = OS.GetMenuDefaultItem (handle, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
+ if (newID == oldID) return;
+ OS.SetMenuDefaultItem (handle, newID, OS.MF_BYCOMMAND);
+ redraw ();
+}
+
+/**
+ * Enables the receiver if the argument is true
,
+ * and disables it otherwise. A disabled menu is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException
+ *
+ */
+public void setEnabled (boolean enabled) {
+ checkWidget ();
+ state &= ~DISABLED;
+ if (!enabled) state |= DISABLED;
+}
+
+/**
+ * Sets the location of the receiver, which must be a popup,
+ * to the point specified by the arguments which are relative
+ * to the display.
+ *
+ *
+ */
+public void setLocation (int x, int y) {
+ checkWidget ();
+ setLocationInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y));
+}
+
+void setLocationInPixels (int x, int y) {
+ if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
+ this.x = x;
+ this.y = y;
+ hasLocation = true;
+}
+
+/**
+ * Sets the location of the receiver, which must be a popup,
+ * to the point specified by the argument which is relative
+ * to the display.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.1
+ */
+public void setLocation (Point location) {
+ checkWidget ();
+ if (location == null) error (SWT.ERROR_NULL_ARGUMENT);
+ location = DPIUtil.autoScaleUp(location);
+ setLocationInPixels(location.x, location.y);
+}
+
+/**
+ * Sets the orientation of the receiver, which must be one
+ * of the constants SWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
+ *
+ *
+ *
+ * @since 3.7
+ */
+public void setOrientation (int orientation) {
+ checkWidget ();
+ if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
+ _setOrientation (orientation);
+}
+
+void _setOrientation (int orientation) {
+ int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT;
+ if ((orientation & flags) == 0 || (orientation & flags) == flags) return;
+ style &= ~flags;
+ style |= orientation & flags;
+ style &= ~SWT.FLIP_TEXT_DIRECTION;
+ MenuItem [] itms = getItems ();
+ for (int i=0; i
+ *
+ */
+public void setVisible (boolean visible) {
+ checkWidget ();
+ if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
+ if (visible) {
+ display.addPopup (this);
+ } else {
+ display.removePopup (this);
+ _setVisible (false);
+ }
+}
+
+void update () {
+ if ((style & SWT.BAR) != 0) {
+ if (this == parent.menuBar) OS.DrawMenuBar (parent.handle);
+ return;
+ }
+ boolean hasCheck = false, hasImage = false;
+ MenuItem [] items = getItems ();
+ for (int i=0; iMenu
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#CHECK
+ * @see SWT#CASCADE
+ * @see SWT#PUSH
+ * @see SWT#RADIO
+ * @see SWT#SEPARATOR
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public MenuItem (Menu parent, int style) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+ parent.createItem (this, (index = parent.getItemCount ()));
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a Menu
), a style value
+ * describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#CHECK
+ * @see SWT#CASCADE
+ * @see SWT#PUSH
+ * @see SWT#RADIO
+ * @see SWT#SEPARATOR
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public MenuItem (Menu parent, int style, int index) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+ parent.createItem (this, (this.index = index));
+}
+
+MenuItem (Menu parent, Menu menu, int style, int index) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+ this.menu = menu;
+ this.index = index;
+ if (menu != null) menu.cascade = this;
+ display.addMenuItem (this);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the arm events are generated for the control, by sending
+ * it one of the messages defined in the ArmListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ArmListener
+ * @see #removeArmListener
+ */
+public void addArmListener (ArmListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Arm, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the help events are generated for the control, by sending
+ * it one of the messages defined in the HelpListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see HelpListener
+ * @see #removeHelpListener
+ */
+public void addHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Help, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the menu item is selected by the user, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called, the stateMask field of the event object is valid.
+ * widgetDefaultSelected
is not called.
+ * SWT.RADIO
style bit is set, the widgetSelected
method is
+ * also called when the receiver loses selection because another item in the same radio group
+ * was selected by the user. During widgetSelected
the application can use
+ * getSelection()
to determine the current selected state of the receiver.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.PUSH, SWT.CHECK, SWT.RADIO, SWT.SEPARATOR, SWT.CASCADE, 0);
+}
+
+@Override
+void destroyWidget () {
+ parent.destroyItem (this);
+ releaseHandle ();
+}
+
+boolean fillAccel (ACCEL accel) {
+ accel.cmd = accel.key = accel.fVirt = 0;
+ if (accelerator == 0 || !getEnabled ()) return false;
+ if ((accelerator & SWT.COMMAND) != 0) return false;
+ int fVirt = OS.FVIRTKEY;
+ int key = accelerator & SWT.KEY_MASK;
+ int vKey = Display.untranslateKey (key);
+ if (vKey != 0) {
+ key = vKey;
+ } else {
+ switch (key) {
+ /*
+ * Bug in Windows. For some reason, VkKeyScan
+ * fails to map ESC to VK_ESCAPE and DEL to
+ * VK_DELETE. The fix is to map these keys
+ * as a special case.
+ */
+ case 27: key = OS.VK_ESCAPE; break;
+ case 127: key = OS.VK_DELETE; break;
+ default: {
+ if (key == 0) return false;
+ vKey = OS.VkKeyScan ((short) key);
+ if (vKey == -1) {
+ if (key != (int)OS.CharUpper ((short) key)) {
+ fVirt = 0;
+ }
+ } else {
+ key = vKey & 0xFF;
+ }
+ }
+ }
+ }
+ accel.key = (short) key;
+ accel.cmd = (short) id;
+ accel.fVirt = (byte) fVirt;
+ if ((accelerator & SWT.ALT) != 0) accel.fVirt |= OS.FALT;
+ if ((accelerator & SWT.SHIFT) != 0) accel.fVirt |= OS.FSHIFT;
+ if ((accelerator & SWT.CONTROL) != 0) accel.fVirt |= OS.FCONTROL;
+ return true;
+}
+
+void fixMenus (Decorations newParent) {
+ if (menu != null && !menu.isDisposed() && !newParent.isDisposed()) menu.fixMenus (newParent);
+}
+
+/**
+ * Returns the widget accelerator. An accelerator is the bit-wise
+ * OR of zero or more modifier masks and a key. Examples:
+ * SWT.CONTROL | SWT.SHIFT | 'T', SWT.ALT | SWT.F2
.
+ * The default value is zero, indicating that the menu item does
+ * not have an accelerator.
+ *
+ * @return the accelerator or 0
+ *
+ * @exception SWTException
+ *
+ */
+public int getAccelerator () {
+ checkWidget ();
+ return accelerator;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent (or its display if its parent is null).
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.1
+ */
+/*public*/ Rectangle getBounds () {
+ checkWidget ();
+ int index = parent.indexOf (this);
+ if (index == -1) return new Rectangle (0, 0, 0, 0);
+ if ((parent.style & SWT.BAR) != 0) {
+ Decorations shell = parent.parent;
+ if (shell.menuBar != parent) {
+ return new Rectangle (0, 0, 0, 0);
+ }
+ long hwndShell = shell.handle;
+ MENUBARINFO info1 = new MENUBARINFO ();
+ info1.cbSize = MENUBARINFO.sizeof;
+ if (!OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, 1, info1)) {
+ return new Rectangle (0, 0, 0, 0);
+ }
+ MENUBARINFO info2 = new MENUBARINFO ();
+ info2.cbSize = MENUBARINFO.sizeof;
+ if (!OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, index + 1, info2)) {
+ return new Rectangle (0, 0, 0, 0);
+ }
+ int x = info2.left - info1.left;
+ int y = info2.top - info1.top;
+ int width = info2.right - info2.left;
+ int height = info2.bottom - info2.top;
+ return new Rectangle (x, y, width, height);
+ } else {
+ long hMenu = parent.handle;
+ RECT rect1 = new RECT ();
+ if (!OS.GetMenuItemRect (0, hMenu, 0, rect1)) {
+ return new Rectangle (0, 0, 0, 0);
+ }
+ RECT rect2 = new RECT ();
+ if (!OS.GetMenuItemRect (0, hMenu, index, rect2)) {
+ return new Rectangle (0, 0, 0, 0);
+ }
+ int x = rect2.left - rect1.left + 2;
+ int y = rect2.top - rect1.top + 2;
+ int width = rect2.right - rect2.left;
+ int height = rect2.bottom - rect2.top;
+ return new Rectangle (x, y, width, height);
+ }
+}
+
+/**
+ * Returns true
if the receiver is enabled, and
+ * false
otherwise. A disabled menu item is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #isEnabled
+ */
+public boolean getEnabled () {
+ checkWidget ();
+ /*
+ * Feature in Windows. For some reason, when the menu item
+ * is a separator, GetMenuItemInfo() always indicates that
+ * the item is not enabled. The fix is to track the enabled
+ * state for separators.
+ */
+ if ((style & SWT.SEPARATOR) != 0) {
+ return (state & DISABLED) == 0;
+ }
+ long hMenu = parent.handle;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_STATE;
+ boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
+ if (!success) error (SWT.ERROR_CANNOT_GET_ENABLED);
+ return (info.fState & (OS.MFS_DISABLED | OS.MFS_GRAYED)) == 0;
+}
+
+/**
+ * Gets the identifier associated with the receiver.
+ *
+ * @return the receiver's identifier
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.7
+ */
+public int getID () {
+ checkWidget();
+ return userId;
+}
+
+/**
+ * Returns the receiver's cascade menu if it has one or null
+ * if it does not. Only CASCADE
menu items can have
+ * a pull down menu. The sequence of key strokes, button presses
+ * and/or button releases that are used to request a pull down
+ * menu is platform specific.
+ *
+ * @return the receiver's menu
+ *
+ * @exception SWTException
+ *
+ */
+@Override
+public Menu getMenu () {
+ checkWidget ();
+ return menu;
+}
+
+@Override
+String getNameText () {
+ if ((style & SWT.SEPARATOR) != 0) return "|";
+ return super.getNameText ();
+}
+
+/**
+ * Returns the receiver's parent, which must be a Menu
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException
+ *
+ */
+public Menu getParent () {
+ checkWidget ();
+ return parent;
+}
+
+/**
+ * Returns true
if the receiver is selected,
+ * and false otherwise.
+ * CHECK
or RADIO
,
+ * it is selected when it is checked.
+ *
+ * @return the selection state
+ *
+ * @exception SWTException
+ *
+ */
+public boolean getSelection () {
+ checkWidget ();
+ if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return false;
+ long hMenu = parent.handle;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_STATE;
+ boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
+ if (!success) error (SWT.ERROR_CANNOT_GET_SELECTION);
+ return (info.fState & OS.MFS_CHECKED) !=0;
+}
+
+/**
+ * Returns the receiver's tool tip text, or null if it has not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.104
+ */
+public String getToolTipText () {
+ checkWidget();
+ return (itemToolTip == null) ? null : itemToolTip.getMessage();
+}
+
+void hideToolTip () {
+ if (itemToolTip == null) return;
+ itemToolTip.setVisible (false);
+}
+
+/**
+ * Returns true
if the receiver is enabled and all
+ * of the receiver's ancestors are enabled, and false
+ * otherwise. A disabled menu item is typically not selectable from the
+ * user interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getEnabled
+ */
+public boolean isEnabled () {
+ return getEnabled () && parent.isEnabled ();
+}
+
+@Override
+void releaseChildren (boolean destroy) {
+ if (menu != null) {
+ menu.release (false);
+ menu = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+@Override
+void releaseHandle () {
+ super.releaseHandle ();
+ parent = null;
+ id = -1;
+}
+
+@Override
+void releaseParent () {
+ super.releaseParent ();
+ if (menu != null) menu.dispose ();
+ menu = null;
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ if (hBitmap != 0) OS.DeleteObject (hBitmap);
+ hBitmap = 0;
+ if (accelerator != 0) {
+ parent.destroyAccelerators ();
+ }
+ accelerator = 0;
+ display.removeMenuItem (this);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the arm events are generated for the control.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ArmListener
+ * @see #addArmListener
+ */
+public void removeArmListener (ArmListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Arm, listener);
+}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the help events are generated for the control.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see HelpListener
+ * @see #addHelpListener
+ */
+public void removeHelpListener (HelpListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Help, listener);
+}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+
+@Override
+void reskinChildren (int flags) {
+ if (menu != null) {
+ menu.reskin (flags);
+ }
+ super.reskinChildren (flags);
+}
+
+void selectRadio () {
+ int index = 0;
+ MenuItem [] items = parent.getItems ();
+ while (index < items.length && items [index] != this) index++;
+ int i = index - 1;
+ while (i >= 0 && items [i].setRadioSelection (false)) --i;
+ int j = index + 1;
+ while (j < items.length && items [j].setRadioSelection (false)) j++;
+ setSelection (true);
+}
+
+/**
+ * Sets the widget accelerator. An accelerator is the bit-wise
+ * OR of zero or more modifier masks and a key. Examples:
+ * SWT.MOD1 | SWT.MOD2 | 'T', SWT.MOD3 | SWT.F2
.
+ * SWT.CONTROL | SWT.SHIFT | 'T', SWT.ALT | SWT.F2
.
+ * The default value is zero, indicating that the menu item does
+ * not have an accelerator.
+ *
+ * @param accelerator an integer that is the bit-wise OR of masks and a key
+ *
+ * @exception SWTException
+ *
+ */
+public void setAccelerator (int accelerator) {
+ checkWidget ();
+ if (this.accelerator == accelerator) return;
+ this.accelerator = accelerator;
+ parent.destroyAccelerators ();
+}
+
+/**
+ * Enables the receiver if the argument is true
,
+ * and disables it otherwise. A disabled menu item is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException
+ *
+ */
+public void setEnabled (boolean enabled) {
+ checkWidget ();
+ /*
+ * Feature in Windows. For some reason, when the menu item
+ * is a separator, GetMenuItemInfo() always indicates that
+ * the item is not enabled. The fix is to track the enabled
+ * state for separators.
+ */
+ if ((style & SWT.SEPARATOR) != 0) {
+ if (enabled) {
+ state &= ~DISABLED;
+ } else {
+ state |= DISABLED;
+ }
+ }
+ long hMenu = parent.handle;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_STATE;
+ boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
+ if (!success) {
+ int error = OS.GetLastError();
+ SWT.error (SWT.ERROR_CANNOT_SET_ENABLED, null, " [GetLastError=0x" + Integer.toHexString(error) + "]");//$NON-NLS-1$ $NON-NLS-2$
+ }
+ int bits = OS.MFS_DISABLED | OS.MFS_GRAYED;
+ if (enabled) {
+ if ((info.fState & bits) == 0) return;
+ info.fState &= ~bits;
+ } else {
+ if ((info.fState & bits) == bits) return;
+ info.fState |= bits;
+ }
+ success = OS.SetMenuItemInfo (hMenu, id, false, info);
+ if (!success) {
+ /*
+ * Bug in Windows. For some reason SetMenuItemInfo(),
+ * returns a fail code when setting the enabled or
+ * selected state of a default item, but sets the
+ * state anyway. The fix is to ignore the error.
+ *
+ * NOTE: This only happens on Vista.
+ */
+ success = id == OS.GetMenuDefaultItem (hMenu, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
+ if (!success) {
+ int error = OS.GetLastError();
+ SWT.error (SWT.ERROR_CANNOT_SET_ENABLED, null, " [GetLastError=0x" + Integer.toHexString(error) + "]");//$NON-NLS-1$ $NON-NLS-2$
+ }
+ }
+ parent.destroyAccelerators ();
+ parent.redraw ();
+}
+
+/**
+ * Sets the identifier associated with the receiver to the argument.
+ *
+ * @param id the new identifier. This must be a non-negative value. System-defined identifiers are negative values.
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.7
+ */
+public void setID (int id) {
+ checkWidget();
+ if (id < 0) error(SWT.ERROR_INVALID_ARGUMENT);
+ userId = id;
+}
+
+/**
+ * Sets the receiver's image to the argument, which may be
+ * null indicating that no image should be displayed.
+ *
+ *
+ */
+@Override
+public void setImage (Image image) {
+ checkWidget ();
+ if ((style & SWT.SEPARATOR) != 0) return;
+ super.setImage (image);
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_BITMAP;
+ if (parent.foreground != -1) {
+ info.hbmpItem = OS.HBMMENU_CALLBACK;
+ } else {
+ if (OS.IsAppThemed ()) {
+ if (hBitmap != 0) OS.DeleteObject (hBitmap);
+ info.hbmpItem = hBitmap = image != null ? Display.create32bitDIB (image) : 0;
+ } else {
+ info.hbmpItem = image != null ? OS.HBMMENU_CALLBACK : 0;
+ }
+ }
+ long hMenu = parent.handle;
+ OS.SetMenuItemInfo (hMenu, id, false, info);
+ parent.redraw ();
+}
+
+/**
+ * Sets the receiver's pull down menu to the argument.
+ * Only CASCADE
menu items can have a
+ * pull down menu. The sequence of key strokes, button presses
+ * and/or button releases that are used to request a pull down
+ * menu is platform specific.
+ *
+ *
+ * @exception SWTException CASCADE
+ *
+ */
+public void setMenu (Menu menu) {
+ checkWidget ();
+
+ /* Check to make sure the new menu is valid */
+ if ((style & SWT.CASCADE) == 0) {
+ error (SWT.ERROR_MENUITEM_NOT_CASCADE);
+ }
+ if (menu != null) {
+ if (menu.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+ if ((menu.style & SWT.DROP_DOWN) == 0) {
+ error (SWT.ERROR_MENU_NOT_DROP_DOWN);
+ }
+ if (menu.parent != parent.parent) {
+ error (SWT.ERROR_INVALID_PARENT);
+ }
+ }
+ setMenu (menu, false);
+}
+
+void setMenu (Menu menu, boolean dispose) {
+
+ /* Assign the new menu */
+ Menu oldMenu = this.menu;
+ if (oldMenu == menu) return;
+ if (oldMenu != null) oldMenu.cascade = null;
+ this.menu = menu;
+
+ long hMenu = parent.handle;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_DATA;
+ int index = 0;
+ while (OS.GetMenuItemInfo (hMenu, index, true, info)) {
+ if (info.dwItemData == id) break;
+ index++;
+ }
+ if (info.dwItemData != id) return;
+ int cch = 128;
+ long hHeap = OS.GetProcessHeap ();
+ int byteCount = cch * 2;
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ info.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_DATA;
+ /*
+ * Bug in Windows. When GetMenuItemInfo() is used to get the text,
+ * for an item that has a bitmap set using MIIM_BITMAP, the text is
+ * not returned. This means that when SetMenuItemInfo() is used to
+ * set the submenu and the current menu state, the text is lost.
+ * The fix is use MIIM_BITMAP and MIIM_STRING.
+ */
+ info.fMask |= OS.MIIM_BITMAP | OS.MIIM_STRING;
+ info.dwTypeData = pszText;
+ info.cch = cch;
+ boolean success = OS.GetMenuItemInfo (hMenu, index, true, info);
+ if (menu != null) {
+ menu.cascade = this;
+ info.fMask |= OS.MIIM_SUBMENU;
+ info.hSubMenu = menu.handle;
+ }
+ if (dispose || oldMenu == null) {
+ success = OS.SetMenuItemInfo (hMenu, index, true, info);
+ } else {
+ /*
+ * Feature in Windows. When SetMenuItemInfo () is used to
+ * set a submenu and the menu item already has a submenu,
+ * Windows destroys the previous menu. This is undocumented
+ * and unexpected but not necessarily wrong. The fix is to
+ * remove the item with RemoveMenu () which does not destroy
+ * the submenu and then insert the item with InsertMenuItem ().
+ */
+ OS.RemoveMenu (hMenu, index, OS.MF_BYPOSITION);
+ success = OS.InsertMenuItem (hMenu, index, true, info);
+ }
+ if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
+ if (!success) {
+ int error = OS.GetLastError();
+ SWT.error (SWT.ERROR_CANNOT_SET_MENU, null, " [GetLastError=0x" + Integer.toHexString(error) + "]");//$NON-NLS-1$ $NON-NLS-2$
+ }
+ parent.destroyAccelerators ();
+}
+
+boolean setRadioSelection (boolean value) {
+ if ((style & SWT.RADIO) == 0) return false;
+ if (getSelection () != value) {
+ setSelection (value);
+ sendSelectionEvent (SWT.Selection);
+ }
+ return true;
+}
+
+void setOrientation (int orientation) {
+ long hMenu = parent.handle;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_FTYPE;
+ info.fType = widgetStyle ();
+ OS.SetMenuItemInfo (hMenu, id, false, info);
+ if (menu != null) menu._setOrientation (orientation);
+}
+
+/**
+ * Sets the selection state of the receiver.
+ * CHECK
or RADIO
,
+ * it is selected when it is checked.
+ *
+ * @param selected the new selection state
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (boolean selected) {
+ checkWidget ();
+ if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return;
+ long hMenu = parent.handle;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ info.fMask = OS.MIIM_STATE;
+ boolean success = OS.GetMenuItemInfo (hMenu, id, false, info);
+ if (!success) error (SWT.ERROR_CANNOT_SET_SELECTION);
+ info.fState &= ~OS.MFS_CHECKED;
+ if (selected) info.fState |= OS.MFS_CHECKED;
+ success = OS.SetMenuItemInfo (hMenu, id, false, info);
+ if (!success) {
+ /*
+ * Bug in Windows. For some reason SetMenuItemInfo(),
+ * returns a fail code when setting the enabled or
+ * selected state of a default item, but sets the
+ * state anyway. The fix is to ignore the error.
+ *
+ * NOTE: This only happens on Vista.
+ */
+ success = id == OS.GetMenuDefaultItem (hMenu, OS.MF_BYCOMMAND, OS.GMDI_USEDISABLED);
+ if (!success) {
+ int error = OS.GetLastError();
+ SWT.error (SWT.ERROR_CANNOT_SET_SELECTION, null, " [GetLastError=0x" + Integer.toHexString(error) + "]");//$NON-NLS-1$ $NON-NLS-2$
+ }
+ }
+ parent.redraw ();
+}
+/**
+ * Sets the receiver's text. The string may include
+ * the mnemonic character and accelerator text.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #setAccelerator
+ */
+@Override
+public void setText (String string) {
+ checkWidget ();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if ((style & SWT.SEPARATOR) != 0) return;
+ if (text.equals (string)) return;
+ super.setText (string);
+ long hHeap = OS.GetProcessHeap ();
+ long pszText = 0;
+ MENUITEMINFO info = new MENUITEMINFO ();
+ info.cbSize = MENUITEMINFO.sizeof;
+ long hMenu = parent.handle;
+
+ /* Use the character encoding for the default locale */
+ TCHAR buffer = new TCHAR (0, string, true);
+ int byteCount = buffer.length () * TCHAR.sizeof;
+ pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory (pszText, buffer, byteCount);
+ /*
+ * Bug in Windows 2000. For some reason, when MIIM_TYPE is set
+ * on a menu item that also has MIIM_BITMAP, the MIIM_TYPE clears
+ * the MIIM_BITMAP style. The fix is to use MIIM_STRING.
+ */
+ info.fMask = OS.MIIM_STRING;
+ info.dwTypeData = pszText;
+ boolean success = OS.SetMenuItemInfo (hMenu, id, false, info);
+ if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
+ if (!success) {
+ int error = OS.GetLastError();
+ SWT.error (SWT.ERROR_CANNOT_SET_TEXT, null, " [GetLastError=0x" + Integer.toHexString(error) + "]");//$NON-NLS-1$ $NON-NLS-2$
+ }
+ parent.redraw ();
+}
+
+/**
+ * Sets the receiver's tool tip text to the argument, which
+ * may be null indicating that the default tool tip for the
+ * control will be shown. For a menu item that has a default
+ * tool tip, setting
+ * the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ *
+ *
+ *
+ * @since 3.104
+ */
+public void setToolTipText (String toolTip) {
+ checkWidget ();
+
+ if (toolTip == null && itemToolTip != null) {
+ itemToolTip.setVisible (false);
+ itemToolTip = null;
+ }
+
+ if (toolTip == null || toolTip.trim().length() == 0
+ || (itemToolTip != null && toolTip.equals(itemToolTip.getMessage()))) return;
+
+ itemToolTip = new MenuItemToolTip (this.getParent().getShell());
+ itemToolTip.setMessage (toolTip);
+ itemToolTip.setVisible (false);
+}
+
+void showTooltip (int x, int y) {
+ if (itemToolTip == null) return;
+ itemToolTip.setLocationInPixels (x, y);
+ itemToolTip.setVisible (true);
+}
+
+int widgetStyle () {
+ int bits = 0;
+ Decorations shell = parent.parent;
+ if ((shell.style & SWT.MIRRORED) != 0) {
+ if ((parent.style & SWT.LEFT_TO_RIGHT) != 0) {
+ bits |= OS.MFT_RIGHTJUSTIFY | OS.MFT_RIGHTORDER;
+ }
+ } else {
+ if ((parent.style & SWT.RIGHT_TO_LEFT) != 0) {
+ bits |= OS.MFT_RIGHTJUSTIFY | OS.MFT_RIGHTORDER;
+ }
+ }
+ if ((style & SWT.SEPARATOR) != 0) return bits | OS.MFT_SEPARATOR;
+ if ((style & SWT.RADIO) != 0) return bits | OS.MFT_RADIOCHECK;
+ return bits | OS.MFT_STRING;
+}
+
+LRESULT wmCommandChild (long wParam, long lParam) {
+ if ((style & SWT.CHECK) != 0) {
+ setSelection (!getSelection ());
+ } else {
+ if ((style & SWT.RADIO) != 0) {
+ if ((parent.getStyle () & SWT.NO_RADIO_GROUP) != 0) {
+ setSelection (!getSelection ());
+ } else {
+ selectRadio ();
+ }
+ }
+ }
+ sendSelectionEvent (SWT.Selection);
+ return null;
+}
+
+LRESULT wmDrawChild (long wParam, long lParam) {
+ DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
+ OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
+ if (image != null) {
+ GCData data = new GCData();
+ data.device = display;
+ GC gc = GC.win32_new (struct.hDC, data);
+ /*
+ * Bug in Windows. When a bitmap is included in the
+ * menu bar, the HDC seems to already include the left
+ * coordinate. The fix is to ignore this value when
+ * the item is in a menu bar.
+ */
+ int x = (parent.style & SWT.BAR) != 0 ? MARGIN_WIDTH * 2 : struct.left;
+ Image image = getEnabled () ? this.image : new Image (display, this.image, SWT.IMAGE_DISABLE);
+ gc.drawImage (image, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(struct.top + MARGIN_HEIGHT));
+ if (this.image != image) image.dispose ();
+ gc.dispose ();
+ }
+ if (parent.foreground != -1) OS.SetTextColor (struct.hDC, parent.foreground);
+ return null;
+}
+
+LRESULT wmMeasureChild (long wParam, long lParam) {
+ MEASUREITEMSTRUCT struct = new MEASUREITEMSTRUCT ();
+ OS.MoveMemory (struct, lParam, MEASUREITEMSTRUCT.sizeof);
+ int width = 0, height = 0;
+ if (image != null) {
+ Rectangle rect = image.getBoundsInPixels ();
+ width = rect.width;
+ height = rect.height;
+ } else {
+ /*
+ * Bug in Windows. If a menu contains items that have
+ * images and can be checked, Windows does not include
+ * the width of the image and the width of the check when
+ * computing the width of the menu. When the longest item
+ * does not have an image, the label and the accelerator
+ * text can overlap. The fix is to use SetMenuItemInfo()
+ * to indicate that all items have a bitmap and then include
+ * the width of the widest bitmap in WM_MEASURECHILD.
+ */
+ MENUINFO lpcmi = new MENUINFO ();
+ lpcmi.cbSize = MENUINFO.sizeof;
+ lpcmi.fMask = OS.MIM_STYLE;
+ long hMenu = parent.handle;
+ OS.GetMenuInfo (hMenu, lpcmi);
+ if ((lpcmi.dwStyle & OS.MNS_CHECKORBMP) == 0) {
+ MenuItem [] items = parent.getItems ();
+ for (int i=0; i
+ *
+ * @exception SWTException
+ *
+ */
+public MessageBox (Shell parent) {
+ this (parent, SWT.OK | SWT.ICON_INFORMATION | SWT.APPLICATION_MODAL);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * @param parent a shell which will be the parent of the new instance
+ * @param style the style of dialog to construct
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#ICON_ERROR
+ * @see SWT#ICON_INFORMATION
+ * @see SWT#ICON_QUESTION
+ * @see SWT#ICON_WARNING
+ * @see SWT#ICON_WORKING
+ * @see SWT#OK
+ * @see SWT#CANCEL
+ * @see SWT#YES
+ * @see SWT#NO
+ * @see SWT#ABORT
+ * @see SWT#RETRY
+ * @see SWT#IGNORE
+ */
+public MessageBox (Shell parent, int style) {
+ super (parent, checkStyle (parent, checkStyle (style)));
+ checkSubclass ();
+}
+
+static int checkStyle (int style) {
+ int mask = (SWT.YES | SWT.NO | SWT.OK | SWT.CANCEL | SWT.ABORT | SWT.RETRY | SWT.IGNORE);
+ int bits = style & mask;
+ if (bits == SWT.OK || bits == SWT.CANCEL || bits == (SWT.OK | SWT.CANCEL)) return style;
+ if (bits == SWT.YES || bits == SWT.NO || bits == (SWT.YES | SWT.NO) || bits == (SWT.YES | SWT.NO | SWT.CANCEL)) return style;
+ if (bits == (SWT.RETRY | SWT.CANCEL) || bits == (SWT.ABORT | SWT.RETRY | SWT.IGNORE)) return style;
+ style = (style & ~mask) | SWT.OK;
+ return style;
+}
+
+/**
+ * Returns the dialog's message, or an empty string if it does not have one.
+ * The message is a description of the purpose for which the dialog was opened.
+ * This message will be visible in the dialog while it is open.
+ *
+ * @return the message
+ */
+public String getMessage () {
+ return message;
+}
+
+/**
+ * Makes the dialog visible and brings it to the front
+ * of the display.
+ *
+ * @return the ID of the button that was selected to dismiss the
+ * message box (e.g. SWT.OK, SWT.CANCEL, etc.)
+ *
+ * @exception SWTException
+ *
+ */
+public int open () {
+
+ /* Compute the MessageBox style */
+ int buttonBits = 0;
+ if ((style & SWT.OK) == SWT.OK) buttonBits = OS.MB_OK;
+ if ((style & (SWT.OK | SWT.CANCEL)) == (SWT.OK | SWT.CANCEL)) buttonBits = OS.MB_OKCANCEL;
+ if ((style & (SWT.YES | SWT.NO)) == (SWT.YES | SWT.NO)) buttonBits = OS.MB_YESNO;
+ if ((style & (SWT.YES | SWT.NO | SWT.CANCEL)) == (SWT.YES | SWT.NO | SWT.CANCEL)) buttonBits = OS.MB_YESNOCANCEL;
+ if ((style & (SWT.RETRY | SWT.CANCEL)) == (SWT.RETRY | SWT.CANCEL)) buttonBits = OS.MB_RETRYCANCEL;
+ if ((style & (SWT.ABORT | SWT.RETRY | SWT.IGNORE)) == (SWT.ABORT | SWT.RETRY | SWT.IGNORE)) buttonBits = OS.MB_ABORTRETRYIGNORE;
+ if (buttonBits == 0) buttonBits = OS.MB_OK;
+
+ int iconBits = 0;
+ if ((style & SWT.ICON_ERROR) != 0) iconBits = OS.MB_ICONERROR;
+ if ((style & SWT.ICON_INFORMATION) != 0) iconBits = OS.MB_ICONINFORMATION;
+ if ((style & SWT.ICON_QUESTION) != 0) iconBits = OS.MB_ICONQUESTION;
+ if ((style & SWT.ICON_WARNING) != 0) iconBits = OS.MB_ICONWARNING;
+ if ((style & SWT.ICON_WORKING) != 0) iconBits = OS.MB_ICONINFORMATION;
+
+ int modalBits = 0;
+ if ((style & SWT.PRIMARY_MODAL) != 0) modalBits = OS.MB_APPLMODAL;
+ if ((style & SWT.APPLICATION_MODAL) != 0) modalBits = OS.MB_TASKMODAL;
+ if ((style & SWT.SYSTEM_MODAL) != 0) modalBits = OS.MB_SYSTEMMODAL;
+
+ int bits = buttonBits | iconBits | modalBits;
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.MB_RTLREADING | OS.MB_RIGHT;
+ if ((style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)) == 0) {
+ if (parent != null && (parent.style & SWT.MIRRORED) != 0) {
+ bits |= OS.MB_RTLREADING | OS.MB_RIGHT;
+ }
+ }
+
+ /*
+ * Feature in Windows. System modal is not supported
+ * on Windows 95 and NT. The fix is to convert system
+ * modal to task modal.
+ */
+ if ((bits & OS.MB_SYSTEMMODAL) != 0) {
+ bits |= OS.MB_TASKMODAL;
+ bits &= ~OS.MB_SYSTEMMODAL;
+ /* Force a system modal message box to the front */
+ bits |= OS.MB_TOPMOST;
+ }
+
+ /*
+ * Feature in Windows. In order for MB_TASKMODAL to work,
+ * the parent HWND of the MessageBox () call must be NULL.
+ * If the parent is not NULL, MB_TASKMODAL behaves the
+ * same as MB_APPLMODAL. The fix to set the parent HWND
+ * anyway and not rely on MB_MODAL to work by making the
+ * parent be temporarily modal.
+ */
+ long hwndOwner = parent != null ? parent.handle : 0;
+ Display display = parent != null ? parent.getDisplay (): Display.getCurrent ();
+ Dialog oldModal = null;
+ if ((bits & OS.MB_TASKMODAL) != 0) {
+ oldModal = display.getModalDialog ();
+ display.setModalDialog (this);
+ }
+
+ /* Open the message box */
+ display.sendPreExternalEventDispatchEvent ();
+ /* Use the character encoding for the default locale */
+ TCHAR buffer1 = new TCHAR (0, message, true);
+ TCHAR buffer2 = new TCHAR (0, title, true);
+ display.externalEventLoop = true;
+ int code = OS.MessageBox (hwndOwner, buffer1, buffer2, bits);
+ display.externalEventLoop = false;
+ display.sendPostExternalEventDispatchEvent ();
+
+ /* Clear the temporarily dialog modal parent */
+ if ((bits & OS.MB_TASKMODAL) != 0) {
+ display.setModalDialog (oldModal);
+ }
+
+ /*
+ * This code is intentionally commented. On some
+ * platforms, the owner window is repainted right
+ * away when a dialog window exits. This behavior
+ * is currently unspecified.
+ */
+// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner);
+
+ /* Compute and return the result */
+ if (code != 0) {
+ int type = bits & 0x0F;
+ if (type == OS.MB_OK) return SWT.OK;
+ if (type == OS.MB_OKCANCEL) {
+ return (code == OS.IDOK) ? SWT.OK : SWT.CANCEL;
+ }
+ if (type == OS.MB_YESNO) {
+ return (code == OS.IDYES) ? SWT.YES : SWT.NO;
+ }
+ if (type == OS.MB_YESNOCANCEL) {
+ if (code == OS.IDYES) return SWT.YES;
+ if (code == OS.IDNO) return SWT.NO;
+ return SWT.CANCEL;
+ }
+ if (type == OS.MB_RETRYCANCEL) {
+ return (code == OS.IDRETRY) ? SWT.RETRY : SWT.CANCEL;
+ }
+ if (type == OS.MB_ABORTRETRYIGNORE) {
+ if (code == OS.IDRETRY) return SWT.RETRY;
+ if (code == OS.IDABORT) return SWT.ABORT;
+ return SWT.IGNORE;
+ }
+ }
+ return SWT.CANCEL;
+}
+
+/**
+ * Sets the dialog's message, which is a description of
+ * the purpose for which it was opened. This message will be
+ * visible on the dialog while it is open.
+ *
+ * @param string the message
+ *
+ * @exception IllegalArgumentException
+ *
+ */
+public void setMessage (String string) {
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ message = string;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Monitor.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Monitor.java
new file mode 100644
index 000000000..7948528a7
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Monitor.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class are descriptions of monitors.
+ *
+ * @see Display
+ * @see Monitor snippets
+ * @see Sample code and further information
+ *
+ * @since 3.0
+ */
+public final class Monitor {
+ long handle;
+ int x, y, width, height;
+ int clientX, clientY, clientWidth, clientHeight;
+ int zoom;
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+Monitor () {
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the same object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return true
if the object is the same as this object and false
otherwise
+ *
+ * @see #hashCode()
+ */
+@Override
+public boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Monitor)) return false;
+ Monitor monitor = (Monitor) object;
+ return handle == monitor.handle;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its device. Note that on multi-monitor systems the
+ * origin can be negative.
+ *
+ * @return the receiver's bounding rectangle
+ */
+public Rectangle getBounds () {
+ return new Rectangle (x, y, width, height);
+}
+
+/**
+ * Returns a rectangle which describes the area of the
+ * receiver which is capable of displaying data.
+ *
+ * @return the client area
+ */
+public Rectangle getClientArea () {
+ return new Rectangle (clientX, clientY, clientWidth, clientHeight);
+}
+
+/**
+ * Returns the zoom value for the monitor
+ *
+ * @return monitor's zoom value
+ *
+ * @since 3.107
+ */
+public int getZoom () {
+ return zoom;
+}
+
+void setBounds (Rectangle rect) {
+ x = rect.x;
+ y = rect.y;
+ width = rect.width;
+ height = rect.height;
+}
+
+void setClientArea (Rectangle rect) {
+ clientX = rect.x;
+ clientY = rect.y;
+ clientWidth = rect.width;
+ clientHeight = rect.height;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return true
when passed to
+ * equals
must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ *
+ */
+@Override
+public int hashCode () {
+ return (int)/*64*/handle;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ProgressBar.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ProgressBar.java
new file mode 100644
index 000000000..c761b0a2f
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ProgressBar.java
@@ -0,0 +1,454 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of the receiver represent an unselectable
+ * user interface object that is used to display progress,
+ * typically in the form of a bar.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#SMOOTH
+ * @see SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see SWT#INDETERMINATE
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public ProgressBar (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ return OS.CallWindowProc (ProgressBarProc, hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ style |= SWT.NO_FOCUS;
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int border = getBorderWidthInPixels ();
+ int width = border * 2, height = border * 2;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10;
+ height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
+ } else {
+ width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
+ height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
+ if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
+ return new Point (width, height);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ startTimer ();
+}
+
+@Override
+int defaultForeground () {
+ return OS.GetSysColor (OS.COLOR_HIGHLIGHT);
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMaximum () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.PBM_GETRANGE, 0, 0);
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMinimum () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.PBM_GETRANGE, 1, 0);
+}
+
+/**
+ * Returns the single 'selection' that is the receiver's position.
+ *
+ * @return the selection
+ *
+ * @exception SWTException
+ *
+ */
+public int getSelection () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.PBM_GETPOS, 0, 0);
+}
+
+/**
+ * Returns the state of the receiver. The value will be one of:
+ *
+ *
+ *
+ * @return the state
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public int getState () {
+ checkWidget ();
+ int state = (int)OS.SendMessage (handle, OS.PBM_GETSTATE, 0, 0);
+ switch (state) {
+ case OS.PBST_NORMAL: return SWT.NORMAL;
+ case OS.PBST_ERROR: return SWT.ERROR;
+ case OS.PBST_PAUSED: return SWT.PAUSED;
+ }
+ return SWT.NORMAL;
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ stopTimer ();
+}
+
+void startTimer () {
+ if ((style & SWT.INDETERMINATE) != 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.PBS_MARQUEE) == 0) {
+ OS.SetTimer (handle, TIMER_ID, DELAY, 0);
+ } else {
+ OS.SendMessage (handle, OS.PBM_SETMARQUEE, 1, DELAY);
+ }
+ }
+}
+
+void stopTimer () {
+ if ((style & SWT.INDETERMINATE) != 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.PBS_MARQUEE) == 0) {
+ OS.KillTimer (handle, TIMER_ID);
+ } else {
+ OS.SendMessage (handle, OS.PBM_SETMARQUEE, 0, 0);
+ }
+ }
+}
+
+@Override
+void setBackgroundPixel (int pixel) {
+ if (pixel == -1) pixel = OS.CLR_DEFAULT;
+ OS.SendMessage (handle, OS.PBM_SETBKCOLOR, 0, pixel);
+}
+
+@Override
+void setForegroundPixel (int pixel) {
+ if (pixel == -1) pixel = OS.CLR_DEFAULT;
+ OS.SendMessage (handle, OS.PBM_SETBARCOLOR, 0, pixel);
+}
+
+/**
+ * Sets the maximum value that the receiver will allow. This new
+ * value will be ignored if it is not greater than the receiver's current
+ * minimum value. If the new maximum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new maximum, which must be greater than the current minimum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMaximum (int value) {
+ checkWidget ();
+ int minimum = (int)OS.SendMessage (handle, OS.PBM_GETRANGE, 1, 0);
+ if (0 <= minimum && minimum < value) {
+ OS.SendMessage (handle, OS.PBM_SETRANGE32, minimum, value);
+ }
+}
+
+/**
+ * Sets the minimum value that the receiver will allow. This new
+ * value will be ignored if it is negative or is not less than the receiver's
+ * current maximum value. If the new minimum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new minimum, which must be nonnegative and less than the current maximum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMinimum (int value) {
+ checkWidget ();
+ int maximum = (int)OS.SendMessage (handle, OS.PBM_GETRANGE, 0, 0);
+ if (0 <= value && value < maximum) {
+ OS.SendMessage (handle, OS.PBM_SETRANGE32, value, maximum);
+ }
+}
+
+/**
+ * Sets the single 'selection' that is the receiver's
+ * position to the argument which must be greater than or equal
+ * to zero.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (int value) {
+ checkWidget ();
+ OS.SendMessage (handle, OS.PBM_SETPOS, value, 0);
+
+ /*
+ * Bug in Vista. For some reason, when the progress bar is not in
+ * a normal state, it shows the selection of previous call to
+ * PBM_SETPOS. This is undocumented. The fix is to call PBM_SETPOS
+ * a second time.
+ */
+ long state = OS.SendMessage (handle, OS.PBM_GETSTATE, 0, 0);
+ if (state != OS.PBST_NORMAL) {
+ OS.SendMessage (handle, OS.PBM_SETPOS, value, 0);
+ }
+}
+
+/**
+ * Sets the state of the receiver. The state must be one of these values:
+ *
+ *
+ *
+ *
+ *
+ * @since 3.4
+ */
+public void setState (int state) {
+ checkWidget ();
+ switch (state) {
+ case SWT.NORMAL:
+ OS.SendMessage (handle, OS.PBM_SETSTATE, OS.PBST_NORMAL, 0);
+ break;
+ case SWT.ERROR:
+ OS.SendMessage (handle, OS.PBM_SETSTATE, OS.PBST_ERROR, 0);
+ break;
+ case SWT.PAUSED:
+ OS.SendMessage (handle, OS.PBM_SETSTATE, OS.PBST_PAUSED, 0);
+ break;
+ }
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle ();
+ if ((style & SWT.SMOOTH) != 0) bits |= OS.PBS_SMOOTH;
+ if ((style & SWT.VERTICAL) != 0) bits |= OS.PBS_VERTICAL;
+ if ((style & SWT.INDETERMINATE) != 0) bits |= OS.PBS_MARQUEE;
+ return bits;
+}
+
+@Override
+TCHAR windowClass () {
+ return ProgressBarClass;
+}
+
+@Override
+long windowProc () {
+ return ProgressBarProc;
+}
+
+@Override
+LRESULT WM_GETDLGCODE (long wParam, long lParam) {
+ LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. The progress bar does
+ * not implement WM_GETDLGCODE. As a result,
+ * a progress bar takes focus and takes part
+ * in tab traversal. This behavior, while
+ * unspecified, is unwanted. The fix is to
+ * implement WM_GETDLGCODE to behave like a
+ * STATIC control.
+ */
+ return new LRESULT (OS.DLGC_STATIC);
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. When a progress bar with the style
+ * PBS_MARQUEE becomes too small, the animation (currently
+ * a small bar moving from right to left) does not have
+ * enough space to draw. The result is that the progress
+ * bar does not appear to be moving. The fix is to detect
+ * this case, clear the PBS_MARQUEE style and emulate the
+ * animation using PBM_STEPIT.
+ *
+ * NOTE: This only happens on Window XP.
+ */
+ if ((style & SWT.INDETERMINATE) != 0) {
+ if (!OS.IsAppThemed()) {
+ forceResize ();
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ int newBits = oldBits;
+ if (rect.right - rect.left < MINIMUM_WIDTH) {
+ newBits &= ~OS.PBS_MARQUEE;
+ } else {
+ newBits |= OS.PBS_MARQUEE;
+ }
+ if (newBits != oldBits) {
+ stopTimer ();
+ OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
+ startTimer ();
+ }
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_TIMER (long wParam, long lParam) {
+ LRESULT result = super.WM_TIMER (wParam, lParam);
+ if (result != null) return result;
+ if ((style & SWT.INDETERMINATE) != 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.PBS_MARQUEE) == 0) {
+ if (wParam == TIMER_ID) {
+ OS.SendMessage (handle, OS.PBM_STEPIT, 0, 0);
+ }
+ }
+ }
+ return result;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/RunnableLock.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/RunnableLock.java
new file mode 100644
index 000000000..5654eca7f
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/RunnableLock.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+/**
+ * Instances of this class are used to ensure that an
+ * application cannot interfere with the locking mechanism
+ * used to implement asynchronous and synchronous communication
+ * between widgets and background threads.
+ */
+
+class RunnableLock {
+ Runnable runnable;
+ Thread thread;
+ Throwable throwable;
+
+RunnableLock (Runnable runnable) {
+ this.runnable = runnable;
+}
+
+boolean done () {
+ return runnable == null || throwable != null;
+}
+
+void run (Display display) {
+ if (runnable != null) {
+ try {
+ runnable.run ();
+ } catch (RuntimeException exception) {
+ display.getRuntimeExceptionHandler ().accept (exception);
+ } catch (Error error) {
+ display.getErrorHandler ().accept (error);
+ }
+ }
+ runnable = null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Sash.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Sash.java
new file mode 100644
index 000000000..59eb302b2
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Sash.java
@@ -0,0 +1,413 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of the receiver represent a selectable user interface object
+ * that allows the user to drag a rubber banded outline of the sash within
+ * the parent control.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see SWT#SMOOTH
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Sash (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the control is selected by the user, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called, the x, y, width, and height fields of the event object are valid.
+ * If the receiver is being dragged, the event object detail field contains the value SWT.DRAG
.
+ * widgetDefaultSelected
is not called.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state |= THEME_BACKGROUND;
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int border = getBorderWidthInPixels ();
+ int width = border * 2, height = border * 2;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ width += DEFAULT_WIDTH; height += 3;
+ } else {
+ width += 3; height += DEFAULT_HEIGHT;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
+ if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
+ return new Point (width, height);
+}
+
+void drawBand (int x, int y, int width, int height) {
+ if ((style & SWT.SMOOTH) != 0) return;
+ long hwndTrack = parent.handle;
+ byte [] bits = {-86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0};
+ long stippleBitmap = OS.CreateBitmap (8, 8, 1, 1, bits);
+ long stippleBrush = OS.CreatePatternBrush (stippleBitmap);
+ long hDC = OS.GetDCEx (hwndTrack, 0, OS.DCX_CACHE);
+ long oldBrush = OS.SelectObject (hDC, stippleBrush);
+ OS.PatBlt (hDC, x, y, width, height, OS.PATINVERT);
+ OS.SelectObject (hDC, oldBrush);
+ OS.ReleaseDC (hwndTrack, hDC);
+ OS.DeleteObject (stippleBrush);
+ OS.DeleteObject (stippleBitmap);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+@Override
+TCHAR windowClass () {
+ return display.windowClass;
+}
+
+@Override
+long windowProc () {
+ return display.windowProc;
+}
+
+@Override
+LRESULT WM_ERASEBKGND (long wParam, long lParam) {
+ super.WM_ERASEBKGND (wParam, lParam);
+ drawBackground (wParam);
+ return LRESULT.ONE;
+}
+
+@Override
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_KEYDOWN (wParam, lParam);
+ if (result != null) return result;
+ switch ((int)wParam) {
+ case OS.VK_LEFT:
+ case OS.VK_RIGHT:
+ case OS.VK_UP:
+ case OS.VK_DOWN:
+
+ /* Calculate the new x or y position */
+ if (OS.GetKeyState (OS.VK_LBUTTON) < 0) return result;
+ int step = OS.GetKeyState (OS.VK_CONTROL) < 0 ? INCREMENT : PAGE_INCREMENT;
+ if ((style & SWT.VERTICAL) != 0) {
+ if (wParam == OS.VK_UP || wParam == OS.VK_DOWN) break;
+ if (wParam == OS.VK_LEFT) step = -step;
+ if ((parent.style & SWT.MIRRORED) != 0) step = -step;
+ } else {
+ if (wParam == OS.VK_LEFT || wParam == OS.VK_RIGHT) break;
+ if (wParam == OS.VK_UP) step = -step;
+ }
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ long hwndTrack = parent.handle;
+ RECT clientRect = new RECT ();
+ OS.GetClientRect (hwndTrack, clientRect);
+ int clientWidth = clientRect.right - clientRect.left;
+ int clientHeight = clientRect.bottom - clientRect.top;
+ OS.MapWindowPoints (0, hwndTrack, rect, 2);
+ POINT cursorPt = new POINT ();
+ int newX = rect.left, newY = rect.top;
+ if ((style & SWT.VERTICAL) != 0) {
+ cursorPt.x = newX = Math.min (Math.max (clientRect.left, newX + step), clientWidth - width);
+ cursorPt.y = rect.top + height / 2;
+ } else {
+ cursorPt.x = rect.left + width / 2;
+ cursorPt.y = newY = Math.min (Math.max (clientRect.top, newY + step), clientHeight - height);
+ }
+ if (newX == rect.left && newY == rect.top) return result;
+
+ /* Update the pointer position */
+ OS.ClientToScreen (hwndTrack, cursorPt);
+ OS.SetCursorPos (cursorPt.x, cursorPt.y);
+
+ Event event = new Event ();
+ event.setBoundsInPixels(new Rectangle(newX, newY, width, height));
+ sendSelectionEvent (SWT.Selection, event, true);
+ if (isDisposed ()) return LRESULT.ZERO;
+ if (event.doit) {
+ if ((style & SWT.SMOOTH) != 0) {
+ setBoundsInPixels (event.getBoundsInPixels());
+ }
+ }
+ return result;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_GETDLGCODE (long wParam, long lParam) {
+ return new LRESULT (OS.DLGC_STATIC);
+}
+
+@Override
+LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
+ if (result == LRESULT.ZERO) return result;
+
+ /* Compute the banding rectangle */
+ long hwndTrack = parent.handle;
+ POINT pt = new POINT ();
+ OS.POINTSTOPOINT (pt, lParam);
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ OS.MapWindowPoints (handle, 0, pt, 1);
+ startX = pt.x - rect.left;
+ startY = pt.y - rect.top;
+ OS.MapWindowPoints (0, hwndTrack, rect, 2);
+ lastX = rect.left;
+ lastY = rect.top;
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ /* The event must be sent because doit flag is used */
+ Event event = new Event ();
+ event.setBoundsInPixels(new Rectangle(lastX, lastY, width, height));
+ if ((style & SWT.SMOOTH) == 0) {
+ event.detail = SWT.DRAG;
+ }
+ sendSelectionEvent (SWT.Selection, event, true);
+ if (isDisposed ()) return LRESULT.ZERO;
+
+ /* Draw the banding rectangle */
+ Rectangle bounds = event.getBoundsInPixels();
+ if (event.doit) {
+ dragging = true;
+ lastX = bounds.x;
+ lastY = bounds.y;
+ menuShell ().bringToTop ();
+ if (isDisposed ()) return LRESULT.ZERO;
+ int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (hwndTrack, null, 0, flags);
+ drawBand (bounds.x, bounds.y, width, height);
+ if ((style & SWT.SMOOTH) != 0) {
+ setBoundsInPixels (bounds.x, bounds.y, width, height);
+ // widget could be disposed at this point
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONUP (long wParam, long lParam) {
+ LRESULT result = super.WM_LBUTTONUP (wParam, lParam);
+ if (result == LRESULT.ZERO) return result;
+
+ /* Compute the banding rectangle */
+ if (!dragging) return result;
+ dragging = false;
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ /* The event must be sent because doit flag is used */
+ Event event = new Event ();
+ event.setBoundsInPixels(new Rectangle(lastX, lastY, width, height));
+ drawBand (lastX, lastY, width, height);
+ sendSelectionEvent (SWT.Selection, event, true);
+ if (isDisposed ()) return result;
+ Rectangle bounds = event.getBoundsInPixels();
+ if (event.doit) {
+ if ((style & SWT.SMOOTH) != 0) {
+ setBoundsInPixels (bounds.x, bounds.y, width, height);
+ // widget could be disposed at this point
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_MOUSEMOVE (long wParam, long lParam) {
+ LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
+ if (result != null) return result;
+ if (!dragging || (wParam & OS.MK_LBUTTON) == 0) return result;
+
+ /* Compute the banding rectangle */
+ POINT pt = new POINT ();
+ OS.POINTSTOPOINT (pt, lParam);
+ long hwndTrack = parent.handle;
+ OS.MapWindowPoints (handle, hwndTrack, pt, 1);
+ RECT rect = new RECT (), clientRect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ OS.GetClientRect (hwndTrack, clientRect);
+ int newX = lastX, newY = lastY;
+ if ((style & SWT.VERTICAL) != 0) {
+ int clientWidth = clientRect.right - clientRect.left;
+ newX = Math.min (Math.max (0, pt.x - startX), clientWidth - width);
+ } else {
+ int clientHeight = clientRect.bottom - clientRect.top;
+ newY = Math.min (Math.max (0, pt.y - startY), clientHeight - height);
+ }
+ if (newX == lastX && newY == lastY) return result;
+ drawBand (lastX, lastY, width, height);
+
+ /* The event must be sent because doit flag is used */
+ Event event = new Event ();
+ event.setBoundsInPixels(new Rectangle(newX, newY, width, height));
+ if ((style & SWT.SMOOTH) == 0) {
+ event.detail = SWT.DRAG;
+ }
+ sendSelectionEvent (SWT.Selection, event, true);
+ if (isDisposed ()) return LRESULT.ZERO;
+ if (event.doit) {
+ Rectangle boundsInPixels = event.getBoundsInPixels();
+ lastX = boundsInPixels.x;
+ lastY = boundsInPixels.y;
+ }
+ int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (hwndTrack, null, 0, flags);
+ drawBand (lastX, lastY, width, height);
+ if ((style & SWT.SMOOTH) != 0) {
+ setBoundsInPixels (lastX, lastY, width, height);
+ // widget could be disposed at this point
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_SETCURSOR (long wParam, long lParam) {
+ LRESULT result = super.WM_SETCURSOR (wParam, lParam);
+ if (result != null) return result;
+ int hitTest = (short) OS.LOWORD (lParam);
+ if (hitTest == OS.HTCLIENT) {
+ long hCursor = 0;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ hCursor = OS.LoadCursor (0, OS.IDC_SIZENS);
+ } else {
+ hCursor = OS.LoadCursor (0, OS.IDC_SIZEWE);
+ }
+ OS.SetCursor (hCursor);
+ return LRESULT.ONE;
+ }
+ return result;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Scale.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Scale.java
new file mode 100644
index 000000000..65d41a87a
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Scale.java
@@ -0,0 +1,596 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of the receiver represent a selectable user
+ * interface object that present a range of continuous
+ * numeric values.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Scale (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's value, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called when the user changes the receiver's value.
+ * widgetDefaultSelected
is not called.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ */
+public void addSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ return OS.CallWindowProc (TrackBarProc, hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int border = getBorderWidthInPixels ();
+ int width = border * 2, height = border * 2;
+ RECT rect = new RECT ();
+ OS.SendMessage (handle, OS.TBM_GETTHUMBRECT, 0, rect);
+ if ((style & SWT.HORIZONTAL) != 0) {
+ width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10;
+ int scrollY = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
+ height += (rect.top * 2) + scrollY + (scrollY / 3);
+ } else {
+ int scrollX = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
+ width += (rect.left * 2) + scrollX + (scrollX / 3);
+ height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
+ if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
+ return new Point (width, height);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state |= THEME_BACKGROUND | DRAW_BACKGROUND;
+ OS.SendMessage (handle, OS.TBM_SETRANGEMAX, 0, 100);
+ OS.SendMessage (handle, OS.TBM_SETPAGESIZE, 0, 10);
+ OS.SendMessage (handle, OS.TBM_SETTICFREQ, 10, 0);
+ createdAsRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
+}
+
+@Override
+int defaultForeground () {
+ return OS.GetSysColor (OS.COLOR_BTNFACE);
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed.
+ *
+ * @return the increment
+ *
+ * @exception SWTException
+ *
+ */
+public int getIncrement () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.TBM_GETLINESIZE, 0, 0);
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMaximum () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMinimum () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected.
+ *
+ * @return the page increment
+ *
+ * @exception SWTException
+ *
+ */
+public int getPageIncrement () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.TBM_GETPAGESIZE, 0, 0);
+}
+
+/**
+ * Returns the 'selection', which is the receiver's position.
+ *
+ * @return the selection
+ *
+ * @exception SWTException
+ *
+ */
+public int getSelection () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.TBM_GETPOS, 0, 0);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's value.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+@Override
+void setBackgroundImage (long hImage) {
+ super.setBackgroundImage (hImage);
+ /*
+ * Bug in Windows. Changing the background color of the Scale
+ * widget and calling InvalidateRect() still draws with the old
+ * color. The fix is to send a fake WM_SIZE event to cause
+ * it to redraw with the new background color.
+ */
+ ignoreResize = true;
+ OS.SendMessage (handle, OS.WM_SIZE, 0, 0);
+ ignoreResize = false;
+}
+
+@Override
+void setBackgroundPixel (int pixel) {
+ super.setBackgroundPixel (pixel);
+ /*
+ * Bug in Windows. Changing the background color of the Scale
+ * widget and calling InvalidateRect() still draws with the old
+ * color. The fix is to send a fake WM_SIZE event to cause
+ * it to redraw with the new background color.
+ */
+ ignoreResize = true;
+ OS.SendMessage (handle, OS.WM_SIZE, 0, 0);
+ ignoreResize = false;
+}
+
+@Override
+void setBoundsInPixels (int x, int y, int width, int height, int flags, boolean defer) {
+ /*
+ * Bug in Windows. If SetWindowPos() is called on a
+ * track bar with either SWP_DRAWFRAME, a new size,
+ * or both during mouse down, the track bar posts a
+ * WM_MOUSEMOVE message when the mouse has not moved.
+ * The window proc for the track bar uses WM_MOUSEMOVE
+ * to issue WM_HSCROLL or WM_SCROLL events to notify
+ * the application that the slider has changed. The
+ * end result is that when the user requests a page
+ * scroll and the application resizes the track bar
+ * during the change notification, continuous stream
+ * of WM_MOUSEMOVE messages are generated and the
+ * thumb moves to the mouse position rather than
+ * scrolling by a page. The fix is to clear the
+ * SWP_DRAWFRAME flag.
+ *
+ * NOTE: There is no fix for the WM_MOUSEMOVE that
+ * is generated by a new size. Clearing SWP_DRAWFRAME
+ * does not fix the problem. However, it is unlikely
+ * that the programmer will resize the control during
+ * mouse down.
+ */
+ flags &= ~OS.SWP_DRAWFRAME;
+ super.setBoundsInPixels (x, y, width, height, flags, true);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed to the argument, which must be at least
+ * one.
+ *
+ * @param increment the new increment (must be greater than zero)
+ *
+ * @exception SWTException
+ *
+ */
+public void setIncrement (int increment) {
+ checkWidget ();
+ if (increment < 1) return;
+ int minimum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
+ int maximum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
+ if (increment > maximum - minimum) return;
+ OS.SendMessage (handle, OS.TBM_SETLINESIZE, 0, increment);
+}
+
+/**
+ * Sets the maximum value that the receiver will allow. This new
+ * value will be ignored if it is not greater than the receiver's current
+ * minimum value. If the new maximum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new maximum, which must be greater than the current minimum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMaximum (int value) {
+ checkWidget ();
+ int minimum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
+ if (0 <= minimum && minimum < value) {
+ OS.SendMessage (handle, OS.TBM_SETRANGEMAX, 1, value);
+ }
+}
+
+/**
+ * Sets the minimum value that the receiver will allow. This new
+ * value will be ignored if it is negative or is not less than the receiver's
+ * current maximum value. If the new minimum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new minimum, which must be nonnegative and less than the current maximum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMinimum (int value) {
+ checkWidget ();
+ int maximum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
+ if (0 <= value && value < maximum) {
+ OS.SendMessage (handle, OS.TBM_SETRANGEMIN, 1, value);
+ }
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected to the argument, which must be at least
+ * one.
+ *
+ * @param pageIncrement the page increment (must be greater than zero)
+ *
+ * @exception SWTException
+ *
+ */
+public void setPageIncrement (int pageIncrement) {
+ checkWidget ();
+ if (pageIncrement < 1) return;
+ int minimum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMIN, 0, 0);
+ int maximum = (int)OS.SendMessage (handle, OS.TBM_GETRANGEMAX, 0, 0);
+ if (pageIncrement > maximum - minimum) return;
+ OS.SendMessage (handle, OS.TBM_SETPAGESIZE, 0, pageIncrement);
+ OS.SendMessage (handle, OS.TBM_SETTICFREQ, pageIncrement, 0);
+}
+
+/**
+ * Sets the 'selection', which is the receiver's value,
+ * to the argument which must be greater than or equal to zero.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (int value) {
+ checkWidget ();
+ OS.SendMessage (handle, OS.TBM_SETPOS, 1, value);
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle () | OS.WS_TABSTOP | OS.TBS_BOTH | OS.TBS_AUTOTICKS;
+ if ((style & SWT.HORIZONTAL) != 0) return bits | OS.TBS_HORZ | OS.TBS_DOWNISLEFT;
+ return bits | OS.TBS_VERT;
+}
+
+@Override
+TCHAR windowClass () {
+ return TrackBarClass;
+}
+
+@Override
+long windowProc () {
+ return TrackBarProc;
+}
+
+@Override
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_KEYDOWN (wParam, lParam);
+ if (result != null) return result;
+ switch ((int)wParam) {
+ case OS.VK_LEFT:
+ case OS.VK_RIGHT:
+ /*
+ * Bug in Windows. The behavior for the left and right keys is not
+ * changed if the orientation changes after the control was created.
+ * The fix is to replace VK_LEFT by VK_RIGHT and VK_RIGHT by VK_LEFT
+ * when the current orientation differs from the orientation used to
+ * create the control.
+ */
+ boolean isRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
+ if (isRTL != createdAsRTL) {
+ long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam == OS.VK_RIGHT ? OS.VK_LEFT : OS.VK_RIGHT, lParam);
+ return new LRESULT (code);
+ }
+ break;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_MOUSEWHEEL (long wParam, long lParam) {
+ LRESULT result = super.WM_MOUSEWHEEL (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Bug in Windows. When a track bar slider is changed
+ * from WM_MOUSEWHEEL, it does not always send either
+ * a WM_VSCROLL or M_HSCROLL to notify the application
+ * of the change. The fix is to detect that the selection
+ * has changed and that notification has not been issued
+ * and send the selection event.
+ */
+ int oldPosition = (int)OS.SendMessage (handle, OS.TBM_GETPOS, 0, 0);
+ ignoreSelection = true;
+ long code = callWindowProc (handle, OS.WM_MOUSEWHEEL, wParam, lParam);
+ ignoreSelection = false;
+ int newPosition = (int)OS.SendMessage (handle, OS.TBM_GETPOS, 0, 0);
+ if (oldPosition != newPosition) {
+ /*
+ * Send the event because WM_HSCROLL and WM_VSCROLL
+ * are sent from a modal message loop in windows that
+ * is active when the user is scrolling.
+ */
+ sendSelectionEvent (SWT.Selection, null, true);
+ // widget could be disposed at this point
+ }
+ return new LRESULT (code);
+}
+
+@Override
+LRESULT WM_PAINT (long wParam, long lParam) {
+ if ((state & DISPOSE_SENT) != 0) return LRESULT.ZERO;
+
+ /*
+ * Bug in Windows. For some reason, when WM_CTLCOLORSTATIC
+ * is used to implement transparency and returns a NULL brush,
+ * Windows doesn't always draw the track bar. It seems that
+ * it is drawn correctly the first time. It is possible that
+ * Windows double buffers the control and the double buffer
+ * strategy fails when WM_CTLCOLORSTATIC returns unexpected
+ * results. The fix is to send a fake WM_SIZE to force it
+ * to redraw every time there is a WM_PAINT.
+ */
+ boolean fixPaint = findBackgroundControl () != null;
+ if (!fixPaint) {
+ if (OS.IsAppThemed ()) {
+ Control control = findThemeControl ();
+ fixPaint = control != null;
+ }
+ }
+ if (fixPaint) {
+ boolean redraw = getDrawing () && OS.IsWindowVisible (handle);
+ if (redraw) OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
+ ignoreResize = true;
+ OS.SendMessage (handle, OS.WM_SIZE, 0, 0);
+ ignoreResize = false;
+ if (redraw) {
+ OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
+ OS.InvalidateRect (handle, null, false);
+ }
+ }
+ return super.WM_PAINT (wParam, lParam);
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ if (ignoreResize) return null;
+ return super.WM_SIZE (wParam, lParam);
+}
+
+@Override
+LRESULT wmScrollChild (long wParam, long lParam) {
+
+ /* Do nothing when scrolling is ending */
+ int code = OS.LOWORD (wParam);
+ switch (code) {
+ case OS.TB_ENDTRACK:
+ case OS.TB_THUMBPOSITION:
+ return null;
+ }
+
+ if (!ignoreSelection) {
+ Event event = new Event ();
+ /*
+ * This code is intentionally commented. The event
+ * detail field is not currently supported on all
+ * platforms.
+ */
+// switch (code) {
+// case OS.TB_TOP: event.detail = SWT.HOME; break;
+// case OS.TB_BOTTOM: event.detail = SWT.END; break;
+// case OS.TB_LINEDOWN: event.detail = SWT.ARROW_DOWN; break;
+// case OS.TB_LINEUP: event.detail = SWT.ARROW_UP; break;
+// case OS.TB_PAGEDOWN: event.detail = SWT.PAGE_DOWN; break;
+// case OS.TB_PAGEUP: event.detail = SWT.PAGE_UP; break;
+// }
+ /*
+ * Send the event because WM_HSCROLL and WM_VSCROLL
+ * are sent from a modal message loop in windows that
+ * is active when the user is scrolling.
+ */
+ sendSelectionEvent (SWT.Selection, event, true);
+ // widget could be disposed at this point
+ }
+ return null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ScrollBar.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ScrollBar.java
new file mode 100644
index 000000000..769bcf010
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ScrollBar.java
@@ -0,0 +1,1008 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2013 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class are selectable user interface
+ * objects that represent a range of positive, numeric values.
+ *
+ *
+ * HORIZONTAL
+ * (which have a left facing button for decrementing the value and a
+ * right facing button for incrementing it) or VERTICAL
+ * (which have an upward facing button for decrementing the value
+ * and a downward facing buttons for incrementing it).
+ * H_SCROLL
,
+ * V_SCROLL
or both when creating a Scrollable
.
+ * They are accessed from the Scrollable
using
+ * getHorizontalBar
and getVerticalBar
.
+ * Slider
.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+ScrollBar (Scrollable parent, int style) {
+ super (parent, checkStyle (style));
+ this.parent = parent;
+ createWidget ();
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's value, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called, the event object detail field contains one of the following values:
+ * SWT.NONE
- for the end of a drag.
+ * SWT.DRAG
.
+ * SWT.HOME
.
+ * SWT.END
.
+ * SWT.ARROW_DOWN
.
+ * SWT.ARROW_UP
.
+ * SWT.PAGE_DOWN
.
+ * SWT.PAGE_UP
.
+ * widgetDefaultSelected
is not called.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener (SelectionListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+void createWidget () {
+ increment = 1;
+ pageIncrement = 10;
+ /*
+ * Do not set the initial values of the maximum
+ * or the thumb. These values normally default
+ * to 100 and 10 but may have been set already
+ * by the widget that owns the scroll bar. For
+ * example, a scroll bar that is created for a
+ * list widget, setting these defaults would
+ * override the initial values provided by the
+ * list widget.
+ */
+}
+
+@Override
+void destroyWidget () {
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ OS.ShowScrollBar (hwnd, type, false);
+ parent.destroyScrollBar (style);
+ releaseHandle ();
+ //This code is intentionally commented
+ //parent.sendEvent (SWT.Resize);
+}
+
+Rectangle getBounds () {
+// checkWidget ();
+ parent.forceResize ();
+ RECT rect = new RECT ();
+ OS.GetClientRect (parent.scrolledHandle (), rect);
+ int x = 0, y = 0, width, height;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ y = rect.bottom - rect.top;
+ width = rect.right - rect.left;
+ height = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
+ } else {
+ x = rect.right - rect.left;
+ width = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
+ height = rect.bottom - rect.top;
+ }
+ return new Rectangle (x, y, width, height);
+}
+
+/**
+ * Returns true
if the receiver is enabled, and
+ * false
otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #isEnabled
+ */
+public boolean getEnabled () {
+ checkWidget();
+ return (state & DISABLED) == 0;
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed.
+ *
+ * @return the increment
+ *
+ * @exception SWTException
+ *
+ */
+public int getIncrement () {
+ checkWidget();
+ return increment;
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMaximum () {
+ checkWidget();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_RANGE;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ OS.GetScrollInfo (hwnd, type, info);
+ return info.nMax;
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMinimum () {
+ checkWidget();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_RANGE;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ OS.GetScrollInfo (hwnd, type, info);
+ return info.nMin;
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected.
+ *
+ * @return the page increment
+ *
+ * @exception SWTException
+ *
+ */
+public int getPageIncrement () {
+ checkWidget();
+ return pageIncrement;
+}
+
+/**
+ * Returns the receiver's parent, which must be a Scrollable.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException
+ *
+ */
+public Scrollable getParent () {
+ checkWidget();
+ return parent;
+}
+
+/**
+ * Returns the single 'selection' that is the receiver's value.
+ *
+ * @return the selection
+ *
+ * @exception SWTException
+ *
+ */
+public int getSelection () {
+ checkWidget();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_POS;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ OS.GetScrollInfo (hwnd, type, info);
+ return info.nPos;
+}
+
+/**
+ * Returns a point describing the receiver's size. The
+ * x coordinate of the result is the width of the receiver.
+ * The y coordinate of the result is the height of the
+ * receiver.
+ *
+ * @return the receiver's size
+ *
+ * @exception SWTException
+ *
+ */
+public Point getSize () {
+ checkWidget();
+ return DPIUtil.autoScaleDown(getSizeInPixels());
+}
+
+Point getSizeInPixels () {
+ parent.forceResize ();
+ RECT rect = new RECT ();
+ OS.GetClientRect (parent.scrolledHandle (), rect);
+ int width, height;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ width = rect.right - rect.left;
+ height = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
+ } else {
+ width = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
+ height = rect.bottom - rect.top;
+ }
+ return new Point (width, height);
+}
+
+/**
+ * Returns the receiver's thumb value.
+ *
+ * @return the thumb value
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ScrollBar
+ */
+public int getThumb () {
+ checkWidget();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_PAGE;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ OS.GetScrollInfo (hwnd, type, info);
+ if (info.nPage != 0) --info.nPage;
+ return info.nPage;
+}
+
+/**
+ * Returns a rectangle describing the size and location of the
+ * receiver's thumb relative to its parent.
+ *
+ * @return the thumb bounds, relative to the {@link #getParent() parent}
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.6
+ */
+public Rectangle getThumbBounds () {
+ checkWidget();
+ return DPIUtil.autoScaleDown(getThumbBoundsInPixels());
+}
+
+Rectangle getThumbBoundsInPixels () {
+ parent.forceResize ();
+ SCROLLBARINFO info = new SCROLLBARINFO();
+ info.cbSize = SCROLLBARINFO.sizeof;
+ int x, y, width, height;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ OS.GetScrollBarInfo(parent.handle, OS.OBJID_HSCROLL, info);
+ x = info.rcScrollBar.left + info.xyThumbTop;
+ y = info.rcScrollBar.top;
+ width = info.xyThumbBottom - info.xyThumbTop;
+ height = info.rcScrollBar.bottom - info.rcScrollBar.top;
+ } else {
+ OS.GetScrollBarInfo(parent.handle, OS.OBJID_VSCROLL, info);
+ x = info.rcScrollBar.left;
+ y = info.rcScrollBar.top + info.xyThumbTop;
+ width = info.rcScrollBar.right - info.rcScrollBar.left;
+ height = info.xyThumbBottom - info.xyThumbTop;
+ }
+ RECT rect = new RECT ();
+ rect.left = x;
+ rect.top = y;
+ rect.right = x + width;
+ rect.bottom = y + height;
+ OS.MapWindowPoints (0, parent.handle, rect, 2);
+ return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+}
+
+/**
+ * Returns a rectangle describing the size and location of the
+ * receiver's thumb track relative to its parent. This rectangle
+ * comprises the areas 2, 3, and 4 as described in {@link ScrollBar}.
+ *
+ * @return the thumb track bounds, relative to the {@link #getParent() parent}
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.6
+ */
+public Rectangle getThumbTrackBounds () {
+ checkWidget();
+ return DPIUtil.autoScaleDown(getThumbTrackBoundsInPixels());
+}
+
+Rectangle getThumbTrackBoundsInPixels () {
+ parent.forceResize ();
+ SCROLLBARINFO info = new SCROLLBARINFO();
+ info.cbSize = SCROLLBARINFO.sizeof;
+ int x = 0, y = 0, width, height;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ OS.GetScrollBarInfo(parent.handle, OS.OBJID_HSCROLL, info);
+ int size = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
+ y = info.rcScrollBar.top;
+ width = info.rcScrollBar.right - info.rcScrollBar.left;
+ height = size;
+ if (width <= 2 * size) {
+ x = info.rcScrollBar.left + width / 2;
+ width = 0;
+ } else {
+ x = info.rcScrollBar.left + size;
+ width -= 2 * size;
+ }
+ } else {
+ OS.GetScrollBarInfo(parent.handle, OS.OBJID_VSCROLL, info);
+ int size = OS.GetSystemMetrics (OS.SM_CYVSCROLL);
+ x = info.rcScrollBar.left;
+ width = size;
+ height = info.rcScrollBar.bottom - info.rcScrollBar.top;
+ if (height <= 2 * size) {
+ y = info.rcScrollBar.top + height / 2;
+ height = 0;
+ } else {
+ y = info.rcScrollBar.top + size;
+ height -= 2 * size;
+ }
+ }
+ RECT rect = new RECT ();
+ rect.left = x;
+ rect.top = y;
+ rect.right = x + width;
+ rect.bottom = y + height;
+ OS.MapWindowPoints (0, parent.handle, rect, 2);
+ return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+}
+
+/**
+ * Returns true
if the receiver is visible, and
+ * false
otherwise.
+ *
+ *
+ */
+public boolean getVisible () {
+ checkWidget();
+ SCROLLBARINFO psbi = new SCROLLBARINFO ();
+ psbi.cbSize = SCROLLBARINFO.sizeof;
+ int idObject = (style & SWT.VERTICAL) != 0 ? OS.OBJID_VSCROLL : OS.OBJID_HSCROLL;
+ OS.GetScrollBarInfo (hwndScrollBar (), idObject, psbi);
+ return (psbi.rgstate [0] & OS.STATE_SYSTEM_INVISIBLE) == 0;
+}
+
+long hwndScrollBar () {
+ return parent.scrolledHandle ();
+}
+
+/**
+ * Returns true
if the receiver is enabled and all
+ * of the receiver's ancestors are enabled, and false
+ * otherwise. A disabled control is typically not selectable from the
+ * user interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getEnabled
+ */
+public boolean isEnabled () {
+ checkWidget();
+ return getEnabled () && parent.isEnabled ();
+}
+
+/**
+ * Returns true
if the receiver is visible and all
+ * of the receiver's ancestors are visible and false
+ * otherwise.
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #getVisible
+ */
+public boolean isVisible () {
+ checkWidget();
+ return getVisible () && parent.isVisible ();
+}
+
+@Override
+void releaseHandle () {
+ super.releaseHandle ();
+ parent = null;
+}
+
+@Override
+void releaseParent () {
+ super.releaseParent ();
+ if (parent.horizontalBar == this) parent.horizontalBar = null;
+ if (parent.verticalBar == this) parent.verticalBar = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's value.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+int scrollBarType () {
+ return (style & SWT.VERTICAL) != 0 ? OS.SB_VERT : OS.SB_HORZ;
+}
+
+/**
+ * Enables the receiver if the argument is true
,
+ * and disables it otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException
+ *
+ */
+public void setEnabled (boolean enabled) {
+ checkWidget();
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ int flags = enabled ? OS.ESB_ENABLE_BOTH : OS.ESB_DISABLE_BOTH;
+ OS.EnableScrollBar (hwnd, type, flags);
+ if (enabled) {
+ state &= ~DISABLED;
+ } else {
+ state |= DISABLED;
+ }
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed to the argument, which must be at least
+ * one.
+ *
+ * @param value the new increment (must be greater than zero)
+ *
+ * @exception SWTException
+ *
+ */
+public void setIncrement (int value) {
+ checkWidget();
+ if (value < 1) return;
+ increment = value;
+}
+
+/**
+ * Sets the maximum. If this value is negative or less than or
+ * equal to the minimum, the value is ignored. If necessary, first
+ * the thumb and then the selection are adjusted to fit within the
+ * new range.
+ *
+ * @param value the new maximum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMaximum (int value) {
+ checkWidget();
+ if (value < 0) return;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
+ OS.GetScrollInfo (hwnd, type, info);
+ if (value - info.nMin - info.nPage < 1) return;
+ info.nMax = value;
+ SetScrollInfo (hwnd, type, info, true);
+}
+
+/**
+ * Sets the minimum value. If this value is negative or greater
+ * than or equal to the maximum, the value is ignored. If necessary,
+ * first the thumb and then the selection are adjusted to fit within
+ * the new range.
+ *
+ * @param value the new minimum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMinimum (int value) {
+ checkWidget();
+ if (value < 0) return;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
+ OS.GetScrollInfo (hwnd, type, info);
+ if (info.nMax - value - info.nPage < 1) return;
+ info.nMin = value;
+ SetScrollInfo (hwnd, type, info, true);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected to the argument, which must be at least
+ * one.
+ *
+ * @param value the page increment (must be greater than zero)
+ *
+ * @exception SWTException
+ *
+ */
+public void setPageIncrement (int value) {
+ checkWidget();
+ if (value < 1) return;
+ pageIncrement = value;
+}
+
+boolean SetScrollInfo (long hwnd, int flags, SCROLLINFO info, boolean fRedraw) {
+ /*
+ * Bug in Windows. For some reason, when SetScrollInfo()
+ * is used with SIF_POS and the scroll bar is hidden,
+ * the opposite scroll bar is incorrectly made visible
+ * so that the next time the parent is resized (or another
+ * scroll bar operation is performed), the opposite scroll
+ * bar draws. The fix is to hide both scroll bars.
+ */
+ boolean barVisible = false;
+ boolean visible = getVisible ();
+
+ ScrollBar bar = null;
+ switch (flags) {
+ case OS.SB_HORZ:
+ bar = parent.getVerticalBar ();
+ break;
+ case OS.SB_VERT:
+ bar = parent.getHorizontalBar ();
+ break;
+ }
+ barVisible = bar != null && bar.getVisible ();
+ if (!visible || (state & DISABLED) != 0) fRedraw = false;
+ boolean result = OS.SetScrollInfo (hwnd, flags, info, fRedraw);
+
+ /*
+ * Bug in Windows. For some reason, when the widget
+ * is a standard scroll bar, and SetScrollInfo() is
+ * called with SIF_RANGE or SIF_PAGE, the widget is
+ * incorrectly made visible so that the next time the
+ * parent is resized (or another scroll bar operation
+ * is performed), the scroll bar draws. The fix is
+ * to hide the scroll bar (again) when already hidden.
+ */
+ if (!visible) {
+ OS.ShowScrollBar (hwnd, !barVisible ? OS.SB_BOTH : flags, false);
+ }
+
+ /*
+ * Bug in Windows. When only one scroll bar is visible,
+ * and the thumb changes using SIF_RANGE or SIF_PAGE
+ * from being visible to hidden, the opposite scroll
+ * bar is incorrectly made visible. The next time the
+ * parent is resized (or another scroll bar operation
+ * is performed), the opposite scroll bar draws. The
+ * fix is to hide the opposite scroll bar again.
+ *
+ * NOTE: This problem only happens on Vista
+ */
+ if (visible && bar != null && !barVisible) {
+ OS.ShowScrollBar (hwnd, flags == OS.SB_HORZ ? OS.SB_VERT : OS.SB_HORZ, false);
+ }
+
+ /*
+ * Feature in Windows. Using SIF_DISABLENOSCROLL,
+ * SetScrollInfo () can change enabled and disabled
+ * state of the scroll bar causing a scroll bar that
+ * was disabled by the application to become enabled.
+ * The fix is to disable the scroll bar (again) when
+ * the application has disabled the scroll bar.
+ */
+ if ((state & DISABLED) != 0) {
+ OS.EnableScrollBar (hwnd, flags, OS.ESB_DISABLE_BOTH);
+ }
+ return result;
+}
+
+/**
+ * Sets the single selection that is the receiver's
+ * value to the argument which must be greater than or equal
+ * to zero.
+ *
+ * @param selection the new selection (must be zero or greater)
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (int selection) {
+ checkWidget();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ info.fMask = OS.SIF_POS;
+ info.nPos = selection;
+ SetScrollInfo (hwnd, type, info, true);
+}
+
+/**
+ * Sets the thumb value. The thumb value should be used to represent
+ * the size of the visual portion of the current range. This value is
+ * usually the same as the page increment value.
+ *
+ *
+ */
+public void setThumb (int value) {
+ checkWidget();
+ if (value < 1) return;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ info.fMask = OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
+ OS.GetScrollInfo (hwnd, type, info);
+ info.nPage = value;
+ if (info.nPage != 0) info.nPage++;
+ SetScrollInfo (hwnd, type, info, true);
+}
+
+/**
+ * Sets the receiver's selection, minimum value, maximum
+ * value, thumb, increment and page increment all at once.
+ *
+ *
+ */
+public void setValues (int selection, int minimum, int maximum, int thumb, int increment, int pageIncrement) {
+ checkWidget();
+ if (minimum < 0) return;
+ if (maximum < 0) return;
+ if (thumb < 1) return;
+ if (increment < 1) return;
+ if (pageIncrement < 1) return;
+ this.increment = increment;
+ this.pageIncrement = pageIncrement;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_POS | OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
+ info.nPos = selection;
+ info.nMin = minimum;
+ info.nMax = maximum;
+ info.nPage = thumb;
+ if (info.nPage != 0) info.nPage++;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ SetScrollInfo (hwnd, type, info, true);
+}
+
+/**
+ * Marks the receiver as visible if the argument is true
,
+ * and marks it invisible otherwise.
+ *
+ *
+ */
+public void setVisible (boolean visible) {
+ checkWidget();
+ if (visible == getVisible ()) return;
+ /*
+ * Set the state bits before calling ShowScrollBar ()
+ * because hiding and showing the scroll bar can cause
+ * WM_SIZE messages when the client area is resized.
+ * Setting the state before the call means that code
+ * that runs during WM_SIZE that queries the visibility
+ * of the scroll bar will get the correct value.
+ */
+ state = visible ? state & ~HIDDEN : state | HIDDEN;
+ long hwnd = hwndScrollBar ();
+ int type = scrollBarType ();
+ /*
+ * Bug in Windows 7. Windows will cause pixel corruption
+ * when there is only one scroll bar visible and it is
+ * hidden. The fix is to temporarily show the other scroll
+ * bar and hide both.
+ */
+ if (!visible) {
+ if (OS.IsAppThemed ()) {
+ SCROLLBARINFO psbi = new SCROLLBARINFO ();
+ psbi.cbSize = SCROLLBARINFO.sizeof;
+ int idObject = (style & SWT.VERTICAL) != 0 ? OS.OBJID_HSCROLL : OS.OBJID_VSCROLL;
+ OS.GetScrollBarInfo (hwnd, idObject, psbi);
+ if ((psbi.rgstate [0] & OS.STATE_SYSTEM_INVISIBLE) != 0) {
+ OS.ShowScrollBar (hwnd, type == OS.SB_VERT ? OS.SB_HORZ : OS.SB_VERT, true);
+ type = OS.SB_BOTH;
+ }
+ }
+ }
+ if (OS.ShowScrollBar (hwnd, type, visible)) {
+ /*
+ * Bug in Windows. For some reason, when the widget
+ * is a standard scroll bar, and SetScrollInfo () is
+ * called with SIF_RANGE or SIF_PAGE while the widget
+ * is not visible, the widget is incorrectly disabled
+ * even though the values for SIF_RANGE and SIF_PAGE,
+ * when set for a visible scroll bar would not disable
+ * the scroll bar. The fix is to enable the scroll bar
+ * when not disabled by the application and the current
+ * scroll bar ranges would cause the scroll bar to be
+ * enabled had they been set when the scroll bar was
+ * visible.
+ */
+ if ((state & DISABLED) == 0) {
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
+ OS.GetScrollInfo (hwnd, type, info);
+ if (info.nMax - info.nMin - info.nPage >= 0) {
+ OS.EnableScrollBar (hwnd, type, OS.ESB_ENABLE_BOTH);
+ }
+ }
+ sendEvent (visible ? SWT.Show : SWT.Hide);
+ // widget could be disposed at this point
+ }
+}
+
+LRESULT wmScrollChild (long wParam, long lParam) {
+
+ /* Do nothing when scrolling is ending */
+ int code = OS.LOWORD (wParam);
+ if (code == OS.SB_ENDSCROLL) return null;
+
+ /*
+ * Send the event because WM_HSCROLL and
+ * WM_VSCROLL are sent from a modal message
+ * loop in Windows that is active when the
+ * user is scrolling.
+ */
+ Event event = new Event ();
+ switch (code) {
+ case OS.SB_THUMBPOSITION: event.detail = SWT.NONE; break;
+ case OS.SB_THUMBTRACK: event.detail = SWT.DRAG; break;
+ case OS.SB_TOP: event.detail = SWT.HOME; break;
+ case OS.SB_BOTTOM: event.detail = SWT.END; break;
+ case OS.SB_LINEDOWN: event.detail = SWT.ARROW_DOWN; break;
+ case OS.SB_LINEUP: event.detail = SWT.ARROW_UP; break;
+ case OS.SB_PAGEDOWN: event.detail = SWT.PAGE_DOWN; break;
+ case OS.SB_PAGEUP: event.detail = SWT.PAGE_UP; break;
+ }
+ sendSelectionEvent (SWT.Selection, event, true);
+ // the widget could be destroyed at this point
+ return null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Scrollable.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Scrollable.java
new file mode 100644
index 000000000..c9efef9da
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Scrollable.java
@@ -0,0 +1,500 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * This class is the abstract superclass of all classes which
+ * represent controls that have standard scroll bars.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#H_SCROLL
+ * @see SWT#V_SCROLL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Scrollable (Composite parent, int style) {
+ super (parent, style);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+}
+
+/**
+ * Given a desired client area for the receiver
+ * (as described by the arguments), returns the bounding
+ * rectangle which would be required to produce that client
+ * area.
+ *
+ *
+ *
+ * @see #getClientArea
+ */
+public Rectangle computeTrim (int x, int y, int width, int height) {
+ checkWidget ();
+ x = DPIUtil.autoScaleUp(x);
+ y = DPIUtil.autoScaleUp(y);
+ width = DPIUtil.autoScaleUp(width);
+ height = DPIUtil.autoScaleUp(height);
+ return DPIUtil.autoScaleDown(computeTrimInPixels(x, y, width, height));
+}
+
+Rectangle computeTrimInPixels (int x, int y, int width, int height) {
+ long scrolledHandle = scrolledHandle ();
+ RECT rect = new RECT ();
+ OS.SetRect (rect, x, y, x + width, y + height);
+ int bits1 = OS.GetWindowLong (scrolledHandle, OS.GWL_STYLE);
+ int bits2 = OS.GetWindowLong (scrolledHandle, OS.GWL_EXSTYLE);
+ OS.AdjustWindowRectEx (rect, bits1, false, bits2);
+ if (horizontalBar != null) rect.bottom += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
+ if (verticalBar != null) rect.right += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
+ int nWidth = rect.right - rect.left, nHeight = rect.bottom - rect.top;
+ return new Rectangle (rect.left, rect.top, nWidth, nHeight);
+}
+
+ScrollBar createScrollBar (int type) {
+ ScrollBar bar = new ScrollBar (this, type);
+ if ((state & CANVAS) != 0) {
+ bar.setMaximum (100);
+ bar.setThumb (10);
+ }
+ return bar;
+}
+
+@Override
+void createWidget () {
+ super.createWidget ();
+ /*
+ * NOTE: ICON_CANCEL and ICON_SEARCH have the same value as H_SCROLL and
+ * V_SCROLL. The meaning is determined by whether SWT.SEARCH is set.
+ */
+ if ((style & SWT.SEARCH) == 0) {
+ if ((style & SWT.H_SCROLL) != 0) horizontalBar = createScrollBar (SWT.H_SCROLL);
+ if ((style & SWT.V_SCROLL) != 0) verticalBar = createScrollBar (SWT.V_SCROLL);
+ }
+}
+
+@Override
+void updateBackgroundColor () {
+ switch (applyThemeBackground ()) {
+ case 0: state &= ~THEME_BACKGROUND; break;
+ case 1: state |= THEME_BACKGROUND; break;
+ default: /* No change */
+ }
+ super.updateBackgroundColor ();
+}
+
+/**
+ * @return
+ *
+ *
+ *
+ * @see #computeTrim
+ */
+public Rectangle getClientArea () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getClientAreaInPixels());
+}
+
+Rectangle getClientAreaInPixels () {
+ forceResize ();
+ RECT rect = new RECT ();
+ long scrolledHandle = scrolledHandle ();
+ OS.GetClientRect (scrolledHandle, rect);
+ int x = rect.left, y = rect.top;
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ if (scrolledHandle != handle) {
+ OS.GetClientRect (handle, rect);
+ OS.MapWindowPoints(handle, scrolledHandle, rect, 2);
+ x = -rect.left;
+ y = -rect.top;
+ }
+ return new Rectangle (x, y, width, height);
+}
+
+/**
+ * Returns the receiver's horizontal scroll bar if it has
+ * one, and null if it does not.
+ *
+ * @return the horizontal scroll bar (or null)
+ *
+ * @exception SWTException
+ *
+ */
+public ScrollBar getHorizontalBar () {
+ checkWidget ();
+ return horizontalBar;
+}
+
+/**
+ * Returns the mode of the receiver's scrollbars. This will be
+ * bitwise OR of one or more of the constants defined in class
+ * SWT
.
+ *
+ *
+ *
+ * @return the mode of scrollbars
+ *
+ * @exception SWTException SWT.SCROLLBAR_OVERLAY
- if receiver
+ * uses overlay scrollbarsSWT.NONE
- otherwise
+ *
+ *
+ * @see SWT#SCROLLBAR_OVERLAY
+ *
+ * @since 3.8
+ */
+public int getScrollbarsMode () {
+ checkWidget();
+ return SWT.NONE;
+}
+
+/**
+ * Returns the receiver's vertical scroll bar if it has
+ * one, and null if it does not.
+ *
+ * @return the vertical scroll bar (or null)
+ *
+ * @exception SWTException
+ *
+ */
+public ScrollBar getVerticalBar () {
+ checkWidget ();
+ return verticalBar;
+}
+
+@Override
+void releaseChildren (boolean destroy) {
+ if (horizontalBar != null) {
+ horizontalBar.release (false);
+ horizontalBar = null;
+ }
+ if (verticalBar != null) {
+ verticalBar.release (false);
+ verticalBar = null;
+ }
+ super.releaseChildren (destroy);
+}
+
+@Override
+void reskinChildren (int flags) {
+ if (horizontalBar != null) horizontalBar.reskin (flags);
+ if (verticalBar != null) verticalBar.reskin (flags);
+ super.reskinChildren (flags);
+}
+
+long scrolledHandle () {
+ return handle;
+}
+
+@Override
+int widgetExtStyle () {
+ return super.widgetExtStyle ();
+ /*
+ * This code is intentionally commented. In future,
+ * we may wish to support different standard Windows
+ * edge styles. The issue here is that not all of
+ * these styles are available on the other platforms
+ * this would need to be a hint.
+ */
+// if ((style & SWT.BORDER) != 0) return OS.WS_EX_CLIENTEDGE;
+// if ((style & SWT.SHADOW_IN) != 0) return OS.WS_EX_STATICEDGE;
+// return super.widgetExtStyle ();
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle () | OS.WS_TABSTOP;
+ /*
+ * NOTE: ICON_CANCEL and ICON_SEARCH have the same value as H_SCROLL and
+ * V_SCROLL. The meaning is determined by whether SWT.SEARCH is set.
+ */
+ if ((style & SWT.SEARCH) == 0) {
+ if ((style & SWT.H_SCROLL) != 0) bits |= OS.WS_HSCROLL;
+ if ((style & SWT.V_SCROLL) != 0) bits |= OS.WS_VSCROLL;
+ }
+ return bits;
+}
+
+@Override
+TCHAR windowClass () {
+ return display.windowClass;
+}
+
+@Override
+long windowProc () {
+ return display.windowProc;
+}
+
+@Override
+LRESULT WM_HSCROLL (long wParam, long lParam) {
+ LRESULT result = super.WM_HSCROLL (wParam, lParam);
+ if (result != null) return result;
+ if (horizontalBar != null && lParam == 0) {
+ return wmScroll (horizontalBar, (state & CANVAS) != 0, handle, OS.WM_HSCROLL, wParam, lParam);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_MOUSEWHEEL (long wParam, long lParam) {
+ return wmScrollWheel ((state & CANVAS) != 0, wParam, lParam);
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ long code = callWindowProc (handle, OS.WM_SIZE, wParam, lParam);
+ super.WM_SIZE (wParam, lParam);
+ // widget may be disposed at this point
+ if (code == 0) return LRESULT.ZERO;
+ return new LRESULT (code);
+}
+
+@Override
+LRESULT WM_VSCROLL (long wParam, long lParam) {
+ LRESULT result = super.WM_VSCROLL (wParam, lParam);
+ if (result != null) return result;
+ if (verticalBar != null && lParam == 0) {
+ return wmScroll (verticalBar, (state & CANVAS) != 0, handle, OS.WM_VSCROLL, wParam, lParam);
+ }
+ return result;
+}
+
+LRESULT wmScrollWheel (boolean update, long wParam, long lParam) {
+ LRESULT result = super.WM_MOUSEWHEEL (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Translate WM_MOUSEWHEEL to WM_VSCROLL or WM_HSCROLL.
+ */
+ if (update) {
+ if ((wParam & (OS.MK_SHIFT | OS.MK_CONTROL)) != 0) return result;
+ boolean vertical = verticalBar != null && verticalBar.getEnabled ();
+ boolean horizontal = horizontalBar != null && horizontalBar.getEnabled ();
+ int msg = vertical ? OS.WM_VSCROLL : horizontal ? OS.WM_HSCROLL : 0;
+ if (msg == 0) return result;
+ int [] linesToScroll = new int [1];
+ OS.SystemParametersInfo (OS.SPI_GETWHEELSCROLLLINES, 0, linesToScroll, 0);
+ int delta = OS.GET_WHEEL_DELTA_WPARAM (wParam);
+ boolean pageScroll = linesToScroll [0] == OS.WHEEL_PAGESCROLL;
+ ScrollBar bar = vertical ? verticalBar : horizontalBar;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_POS;
+ OS.GetScrollInfo (handle, bar.scrollBarType (), info);
+ if (vertical && !pageScroll) delta *= linesToScroll [0];
+ int increment = pageScroll ? bar.getPageIncrement () : bar.getIncrement ();
+ info.nPos -= increment * delta / OS.WHEEL_DELTA;
+ OS.SetScrollInfo (handle, bar.scrollBarType (), info, true);
+ OS.SendMessage (handle, msg, OS.SB_THUMBPOSITION, 0);
+ return LRESULT.ZERO;
+ }
+
+ /*
+ * When the native widget scrolls inside WM_MOUSEWHEEL, it
+ * may or may not send a WM_VSCROLL or WM_HSCROLL to do the
+ * actual scrolling. This depends on the implementation of
+ * each native widget. In order to ensure that application
+ * code is notified when the scroll bar moves, compare the
+ * scroll bar position before and after the WM_MOUSEWHEEL.
+ * If the native control sends a WM_VSCROLL or WM_HSCROLL,
+ * then the application has already been notified. If not
+ * explicitly send the event.
+ */
+ int vPosition = verticalBar == null ? 0 : verticalBar.getSelection ();
+ int hPosition = horizontalBar == null ? 0 : horizontalBar.getSelection ();
+ long code = callWindowProc (handle, OS.WM_MOUSEWHEEL, wParam, lParam);
+ if (verticalBar != null) {
+ int position = verticalBar.getSelection ();
+ if (position != vPosition) {
+ Event event = new Event ();
+ event.detail = position < vPosition ? SWT.PAGE_UP : SWT.PAGE_DOWN;
+ verticalBar.sendSelectionEvent (SWT.Selection, event, true);
+ }
+ }
+ if (horizontalBar != null) {
+ int position = horizontalBar.getSelection ();
+ if (position != hPosition) {
+ Event event = new Event ();
+ event.detail = position < hPosition ? SWT.PAGE_UP : SWT.PAGE_DOWN;
+ horizontalBar.sendSelectionEvent (SWT.Selection, event, true);
+ }
+ }
+ return new LRESULT (code);
+}
+
+LRESULT wmScroll (ScrollBar bar, boolean update, long hwnd, int msg, long wParam, long lParam) {
+ LRESULT result = null;
+ if (update) {
+ int type = msg == OS.WM_HSCROLL ? OS.SB_HORZ : OS.SB_VERT;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_TRACKPOS | OS.SIF_POS | OS.SIF_RANGE;
+ OS.GetScrollInfo (hwnd, type, info);
+ info.fMask = OS.SIF_POS;
+ int code = OS.LOWORD (wParam);
+ switch (code) {
+ case OS.SB_ENDSCROLL: return null;
+ case OS.SB_THUMBPOSITION:
+ case OS.SB_THUMBTRACK:
+ info.nPos = info.nTrackPos;
+ break;
+ case OS.SB_TOP:
+ info.nPos = info.nMin;
+ break;
+ case OS.SB_BOTTOM:
+ info.nPos = info.nMax;
+ break;
+ case OS.SB_LINEDOWN:
+ info.nPos += bar.getIncrement ();
+ break;
+ case OS.SB_LINEUP:
+ int increment = bar.getIncrement ();
+ info.nPos = Math.max (info.nMin, info.nPos - increment);
+ break;
+ case OS.SB_PAGEDOWN:
+ info.nPos += bar.getPageIncrement ();
+ break;
+ case OS.SB_PAGEUP:
+ int pageIncrement = bar.getPageIncrement ();
+ info.nPos = Math.max (info.nMin, info.nPos - pageIncrement);
+ break;
+ }
+ OS.SetScrollInfo (hwnd, type, info, true);
+ } else {
+ long code = callWindowProc (hwnd, msg, wParam, lParam);
+ result = code == 0 ? LRESULT.ZERO : new LRESULT (code);
+ }
+ bar.wmScrollChild (wParam, lParam);
+ return result;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Shell.java
new file mode 100644
index 000000000..d41e3d95a
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Shell.java
@@ -0,0 +1,2500 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent the "windows"
+ * which the desktop or "window manager" is managing.
+ * Instances that do not have a parent (that is, they
+ * are built using the constructor, which takes a
+ * Display
as the argument) are described
+ * as top level shells. Instances that do have
+ * a parent are described as secondary or
+ * dialog shells.
+ *
+ *
+ * RESIZE
) until it is
+ * no longer maximized.
+ * PRIMARY_MODAL
style allows an instance to block
+ * input to its parent. The APPLICATION_MODAL
style
+ * allows an instance to block input to every other shell in the
+ * display. The SYSTEM_MODAL
style allows an instance
+ * to block input to all shells, including shells belonging to
+ * different applications.
+ * PRIMARY_MODAL
is not supported,
+ * it would be upgraded to APPLICATION_MODAL
.
+ * A modality style may also be "downgraded" to a less
+ * restrictive style. For example, most operating systems
+ * no longer support SYSTEM_MODAL
because
+ * it can freeze up the desktop, so this is typically
+ * downgraded to APPLICATION_MODAL
.
+ *
+ * SWT
provides two "convenience constants"
+ * for the most commonly required style combinations:
+ *
+ * SHELL_TRIM
CLOSE | TITLE | MIN | MAX | RESIZE
)
+ * DIALOG_TRIM
TITLE | CLOSE | BORDER
)
+ * Shell((Display) null)
.
+ *
+ * @exception SWTException
+ *
+ */
+public Shell () {
+ this ((Display) null);
+}
+
+/**
+ * Constructs a new instance of this class given only the style
+ * value describing its behavior and appearance. This is equivalent
+ * to calling Shell((Display) null, style)
.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ *
+ * @see SWT#BORDER
+ * @see SWT#CLOSE
+ * @see SWT#MIN
+ * @see SWT#MAX
+ * @see SWT#RESIZE
+ * @see SWT#TITLE
+ * @see SWT#TOOL
+ * @see SWT#NO_TRIM
+ * @see SWT#NO_MOVE
+ * @see SWT#SHELL_TRIM
+ * @see SWT#DIALOG_TRIM
+ * @see SWT#ON_TOP
+ * @see SWT#MODELESS
+ * @see SWT#PRIMARY_MODAL
+ * @see SWT#APPLICATION_MODAL
+ * @see SWT#SYSTEM_MODAL
+ * @see SWT#SHEET
+ */
+public Shell (int style) {
+ this ((Display) null, style);
+}
+
+/**
+ * Constructs a new instance of this class given only the display
+ * to create it on. It is created with style SWT.SHELL_TRIM
.
+ *
+ *
+ */
+public Shell (Display display) {
+ this (display, SWT.SHELL_TRIM);
+}
+
+/**
+ * Constructs a new instance of this class given the display
+ * to create it on and a style value describing its behavior
+ * and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ *
+ * @see SWT#BORDER
+ * @see SWT#CLOSE
+ * @see SWT#MIN
+ * @see SWT#MAX
+ * @see SWT#RESIZE
+ * @see SWT#TITLE
+ * @see SWT#TOOL
+ * @see SWT#NO_TRIM
+ * @see SWT#NO_MOVE
+ * @see SWT#SHELL_TRIM
+ * @see SWT#DIALOG_TRIM
+ * @see SWT#ON_TOP
+ * @see SWT#MODELESS
+ * @see SWT#PRIMARY_MODAL
+ * @see SWT#APPLICATION_MODAL
+ * @see SWT#SYSTEM_MODAL
+ * @see SWT#SHEET
+ */
+public Shell (Display display, int style) {
+ this (display, null, style, 0, false);
+}
+
+Shell (Display display, Shell parent, int style, long handle, boolean embedded) {
+ super ();
+ checkSubclass ();
+ if (display == null) display = Display.getCurrent ();
+ if (display == null) display = Display.getDefault ();
+ if (!display.isValidThread ()) {
+ error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ }
+ if (parent != null && parent.isDisposed ()) {
+ error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.center = parent != null && (style & SWT.SHEET) != 0;
+ this.style = checkStyle (parent, style);
+ this.parent = parent;
+ this.display = display;
+ this.handle = handle;
+ if (handle != 0 && !embedded) {
+ state |= FOREIGN_HANDLE;
+ }
+ reskinWidget();
+ createWidget ();
+}
+
+/**
+ * Constructs a new instance of this class given only its
+ * parent. It is created with style SWT.DIALOG_TRIM
.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public Shell (Shell parent) {
+ this (parent, SWT.DIALOG_TRIM);
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#BORDER
+ * @see SWT#CLOSE
+ * @see SWT#MIN
+ * @see SWT#MAX
+ * @see SWT#RESIZE
+ * @see SWT#TITLE
+ * @see SWT#NO_TRIM
+ * @see SWT#NO_MOVE
+ * @see SWT#SHELL_TRIM
+ * @see SWT#DIALOG_TRIM
+ * @see SWT#ON_TOP
+ * @see SWT#TOOL
+ * @see SWT#MODELESS
+ * @see SWT#PRIMARY_MODAL
+ * @see SWT#APPLICATION_MODAL
+ * @see SWT#SYSTEM_MODAL
+ * @see SWT#SHEET
+ */
+public Shell (Shell parent, int style) {
+ this (parent != null ? parent.display : null, parent, style, 0, false);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new shell
+ * that is embedded.
+ * Shell
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * Shell
. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * ShellListener
interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ShellListener
+ * @see #removeShellListener
+ */
+public void addShellListener (ShellListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Close,typedListener);
+ addListener (SWT.Iconify,typedListener);
+ addListener (SWT.Deiconify,typedListener);
+ addListener (SWT.Activate, typedListener);
+ addListener (SWT.Deactivate, typedListener);
+}
+
+long balloonTipHandle () {
+ if (balloonTipHandle == 0) createBalloonTipHandle ();
+ return balloonTipHandle;
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ if (hwnd == toolTipHandle || hwnd == balloonTipHandle || hwnd == menuItemToolTipHandle) {
+ return OS.CallWindowProc (ToolTipProc, hwnd, msg, wParam, lParam);
+ }
+ if (hwndMDIClient != 0) {
+ return OS.DefFrameProc (hwnd, hwndMDIClient, msg, wParam, lParam);
+ }
+ if (windowProc != 0) {
+ return OS.CallWindowProc (windowProc, hwnd, msg, wParam, lParam);
+ }
+ if ((style & SWT.TOOL) != 0) {
+ int trim = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX | SWT.BORDER | SWT.RESIZE;
+ if ((style & trim) == 0) return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+ }
+ if ((style & SWT.NO_MOVE) != 0) {
+ setItemEnabled (OS.SC_MOVE, false);
+ }
+ if (parent != null) {
+ switch (msg) {
+ case OS.WM_KILLFOCUS:
+ case OS.WM_SETFOCUS:
+ return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+ }
+ return OS.CallWindowProc (DialogProc, hwnd, msg, wParam, lParam);
+ }
+ return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+}
+
+void center () {
+ if (parent == null) return;
+ Rectangle rect = getBoundsInPixels ();
+ Rectangle parentRect = display.mapInPixels (parent, null, parent.getClientAreaInPixels());
+ int x = Math.max (parentRect.x, parentRect.x + (parentRect.width - rect.width) / 2);
+ int y = Math.max (parentRect.y, parentRect.y + (parentRect.height - rect.height) / 2);
+ Rectangle monitorRect = parent.getMonitor ().getClientArea();
+ if (x + rect.width > monitorRect.x + monitorRect.width) {
+ x = Math.max (monitorRect.x, monitorRect.x + monitorRect.width - rect.width);
+ } else {
+ x = Math.max (x, monitorRect.x);
+ }
+ if (y + rect.height > monitorRect.y + monitorRect.height) {
+ y = Math.max (monitorRect.y, monitorRect.y + monitorRect.height - rect.height);
+ } else {
+ y = Math.max (y, monitorRect.y);
+ }
+ setLocationInPixels (x, y);
+}
+
+/**
+ * Requests that the window manager close the receiver in
+ * the same way it would be closed when the user clicks on
+ * the "close box" or performs some other platform specific
+ * key or mouse combination that indicates the window
+ * should be removed.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#Close
+ * @see #dispose
+ */
+public void close () {
+ checkWidget ();
+ closeWidget ();
+}
+
+void createBalloonTipHandle () {
+ balloonTipHandle = OS.CreateWindowEx (
+ 0,
+ new TCHAR (0, OS.TOOLTIPS_CLASS, true),
+ null,
+ OS.TTS_ALWAYSTIP | OS.TTS_NOPREFIX | OS.TTS_BALLOON,
+ OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
+ handle,
+ 0,
+ OS.GetModuleHandle (null),
+ null);
+ if (balloonTipHandle == 0) error (SWT.ERROR_NO_HANDLES);
+ if (ToolTipProc == 0) {
+ ToolTipProc = OS.GetWindowLongPtr (balloonTipHandle, OS.GWLP_WNDPROC);
+ }
+ /*
+ * Feature in Windows. Despite the fact that the
+ * tool tip text contains \r\n, the tooltip will
+ * not honour the new line unless TTM_SETMAXTIPWIDTH
+ * is set. The fix is to set TTM_SETMAXTIPWIDTH to
+ * a large value.
+ */
+ OS.SendMessage (balloonTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
+ display.addControl (balloonTipHandle, this);
+ OS.SetWindowLongPtr (balloonTipHandle, OS.GWLP_WNDPROC, display.windowProc);
+}
+
+@Override
+void createHandle () {
+ boolean embedded = handle != 0 && (state & FOREIGN_HANDLE) == 0;
+
+ /*
+ * On Windows 98 and NT, setting a window to be the
+ * top most window using HWND_TOPMOST can result in a
+ * parent dialog shell being moved behind its parent
+ * if the dialog has a sibling that is currently on top
+ * This only occurs using SetWindowPos (), not when the
+ * handle is created.
+ */
+ /*
+ * The following code is intentionally commented.
+ */
+// if ((style & SWT.ON_TOP) != 0) display.lockActiveWindow = true;
+ if (handle == 0 || embedded) {
+ super.createHandle ();
+ } else {
+ state |= CANVAS;
+ if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) {
+ state |= THEME_BACKGROUND;
+ }
+ windowProc = OS.GetWindowLongPtr (handle, OS.GWL_WNDPROC);
+ }
+
+ /*
+ * The following code is intentionally commented.
+ */
+// if ((style & SWT.ON_TOP) != 0) display.lockActiveWindow = false;
+
+ if (!embedded) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ bits &= ~(OS.WS_OVERLAPPED | OS.WS_CAPTION);
+ bits |= OS.WS_POPUP;
+ if ((style & SWT.TITLE) != 0) bits |= OS.WS_CAPTION;
+ if ((style & SWT.NO_TRIM) == 0) {
+ if ((style & (SWT.BORDER | SWT.RESIZE)) == 0) bits |= OS.WS_BORDER;
+ }
+ /*
+ * Bug in Windows. When the WS_CAPTION bits are cleared using
+ * SetWindowLong(), Windows does not resize the client area of
+ * the window to get rid of the caption until the first resize.
+ * The fix is to use SetWindowPos() with SWP_DRAWFRAME to force
+ * the frame to be redrawn and resized.
+ */
+ OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+ int flags = OS.SWP_DRAWFRAME | OS.SWP_NOMOVE | OS.SWP_NOSIZE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (handle, 0, 0, 0, 0, 0, flags);
+ }
+ if (OS.IsDBLocale) {
+ hIMC = OS.ImmCreateContext ();
+ if (hIMC != 0) OS.ImmAssociateContext (handle, hIMC);
+ }
+}
+
+void createMenuItemToolTipHandle() {
+ menuItemToolTipHandle = createToolTipHandle (0);
+}
+
+void createToolTip (ToolTip toolTip) {
+ int id = 0;
+ if (toolTips == null) toolTips = new ToolTip [4];
+ while (id < toolTips.length && toolTips [id] != null) id++;
+ if (id == toolTips.length) {
+ ToolTip [] newToolTips = new ToolTip [toolTips.length + 4];
+ System.arraycopy (toolTips, 0, newToolTips, 0, toolTips.length);
+ toolTips = newToolTips;
+ }
+ toolTips [id] = toolTip;
+ toolTip.id = id + Display.ID_START;
+ TOOLINFO lpti = new TOOLINFO ();
+ lpti.cbSize = TOOLINFO.sizeof;
+ lpti.hwnd = handle;
+ lpti.uId = toolTip.id;
+ lpti.uFlags = OS.TTF_TRACK;
+ lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
+ OS.SendMessage (toolTip.hwndToolTip (), OS.TTM_ADDTOOL, 0, lpti);
+}
+
+void createToolTipHandle () {
+ toolTipHandle = createToolTipHandle (handle);
+}
+
+long createToolTipHandle (long parent) {
+ long toolTipHandle = OS.CreateWindowEx (
+ 0,
+ new TCHAR (0, OS.TOOLTIPS_CLASS, true),
+ null,
+ OS.TTS_ALWAYSTIP | OS.TTS_NOPREFIX,
+ OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
+ parent,
+ 0,
+ OS.GetModuleHandle (null),
+ null);
+ if (toolTipHandle == 0) error (SWT.ERROR_NO_HANDLES);
+ if (ToolTipProc == 0) {
+ ToolTipProc = OS.GetWindowLongPtr (toolTipHandle, OS.GWLP_WNDPROC);
+ }
+ /*
+ * Feature in Windows. Despite the fact that the
+ * tool tip text contains \r\n, the tooltip will
+ * not honour the new line unless TTM_SETMAXTIPWIDTH
+ * is set. The fix is to set TTM_SETMAXTIPWIDTH to
+ * a large value.
+ */
+ OS.SendMessage (toolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
+ display.addControl (toolTipHandle, this);
+ OS.SetWindowLongPtr (toolTipHandle, OS.GWLP_WNDPROC, display.windowProc);
+ return toolTipHandle;
+}
+
+@Override
+void deregister () {
+ super.deregister ();
+ if (toolTipHandle != 0) display.removeControl (toolTipHandle);
+ if (balloonTipHandle != 0) display.removeControl (balloonTipHandle);
+ if (menuItemToolTipHandle != 0) display.removeControl (menuItemToolTipHandle);
+}
+
+void destroyToolTip (ToolTip toolTip) {
+ if (toolTips == null) return;
+ toolTips [toolTip.id - Display.ID_START] = null;
+ if (balloonTipHandle != 0) {
+ TOOLINFO lpti = new TOOLINFO ();
+ lpti.cbSize = TOOLINFO.sizeof;
+ lpti.uId = toolTip.id;
+ lpti.hwnd = handle;
+ OS.SendMessage (balloonTipHandle, OS.TTM_DELTOOL, 0, lpti);
+ }
+ toolTip.id = -1;
+}
+
+@Override
+void destroyWidget () {
+ fixActiveShell ();
+ super.destroyWidget ();
+
+ /*
+ * Destroy context only after the controls that used it were destroyed.
+ * Technically, that shouldn't be necessary, because 'Control.releaseWidget'
+ * clears up association by calling 'OS.ImmAssociateContext (handle, 0)'.
+ * However, there's a bug in Windows 10 (see bug 526758), and this is the workaround.
+ */
+ if (OS.IsDBLocale) {
+ if (hIMC != 0) OS.ImmDestroyContext (hIMC);
+ }
+}
+
+@Override
+public void dispose () {
+ /*
+ * This code is intentionally commented. On some
+ * platforms, the owner window is repainted right
+ * away when a dialog window exits. This behavior
+ * is currently unspecified.
+ */
+// /*
+// * Note: It is valid to attempt to dispose a widget
+// * more than once. If this happens, fail silently.
+// */
+// if (!isValidWidget ()) return;
+// if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
+// Display oldDisplay = display;
+ super.dispose ();
+ // widget is disposed at this point
+// if (oldDisplay != null) oldDisplay.update ();
+}
+
+@Override
+void enableWidget (boolean enabled) {
+ if (enabled) {
+ state &= ~DISABLED;
+ } else {
+ state |= DISABLED;
+ }
+ if (Display.TrimEnabled) {
+ if (isActive ()) setItemEnabled (OS.SC_CLOSE, enabled);
+ } else {
+ OS.EnableWindow (handle, enabled);
+ }
+}
+
+@Override
+long findBrush (long value, int lbStyle) {
+ if (lbStyle == OS.BS_SOLID) {
+ for (int i=0; i
+ *
+ *
+ * @since 3.4
+ */
+public int getAlpha () {
+ checkWidget ();
+ byte [] pbAlpha = new byte [1];
+ if (OS.GetLayeredWindowAttributes (handle, null, pbAlpha, null)) {
+ return pbAlpha [0] & 0xFF;
+ }
+ return 0xFF;
+}
+
+@Override Rectangle getBoundsInPixels () {
+ if (OS.IsIconic (handle)) return super.getBoundsInPixels ();
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ return new Rectangle (rect.left, rect.top, width, height);
+}
+
+ToolTip getCurrentToolTip () {
+ if (toolTipHandle != 0) {
+ ToolTip tip = getCurrentToolTip (toolTipHandle);
+ if (tip != null) return tip;
+ }
+ if (balloonTipHandle != 0) {
+ ToolTip tip = getCurrentToolTip (balloonTipHandle);
+ if (tip != null) return tip;
+ }
+ if (menuItemToolTipHandle != 0) {
+ ToolTip tip = getCurrentToolTip (menuItemToolTipHandle);
+ if (tip != null) return tip;
+ }
+ return null;
+}
+
+ToolTip getCurrentToolTip (long hwndToolTip) {
+ if (hwndToolTip == 0) return null;
+ if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, 0) != 0) {
+ TOOLINFO lpti = new TOOLINFO ();
+ lpti.cbSize = TOOLINFO.sizeof;
+ if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, lpti) != 0) {
+ if ((lpti.uFlags & OS.TTF_IDISHWND) == 0) return findToolTip ((int)lpti.uId);
+ }
+ }
+ return null;
+}
+
+@Override
+public boolean getEnabled () {
+ checkWidget ();
+ return (state & DISABLED) == 0;
+}
+
+/**
+ * Returns true
if the receiver is currently
+ * in fullscreen state, and false otherwise.
+ *
+ *
+ *
+ * @since 3.4
+ */
+public boolean getFullScreen () {
+ checkWidget();
+ return fullScreen;
+}
+
+/**
+ * Returns the receiver's input method editor mode. This
+ * will be the result of bitwise OR'ing together one or
+ * more of the following constants defined in class
+ * SWT
:
+ * NONE
, ROMAN
, DBCS
,
+ * PHONETIC
, NATIVE
, ALPHA
.
+ *
+ * @return the IME mode
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ */
+public int getImeInputMode () {
+ checkWidget ();
+ if (!OS.IsDBLocale) return 0;
+ long hIMC = OS.ImmGetContext (handle);
+ int [] lpfdwConversion = new int [1], lpfdwSentence = new int [1];
+ boolean open = OS.ImmGetOpenStatus (hIMC);
+ if (open) open = OS.ImmGetConversionStatus (hIMC, lpfdwConversion, lpfdwSentence);
+ OS.ImmReleaseContext (handle, hIMC);
+ if (!open) return SWT.NONE;
+ int result = 0;
+ if ((lpfdwConversion [0] & OS.IME_CMODE_ROMAN) != 0) result |= SWT.ROMAN;
+ if ((lpfdwConversion [0] & OS.IME_CMODE_FULLSHAPE) != 0) result |= SWT.DBCS;
+ if ((lpfdwConversion [0] & OS.IME_CMODE_KATAKANA) != 0) return result | SWT.PHONETIC;
+ if ((lpfdwConversion [0] & OS.IME_CMODE_NATIVE) != 0) return result | SWT.NATIVE;
+ return result | SWT.ALPHA;
+}
+
+@Override Point getLocationInPixels () {
+ if (OS.IsIconic (handle)) return super.getLocationInPixels ();
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ return new Point (rect.left, rect.top);
+}
+
+@Override
+public boolean getMaximized () {
+ checkWidget ();
+ return !fullScreen && super.getMaximized ();
+}
+
+/**
+ * Returns a point describing the minimum receiver's size. The
+ * x coordinate of the result is the minimum width of the receiver.
+ * The y coordinate of the result is the minimum height of the
+ * receiver.
+ *
+ * @return the receiver's size
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.1
+ */
+public Point getMinimumSize () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getMinimumSizeInPixels());
+}
+
+Point getMinimumSizeInPixels () {
+ int width = Math.max (0, minWidth);
+ int trim = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX;
+ if ((style & SWT.NO_TRIM) == 0 && (style & trim) != 0) {
+ width = Math.max (width, OS.GetSystemMetrics (OS.SM_CXMINTRACK));
+ }
+ int height = Math.max (0, minHeight);
+ if ((style & SWT.NO_TRIM) == 0 && (style & trim) != 0) {
+ if ((style & SWT.RESIZE) != 0) {
+ height = Math.max (height, OS.GetSystemMetrics (OS.SM_CYMINTRACK));
+ } else {
+ RECT rect = new RECT ();
+ int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ OS.AdjustWindowRectEx (rect, bits1, false, bits2);
+ height = Math.max (height, rect.bottom - rect.top);
+ }
+ }
+ return new Point (width, height);
+}
+
+/**
+ * Gets the receiver's modified state.
+ *
+ * @return true
if the receiver is marked as modified, or false
otherwise
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.5
+ */
+public boolean getModified () {
+ checkWidget ();
+ return modified;
+}
+
+/**
+ * Returns the region that defines the shape of the shell,
+ * or null
if the shell has the default shape.
+ *
+ * @return the region that defines the shape of the shell, or null
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.0
+ *
+ */
+@Override
+public Region getRegion () {
+ /* This method is needed for the @since 3.0 Javadoc */
+ checkWidget ();
+ return region;
+}
+
+@Override
+public Shell getShell () {
+ checkWidget ();
+ return this;
+}
+
+@Override Point getSizeInPixels () {
+ if (OS.IsIconic (handle)) return super.getSizeInPixels ();
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ return new Point (width, height);
+}
+
+/**
+ * Returns an array containing all shells which are
+ * descendants of the receiver.
+ *
+ *
+ */
+public Shell [] getShells () {
+ checkWidget ();
+ int count = 0;
+ Shell [] shells = display.getShells ();
+ for (int i=0; inull
.
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.7
+ */
+public ToolBar getToolBar() {
+ checkWidget ();
+ return null;
+}
+
+@Override
+Composite findDeferredControl () {
+ return layoutCount > 0 ? this : null;
+}
+
+@Override
+public boolean isEnabled () {
+ checkWidget ();
+ return getEnabled ();
+}
+
+@Override
+public boolean isVisible () {
+ checkWidget ();
+ return getVisible ();
+}
+
+long hwndMDIClient () {
+ if (hwndMDIClient == 0) {
+ int widgetStyle = OS.MDIS_ALLCHILDSTYLES | OS.WS_CHILD | OS.WS_CLIPCHILDREN | OS.WS_CLIPSIBLINGS;
+ hwndMDIClient = OS.CreateWindowEx (
+ 0,
+ new TCHAR (0, "MDICLIENT", true),
+ null,
+ widgetStyle,
+ 0, 0, 0, 0,
+ handle,
+ 0,
+ OS.GetModuleHandle (null),
+ new CREATESTRUCT ());
+// OS.ShowWindow (hwndMDIClient, OS.SW_SHOW);
+ }
+ return hwndMDIClient;
+}
+
+long menuItemToolTipHandle () {
+ if (menuItemToolTipHandle == 0) createMenuItemToolTipHandle ();
+ return menuItemToolTipHandle;
+}
+
+/**
+ * Moves the receiver to the top of the drawing order for
+ * the display on which it was created (so that all other
+ * shells on that display, which are not the receiver's
+ * children will be drawn behind it), marks it visible,
+ * sets the focus and asks the window manager to make the
+ * shell active.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Control#moveAbove
+ * @see Control#setFocus
+ * @see Control#setVisible
+ * @see Display#getActiveShell
+ * @see Decorations#setDefaultButton(Button)
+ * @see Shell#setActive
+ * @see Shell#forceActive
+ */
+public void open () {
+ checkWidget ();
+ STARTUPINFO lpStartUpInfo = Display.lpStartupInfo;
+ if (lpStartUpInfo == null || (lpStartUpInfo.dwFlags & OS.STARTF_USESHOWWINDOW) == 0) {
+ bringToTop ();
+ if (isDisposed ()) return;
+ }
+ OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
+ setVisible (true);
+ if (isDisposed ()) return;
+ /*
+ * Bug in Windows XP. Despite the fact that an icon has been
+ * set for a window, the task bar displays the wrong icon the
+ * first time the window is made visible with ShowWindow() after
+ * a call to BringToTop(), when a long time elapses between the
+ * ShowWindow() and the time the event queue is read. The icon
+ * in the window trimming is correct but the one in the task
+ * bar does not get updated. The fix is to call PeekMessage()
+ * with the flag PM_NOREMOVE and PM_QS_SENDMESSAGE to respond
+ * to a cross thread WM_GETICON.
+ *
+ * NOTE: This allows other cross thread messages to be delivered,
+ * most notably WM_ACTIVATE.
+ */
+ MSG msg = new MSG ();
+ int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_SENDMESSAGE;
+ OS.PeekMessage (msg, 0, 0, 0, flags);
+ /*
+ * When no widget has been given focus, or another push button has focus,
+ * give focus to the default button. This avoids overriding the default
+ * button.
+ */
+ boolean restored = restoreFocus ();
+ if (!restored) {
+ restored = traverseGroup (true);
+ }
+ if (restored) {
+ Control focusControl = display.getFocusControl ();
+ if (focusControl instanceof Button && (focusControl.style & SWT.PUSH) != 0) {
+ restored = false;
+ }
+ }
+ if (!restored) {
+ if (saveDefault != null && !saveDefault.isDisposed ()) {
+ saveDefault.setFocus ();
+ } else {
+ setFocus ();
+ }
+ }
+}
+
+@Override
+public boolean print (GC gc) {
+ checkWidget ();
+ if (gc == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
+ return false;
+}
+
+@Override
+void register () {
+ super.register ();
+ if (toolTipHandle != 0) display.addControl (toolTipHandle, this);
+ if (balloonTipHandle != 0) display.addControl (balloonTipHandle, this);
+ if (menuItemToolTipHandle != 0) display.addControl (menuItemToolTipHandle, this);
+}
+
+void releaseBrushes () {
+ if (brushes != null) {
+ for (int i=0; i
+ *
+ *
+ * @see ShellListener
+ * @see #addShellListener
+ */
+public void removeShellListener (ShellListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Close, listener);
+ eventTable.unhook (SWT.Iconify,listener);
+ eventTable.unhook (SWT.Deiconify,listener);
+ eventTable.unhook (SWT.Activate, listener);
+ eventTable.unhook (SWT.Deactivate, listener);
+}
+
+@Override
+public void requestLayout () {
+ layout (null, SWT.DEFER);
+}
+
+@Override
+void reskinChildren (int flags) {
+ Shell [] shells = getShells ();
+ for (int i=0; i
+ *
+ *
+ * @since 3.4
+ */
+public void setAlpha (int alpha) {
+ checkWidget ();
+ alpha &= 0xFF;
+ int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ if (alpha == 0xFF) {
+ OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits & ~OS.WS_EX_LAYERED);
+ int flags = OS.RDW_ERASE | OS.RDW_INVALIDATE | OS.RDW_FRAME | OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (handle, null, 0, flags);
+ } else {
+ OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits | OS.WS_EX_LAYERED);
+ OS.SetLayeredWindowAttributes (handle, 0, (byte)alpha, OS.LWA_ALPHA);
+ }
+}
+
+@Override
+void setBoundsInPixels (int x, int y, int width, int height, int flags, boolean defer) {
+ if (fullScreen) setFullScreen (false);
+ /*
+ * Bug in Windows. When a window has alpha and
+ * SetWindowPos() is called with SWP_DRAWFRAME,
+ * the contents of the window are copied rather
+ * than allowing the windows underneath to draw.
+ * This causes pixel corruption. The fix is to
+ * clear the SWP_DRAWFRAME bits.
+ */
+ int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ if ((bits & OS.WS_EX_LAYERED) != 0) {
+ flags &= ~OS.SWP_DRAWFRAME;
+ }
+ super.setBoundsInPixels (x, y, width, height, flags, false);
+}
+
+@Override
+public void setEnabled (boolean enabled) {
+ checkWidget ();
+ if (((state & DISABLED) == 0) == enabled) return;
+ super.setEnabled (enabled);
+ if (enabled && handle == OS.GetActiveWindow ()) {
+ if (!restoreFocus ()) traverseGroup (true);
+ }
+}
+
+/**
+ * Sets the full screen state of the receiver.
+ * If the argument is true
causes the receiver
+ * to switch to the full screen state, and if the argument is
+ * false
and the receiver was previously switched
+ * into full screen state, causes the receiver to switch back
+ * to either the maximized or normal states.
+ * setFullScreen(true)
,
+ * setMaximized(true)
and setMinimized(true)
will
+ * vary by platform. Typically, the behavior will match the platform user's
+ * expectations, but not always. This should be avoided if possible.
+ *
+ *
+ *
+ * @since 3.4
+ */
+public void setFullScreen (boolean fullScreen) {
+ checkWidget();
+ if (this.fullScreen == fullScreen) return;
+ int stateFlags = fullScreen ? OS.SW_SHOWMAXIMIZED : OS.SW_RESTORE;
+ int styleFlags = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ int mask = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX;
+ if ((style & mask) != 0) {
+ if (fullScreen) {
+ styleFlags &= ~(OS.WS_CAPTION | OS.WS_MAXIMIZEBOX | OS.WS_MINIMIZEBOX | OS.WS_THICKFRAME);
+ } else {
+ styleFlags |= OS.WS_CAPTION;
+ if ((style & SWT.MAX) != 0) styleFlags |= OS.WS_MAXIMIZEBOX;
+ if ((style & SWT.MIN) != 0) styleFlags |= OS.WS_MINIMIZEBOX;
+ if ((style & SWT.RESIZE) != 0) styleFlags |= OS.WS_THICKFRAME;
+ }
+ }
+ if (fullScreen) wasMaximized = getMaximized ();
+ boolean visible = isVisible ();
+ OS.SetWindowLong (handle, OS.GWL_STYLE, styleFlags);
+ if (wasMaximized) {
+ OS.ShowWindow (handle, OS.SW_HIDE);
+ stateFlags = OS.SW_SHOWMAXIMIZED;
+ }
+ if (visible) OS.ShowWindow (handle, stateFlags);
+ OS.UpdateWindow (handle);
+ this.fullScreen = fullScreen;
+}
+
+/**
+ * Sets the input method editor mode to the argument which
+ * should be the result of bitwise OR'ing together one or more
+ * of the following constants defined in class SWT
:
+ * NONE
, ROMAN
, DBCS
,
+ * PHONETIC
, NATIVE
, ALPHA
.
+ *
+ * @param mode the new IME mode
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ */
+public void setImeInputMode (int mode) {
+ checkWidget ();
+ if (!OS.IsDBLocale) return;
+ boolean imeOn = mode != SWT.NONE;
+ long hIMC = OS.ImmGetContext (handle);
+ OS.ImmSetOpenStatus (hIMC, imeOn);
+ if (imeOn) {
+ int [] lpfdwConversion = new int [1], lpfdwSentence = new int [1];
+ if (OS.ImmGetConversionStatus (hIMC, lpfdwConversion, lpfdwSentence)) {
+ int newBits = 0;
+ int oldBits = OS.IME_CMODE_NATIVE | OS.IME_CMODE_KATAKANA;
+ if ((mode & SWT.PHONETIC) != 0) {
+ newBits = OS.IME_CMODE_KATAKANA | OS.IME_CMODE_NATIVE;
+ oldBits = 0;
+ } else {
+ if ((mode & SWT.NATIVE) != 0) {
+ newBits = OS.IME_CMODE_NATIVE;
+ oldBits = OS.IME_CMODE_KATAKANA;
+ }
+ }
+ boolean fullShape = (mode & SWT.DBCS) != 0;
+ if ((mode & SWT.NATIVE) != 0) {
+ long hkl = OS.GetKeyboardLayout (0);
+ int langid = OS.PRIMARYLANGID (OS.LOWORD (hkl));
+ if (langid == OS.LANG_JAPANESE) {
+ fullShape = true;
+ }
+ }
+ if (fullShape) {
+ newBits |= OS.IME_CMODE_FULLSHAPE;
+ } else {
+ oldBits |= OS.IME_CMODE_FULLSHAPE;
+ }
+ if ((mode & SWT.ROMAN) != 0) {
+ newBits |= OS.IME_CMODE_ROMAN;
+ } else {
+ oldBits |= OS.IME_CMODE_ROMAN;
+ }
+ lpfdwConversion [0] |= newBits;
+ lpfdwConversion [0] &= ~oldBits;
+ OS.ImmSetConversionStatus (hIMC, lpfdwConversion [0], lpfdwSentence [0]);
+ }
+ }
+ OS.ImmReleaseContext (handle, hIMC);
+}
+
+/**
+ * Sets the receiver's minimum size to the size specified by the arguments.
+ * If the new minimum size is larger than the current size of the receiver,
+ * the receiver is resized to the new minimum size.
+ *
+ * @param width the new minimum width for the receiver
+ * @param height the new minimum height for the receiver
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.1
+ */
+public void setMinimumSize (int width, int height) {
+ checkWidget ();
+ setMinimumSizeInPixels(DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height));
+}
+
+void setMinimumSizeInPixels (int width, int height) {
+ int widthLimit = 0, heightLimit = 0;
+ int trim = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX;
+ if ((style & SWT.NO_TRIM) == 0 && (style & trim) != 0) {
+ widthLimit = OS.GetSystemMetrics (OS.SM_CXMINTRACK);
+ if ((style & SWT.RESIZE) != 0) {
+ heightLimit = OS.GetSystemMetrics (OS.SM_CYMINTRACK);
+ } else {
+ RECT rect = new RECT ();
+ int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ OS.AdjustWindowRectEx (rect, bits1, false, bits2);
+ heightLimit = rect.bottom - rect.top;
+ }
+ }
+ minWidth = Math.max (widthLimit, width);
+ minHeight = Math.max (heightLimit, height);
+ Point size = getSizeInPixels ();
+ int newWidth = Math.max (size.x, minWidth);
+ int newHeight = Math.max (size.y, minHeight);
+ if (minWidth <= widthLimit) minWidth = SWT.DEFAULT;
+ if (minHeight <= heightLimit) minHeight = SWT.DEFAULT;
+ if (newWidth != size.x || newHeight != size.y) setSizeInPixels (newWidth, newHeight);
+}
+
+/**
+ * Sets the receiver's minimum size to the size specified by the argument.
+ * If the new minimum size is larger than the current size of the receiver,
+ * the receiver is resized to the new minimum size.
+ *
+ * @param size the new minimum size for the receiver
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.1
+ */
+public void setMinimumSize (Point size) {
+ checkWidget ();
+ if (size == null) error (SWT.ERROR_NULL_ARGUMENT);
+ size = DPIUtil.autoScaleUp(size);
+ setMinimumSizeInPixels(size.x, size.y);
+}
+
+/**
+ * Sets the receiver's modified state as specified by the argument.
+ *
+ * @param modified the new modified state for the receiver
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.5
+ */
+public void setModified (boolean modified) {
+ checkWidget ();
+ this.modified = modified;
+}
+
+void setItemEnabled (int cmd, boolean enabled) {
+ long hMenu = OS.GetSystemMenu (handle, false);
+ if (hMenu == 0) return;
+ int flags = OS.MF_ENABLED;
+ if (!enabled) flags = OS.MF_DISABLED | OS.MF_GRAYED;
+ OS.EnableMenuItem (hMenu, cmd, OS.MF_BYCOMMAND | flags);
+}
+
+@Override
+void setParent () {
+ /* Do nothing. Not necessary for Shells */
+}
+
+/**
+ * Sets the shape of the shell to the region specified
+ * by the argument. When the argument is null, the
+ * default shape of the shell is restored. The shell
+ * must be created with the style SWT.NO_TRIM in order
+ * to specify a region.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.0
+ */
+@Override
+public void setRegion (Region region) {
+ checkWidget ();
+ if ((style & SWT.NO_TRIM) == 0) return;
+ if (region != null) {
+ Rectangle bounds = region.getBounds ();
+ setSize (bounds.x + bounds.width, bounds.y + bounds.height);
+ }
+ super.setRegion (region);
+}
+
+void setToolTipText (long hwnd, String text) {
+ TOOLINFO lpti = new TOOLINFO ();
+ lpti.cbSize = TOOLINFO.sizeof;
+ lpti.hwnd = handle;
+ lpti.uId = hwnd;
+ long hwndToolTip = toolTipHandle ();
+ if (text == null) {
+ OS.SendMessage (hwndToolTip, OS.TTM_DELTOOL, 0, lpti);
+ } else {
+ if (OS.SendMessage (hwndToolTip, OS.TTM_GETTOOLINFO, 0, lpti) != 0) {
+ OS.SendMessage (hwndToolTip, OS.TTM_UPDATE, 0, 0);
+ } else {
+ lpti.uFlags = OS.TTF_IDISHWND | OS.TTF_SUBCLASS;
+ lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
+ OS.SendMessage (hwndToolTip, OS.TTM_ADDTOOL, 0, lpti);
+ }
+ }
+}
+
+void setToolTipText (NMTTDISPINFO lpnmtdi, char [] buffer) {
+ /*
+ * Ensure that the current position of the mouse
+ * is inside the client area of the shell. This
+ * prevents tool tips from popping up over the
+ * shell trimmings.
+ */
+ if (!hasCursor ()) return;
+ long hHeap = OS.GetProcessHeap ();
+ if (lpstrTip != 0) OS.HeapFree (hHeap, 0, lpstrTip);
+ int byteCount = buffer.length * 2;
+ lpstrTip = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory (lpstrTip, buffer, byteCount);
+ lpnmtdi.lpszText = lpstrTip;
+}
+
+void setToolTipTitle (long hwndToolTip, String text, int icon) {
+ /*
+ * Bug in Windows. For some reason, when TTM_SETTITLE
+ * is used to set the title of a tool tip, Windows leaks
+ * GDI objects. This happens even when TTM_SETTITLE is
+ * called with TTI_NONE and NULL. The documentation
+ * states that Windows copies the icon and that the
+ * programmer must free the copy but does not provide
+ * API to get the icon. For example, when TTM_SETTITLE
+ * is called with ICON_ERROR, when TTM_GETTITLE is used
+ * to query the title and the icon, the uTitleBitmap
+ * field in the TTGETTITLE struct is zero. The fix
+ * is to remember these values, only set them when then
+ * change and leak less.
+ *
+ * NOTE: This only happens on Vista.
+ */
+ if (hwndToolTip != toolTipHandle && hwndToolTip != balloonTipHandle && hwndToolTip != menuItemToolTipHandle) {
+ return;
+ }
+ if (hwndToolTip == toolTipHandle || hwndToolTip == menuItemToolTipHandle) {
+ if (text == toolTitle || (toolTitle != null && toolTitle.equals (text))) {
+ if (icon == toolIcon) return;
+ }
+ toolTitle = text;
+ toolIcon = icon;
+ } else {
+ if (hwndToolTip == balloonTipHandle) {
+ if (text == balloonTitle || (balloonTitle != null && balloonTitle.equals (text))) {
+ if (icon == toolIcon) return;
+ }
+ balloonTitle = text;
+ balloonIcon = icon;
+ }
+ }
+ if (text != null) {
+ /*
+ * Feature in Windows. The text point to by pszTitle
+ * must not exceed 100 characters in length, including
+ * the null terminator.
+ */
+ if (text.length () > 99) text = text.substring (0, 99);
+ TCHAR pszTitle = new TCHAR (getCodePage (), text, true);
+ OS.SendMessage (hwndToolTip, OS.TTM_SETTITLE, icon, pszTitle);
+ } else {
+ OS.SendMessage (hwndToolTip, OS.TTM_SETTITLE, 0, 0);
+ }
+}
+
+@Override
+public void setVisible (boolean visible) {
+ checkWidget ();
+ /*
+ * Feature in Windows. When ShowWindow() is called used to hide
+ * a window, Windows attempts to give focus to the parent. If the
+ * parent is disabled by EnableWindow(), focus is assigned to
+ * another windows on the desktop. This means that if you hide
+ * a modal window before the parent is enabled, the parent will
+ * not come to the front. The fix is to change the modal state
+ * before hiding or showing a window so that this does not occur.
+ */
+ int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
+ if ((style & mask) != 0) {
+ if (visible) {
+ display.setModalShell (this);
+ if ((style & (SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) {
+ display.setModalDialog (null);
+ }
+ Control control = display._getFocusControl ();
+ if (control != null && !control.isActive ()) {
+ bringToTop ();
+ if (isDisposed ()) return;
+ }
+ long hwndShell = OS.GetActiveWindow ();
+ if (hwndShell == 0) {
+ if (parent != null) hwndShell = parent.handle;
+ }
+ if (hwndShell != 0) {
+ OS.SendMessage (hwndShell, OS.WM_CANCELMODE, 0, 0);
+ }
+ OS.ReleaseCapture ();
+ } else {
+ display.clearModal (this);
+ }
+ } else {
+ updateModal ();
+ }
+
+ /*
+ * Bug in Windows. Calling ShowOwnedPopups() to hide the
+ * child windows of a hidden window causes the application
+ * to be deactivated. The fix is to call ShowOwnedPopups()
+ * to hide children before hiding the parent.
+ */
+ if (showWithParent && !visible) {
+ OS.ShowOwnedPopups (handle, false);
+ }
+ if (!visible) fixActiveShell ();
+ if (visible && center && !moved) {
+ center ();
+ if (isDisposed ()) return;
+ }
+ super.setVisible (visible);
+ if (isDisposed ()) return;
+ if (showWithParent != visible) {
+ showWithParent = visible;
+ if (visible) {
+ OS.ShowOwnedPopups (handle, true);
+ }
+ }
+
+ /* Make the foreign window parent appear in the task bar */
+ if (visible) {
+ if (parent != null && (parent.state & FOREIGN_HANDLE) != 0) {
+ long hwndParent = parent.handle;
+ int style = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
+ if ((style & OS.WS_EX_TOOLWINDOW) != 0) {
+ OS.SetWindowLong (hwndParent, OS.GWL_EXSTYLE, style & ~OS.WS_EX_TOOLWINDOW);
+ /*
+ * Bug in Windows. The window does not show in the task bar when
+ * WS_EX_TOOLWINDOW is removed after the window has already been shown.
+ * The fix is to hide and shown the shell.
+ */
+ OS.ShowWindow (hwndParent, OS.SW_HIDE);
+ OS.ShowWindow (hwndParent, OS.SW_RESTORE);
+ }
+ }
+ }
+}
+
+@Override
+void subclass () {
+ super.subclass ();
+ if (ToolTipProc != 0) {
+ long newProc = display.windowProc;
+ if (toolTipHandle != 0) {
+ OS.SetWindowLongPtr (toolTipHandle, OS.GWLP_WNDPROC, newProc);
+ }
+ if (balloonTipHandle != 0) {
+ OS.SetWindowLongPtr (balloonTipHandle, OS.GWLP_WNDPROC, newProc);
+ }
+ if (menuItemToolTipHandle != 0) {
+ OS.SetWindowLongPtr (menuItemToolTipHandle, OS.GWLP_WNDPROC, newProc);
+ }
+ }
+}
+
+long toolTipHandle () {
+ if (toolTipHandle == 0) createToolTipHandle ();
+ return toolTipHandle;
+}
+
+@Override
+boolean translateAccelerator (MSG msg) {
+ if (!isEnabled () || !isActive ()) return false;
+ if (menuBar != null && !menuBar.isEnabled ()) return false;
+ return translateMDIAccelerator (msg) || translateMenuAccelerator (msg);
+}
+
+@Override
+boolean traverseEscape () {
+ if (parent == null) return false;
+ if (!isVisible () || !isEnabled ()) return false;
+ close ();
+ return true;
+}
+
+@Override
+void unsubclass () {
+ super.unsubclass ();
+ if (ToolTipProc != 0) {
+ if (toolTipHandle != 0) {
+ OS.SetWindowLongPtr (toolTipHandle, OS.GWLP_WNDPROC, ToolTipProc);
+ }
+ if (toolTipHandle != 0) {
+ OS.SetWindowLongPtr (toolTipHandle, OS.GWLP_WNDPROC, ToolTipProc);
+ }
+ if (menuItemToolTipHandle != 0) {
+ OS.SetWindowLongPtr (menuItemToolTipHandle, OS.GWLP_WNDPROC, ToolTipProc);
+ }
+ }
+}
+
+void updateModal () {
+ if (Display.TrimEnabled) {
+ setItemEnabled (OS.SC_CLOSE, isActive ());
+ } else {
+ OS.EnableWindow (handle, isActive ());
+ }
+}
+
+@Override
+CREATESTRUCT widgetCreateStruct () {
+ return null;
+}
+
+@Override
+long widgetParent () {
+ if (handle != 0) return handle;
+ return parent != null ? parent.handle : 0;
+}
+
+@Override
+int widgetExtStyle () {
+ int bits = super.widgetExtStyle () & ~OS.WS_EX_MDICHILD;
+ if ((style & SWT.TOOL) != 0) bits |= OS.WS_EX_TOOLWINDOW;
+
+ /*
+ * Feature in Windows. When a window that does not have a parent
+ * is created, it is automatically added to the Windows Task Bar,
+ * even when it has no title. The fix is to use WS_EX_TOOLWINDOW
+ * which does not cause the window to appear in the Task Bar.
+ */
+ if (parent == null) {
+ if ((style & SWT.ON_TOP) != 0) {
+ int trim = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX;
+ if ((style & SWT.NO_TRIM) != 0 || (style & trim) == 0) {
+ bits |= OS.WS_EX_TOOLWINDOW;
+ }
+ }
+ }
+
+ if ((style & SWT.ON_TOP) != 0) bits |= OS.WS_EX_TOPMOST;
+ return bits;
+}
+
+@Override
+TCHAR windowClass () {
+ if ((style & SWT.TOOL) != 0) {
+ int trim = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX | SWT.BORDER | SWT.RESIZE;
+ if ((style & trim) == 0) return display.windowShadowClass;
+ }
+ return parent != null ? DialogClass : super.windowClass ();
+}
+
+@Override
+long windowProc () {
+ if (windowProc != 0) return windowProc;
+ if ((style & SWT.TOOL) != 0) {
+ int trim = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX | SWT.BORDER | SWT.RESIZE;
+ if ((style & trim) == 0) return super.windowProc ();
+ }
+ return parent != null ? DialogProc : super.windowProc ();
+}
+
+@Override
+long windowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ if((style & SWT.NO_MOVE) != 0 && msg == OS.WM_NCLBUTTONDOWN && wParam == OS.HTCAPTION) return 0;
+ if (hwnd == toolTipHandle || hwnd == balloonTipHandle || hwnd == menuItemToolTipHandle) {
+ switch (msg) {
+ case OS.WM_TIMER: {
+ if (wParam != ToolTip.TIMER_ID) break;
+ ToolTip tip = getCurrentToolTip (hwnd);
+ if (tip != null && tip.autoHide) {
+ tip.setVisible (false);
+ }
+ break;
+ }
+ case OS.WM_LBUTTONDOWN: {
+ ToolTip tip = getCurrentToolTip (hwnd);
+ if (tip != null) {
+ tip.setVisible (false);
+ tip.sendSelectionEvent (SWT.Selection);
+ }
+ break;
+ }
+ }
+ return callWindowProc (hwnd, msg, wParam, lParam);
+ }
+ if (hwnd == handle) {
+ if ((int)msg == Display.TASKBARBUTTONCREATED) {
+ if (display.taskBar != null) {
+ for (TaskItem item : display.taskBar.items) {
+ if (item != null && item.shell == this) {
+ item.recreate ();
+ break;
+ }
+ }
+ }
+ }
+ }
+ return super.windowProc (hwnd, msg, wParam, lParam);
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle ();
+ if (handle != 0) return bits | OS.WS_CHILD;
+ bits &= ~OS.WS_CHILD;
+
+ /*
+ * Use WS_OVERLAPPED for all windows, either dialog or top level
+ * so that CreateWindowEx () will respect CW_USEDEFAULT and set
+ * the default window location and size.
+ *
+ * NOTE: When a WS_OVERLAPPED window is created, Windows gives
+ * the new window WS_CAPTION style bits. These two constants are
+ * as follows:
+ *
+ * WS_OVERLAPPED = 0
+ * WS_CAPTION = WS_BORDER | WS_DLGFRAME
+ *
+ */
+ return bits | OS.WS_OVERLAPPED | OS.WS_CAPTION;
+}
+
+@Override
+LRESULT WM_ACTIVATE (long wParam, long lParam) {
+ /*
+ * Bug in Windows XP. When a Shell is deactivated, the
+ * IME composition window does not go away. This causes
+ * repaint issues. The fix is to commit the composition
+ * string.
+ */
+ if (OS.LOWORD (wParam) == 0 && OS.IsDBLocale && hIMC != 0) {
+ if (OS.ImmGetOpenStatus (hIMC)) {
+ OS.ImmNotifyIME (hIMC, OS.NI_COMPOSITIONSTR, OS.CPS_COMPLETE, 0);
+ }
+ }
+
+ /* Process WM_ACTIVATE */
+ LRESULT result = super.WM_ACTIVATE (wParam, lParam);
+ if (OS.LOWORD (wParam) == 0) {
+ if (lParam == 0 || (lParam != toolTipHandle && lParam != balloonTipHandle
+ && lParam != menuItemToolTipHandle)) {
+ ToolTip tip = getCurrentToolTip ();
+ if (tip != null) tip.setVisible (false);
+ }
+ }
+ return parent != null ? LRESULT.ZERO : result;
+}
+
+@Override
+LRESULT WM_DESTROY (long wParam, long lParam) {
+ LRESULT result = super.WM_DESTROY (wParam, lParam);
+ /*
+ * When the shell is a WS_CHILD window of a non-SWT
+ * window, the destroy code does not get called because
+ * the non-SWT window does not call dispose (). Instead,
+ * the destroy code is called here in WM_DESTROY.
+ */
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.WS_CHILD) != 0) {
+ releaseParent ();
+ release (false);
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_ERASEBKGND (long wParam, long lParam) {
+ LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. When a shell is resized by dragging
+ * the resize handles, Windows temporarily fills in black
+ * rectangles where the new contents of the shell should
+ * draw. The fix is to always draw the background of shells.
+ *
+ * NOTE: This only happens on Vista.
+ */
+ if (OS.WIN32_VERSION == OS.VERSION (6, 0)) {
+ drawBackground (wParam);
+ return LRESULT.ONE;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_ENTERIDLE (long wParam, long lParam) {
+ LRESULT result = super.WM_ENTERIDLE (wParam, lParam);
+ if (result != null) return result;
+ Display display = this.display;
+ if (display.runAsyncMessages (false)) display.wakeThread ();
+ return result;
+}
+
+@Override
+LRESULT WM_GETMINMAXINFO (long wParam, long lParam) {
+ LRESULT result = super.WM_GETMINMAXINFO (wParam, lParam);
+ if (result != null) return result;
+ if (minWidth != SWT.DEFAULT || minHeight != SWT.DEFAULT) {
+ MINMAXINFO info = new MINMAXINFO ();
+ OS.MoveMemory (info, lParam, MINMAXINFO.sizeof);
+ if (minWidth != SWT.DEFAULT) info.ptMinTrackSize_x = minWidth;
+ if (minHeight != SWT.DEFAULT) info.ptMinTrackSize_y = minHeight;
+ OS.MoveMemory (lParam, info, MINMAXINFO.sizeof);
+ return LRESULT.ZERO;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_MOUSEACTIVATE (long wParam, long lParam) {
+ LRESULT result = super.WM_MOUSEACTIVATE (wParam, lParam);
+ if (result != null) return result;
+
+ /*
+ * Check for WM_MOUSEACTIVATE when an MDI shell is active
+ * and stop the normal shell activation but allow the mouse
+ * down to be delivered.
+ */
+ int hittest = (short) OS.LOWORD (lParam);
+ switch (hittest) {
+ case OS.HTERROR:
+ case OS.HTTRANSPARENT:
+ case OS.HTNOWHERE:
+ break;
+ default: {
+ Control control = display._getFocusControl ();
+ if (control != null) {
+ Decorations decorations = control.menuShell ();
+ if (decorations.getShell () == this && decorations != this) {
+ display.ignoreRestoreFocus = true;
+ display.lastHittest = hittest;
+ display.lastHittestControl = null;
+ if (hittest == OS.HTMENU || hittest == OS.HTSYSMENU) {
+ display.lastHittestControl = control;
+ return null;
+ }
+ return new LRESULT (OS.MA_NOACTIVATE);
+ }
+ }
+ }
+ }
+ if (hittest == OS.HTMENU) return null;
+
+ /*
+ * Get the current location of the cursor,
+ * not the location of the cursor when the
+ * WM_MOUSEACTIVATE was generated. This is
+ * strictly incorrect but is necessary in
+ * order to support Activate and Deactivate
+ * events for embedded widgets that have
+ * their own event loop. In that case, the
+ * cursor location reported by GetMessagePos()
+ * is the one for our event loop, not the
+ * embedded widget's event loop.
+ */
+ POINT pt = new POINT ();
+ if (!OS.GetCursorPos (pt)) {
+ int pos = OS.GetMessagePos ();
+ OS.POINTSTOPOINT (pt, pos);
+ }
+ long hwnd = OS.WindowFromPoint (pt);
+ if (hwnd == 0) return null;
+ Control control = display.findControl (hwnd);
+
+ /*
+ * When a shell is created with SWT.ON_TOP and SWT.NO_FOCUS,
+ * do not activate the shell when the user clicks on the
+ * the client area or on the border or a control within the
+ * shell that does not take focus.
+ */
+ if (control != null && (control.state & CANVAS) != 0) {
+ if ((control.style & SWT.NO_FOCUS) != 0) {
+ int bits = SWT.ON_TOP | SWT.NO_FOCUS;
+ if ((style & bits) == bits) {
+ if (hittest == OS.HTBORDER || hittest == OS.HTCLIENT) {
+ return new LRESULT (OS.MA_NOACTIVATE);
+ }
+ }
+ }
+ }
+
+ long code = callWindowProc (handle, OS.WM_MOUSEACTIVATE, wParam, lParam);
+ setActiveControl (control, SWT.MouseDown);
+ return new LRESULT (code);
+}
+
+@Override
+LRESULT WM_MOVE (long wParam, long lParam) {
+ LRESULT result = super.WM_MOVE (wParam, lParam);
+ if (result != null) return result;
+ ToolTip tip = getCurrentToolTip ();
+ if (tip != null) tip.setVisible (false);
+ return result;
+}
+
+@Override
+LRESULT WM_NCHITTEST (long wParam, long lParam) {
+ if (!OS.IsWindowEnabled (handle)) return null;
+ if (!isEnabled () || !isActive ()) {
+ if (!Display.TrimEnabled) return new LRESULT (OS.HTNOWHERE);
+ long hittest = callWindowProc (handle, OS.WM_NCHITTEST, wParam, lParam);
+ if (hittest == OS.HTCLIENT || hittest == OS.HTMENU) hittest = OS.HTBORDER;
+ return new LRESULT (hittest);
+ }
+ if (menuBar != null && !menuBar.getEnabled ()) {
+ long hittest = callWindowProc (handle, OS.WM_NCHITTEST, wParam, lParam);
+ if (hittest == OS.HTMENU) hittest = OS.HTBORDER;
+ return new LRESULT (hittest);
+ }
+ return null;
+}
+
+@Override
+LRESULT WM_NCLBUTTONDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_NCLBUTTONDOWN (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * When the normal activation was interrupted in WM_MOUSEACTIVATE
+ * because the active shell was an MDI shell, set the active window
+ * to the top level shell but lock the active window and stop focus
+ * changes. This allows the user to interact the top level shell
+ * in the normal manner.
+ */
+ if (!display.ignoreRestoreFocus) return result;
+ Display display = this.display;
+ display.lockActiveWindow = true;
+ long code = callWindowProc (handle, OS.WM_NCLBUTTONDOWN, wParam, lParam);
+ display.lockActiveWindow = false;
+ Control focusControl = display.lastHittestControl;
+ if (focusControl != null && !focusControl.isDisposed ()) {
+ focusControl.setFocus ();
+ }
+ display.lastHittestControl = null;
+ display.ignoreRestoreFocus = false;
+ return new LRESULT (code);
+}
+
+@Override
+LRESULT WM_SETCURSOR (long wParam, long lParam) {
+ /*
+ * Feature in Windows. When the shell is disabled
+ * by a Windows standard dialog (like a MessageBox
+ * or FileDialog), clicking in the shell does not
+ * bring the shell or the dialog to the front. The
+ * fix is to detect this case and bring the shell
+ * forward.
+ */
+ int msg = OS.HIWORD (lParam);
+ if (msg == OS.WM_LBUTTONDOWN) {
+ if (!Display.TrimEnabled) {
+ Shell modalShell = display.getModalShell ();
+ if (modalShell != null && !isActive ()) {
+ long hwndModal = modalShell.handle;
+ if (OS.IsWindowEnabled (hwndModal)) {
+ OS.SetActiveWindow (hwndModal);
+ }
+ }
+ }
+ if (!OS.IsWindowEnabled (handle)) {
+ long hwndPopup = OS.GetLastActivePopup (handle);
+ if (hwndPopup != 0 && hwndPopup != handle) {
+ if (display.getControl (hwndPopup) == null) {
+ if (OS.IsWindowEnabled (hwndPopup)) {
+ OS.SetActiveWindow (hwndPopup);
+ }
+ }
+ }
+ }
+ }
+ /*
+ * When the shell that contains a cursor is disabled,
+ * WM_SETCURSOR is called with HTERROR. Normally,
+ * when a control is disabled, the parent will get
+ * mouse and cursor events. In the case of a disabled
+ * shell, there is no enabled parent. In order to
+ * show the cursor when a shell is disabled, it is
+ * necessary to override WM_SETCURSOR when called
+ * with HTERROR to set the cursor but only when the
+ * mouse is in the client area of the shell.
+ */
+ int hitTest = (short) OS.LOWORD (lParam);
+ if (hitTest == OS.HTERROR) {
+ if (!getEnabled ()) {
+ Control control = display.getControl (wParam);
+ if (control == this && cursor != null) {
+ POINT pt = new POINT ();
+ int pos = OS.GetMessagePos ();
+ OS.POINTSTOPOINT (pt, pos);
+ OS.ScreenToClient (handle, pt);
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ if (OS.PtInRect (rect, pt)) {
+ OS.SetCursor (cursor.handle);
+ switch (msg) {
+ case OS.WM_LBUTTONDOWN:
+ case OS.WM_RBUTTONDOWN:
+ case OS.WM_MBUTTONDOWN:
+ case OS.WM_XBUTTONDOWN:
+ OS.MessageBeep (OS.MB_OK);
+ }
+ return LRESULT.ONE;
+ }
+ }
+ }
+ }
+ return super.WM_SETCURSOR (wParam, lParam);
+}
+
+@Override
+LRESULT WM_SHOWWINDOW (long wParam, long lParam) {
+ LRESULT result = super.WM_SHOWWINDOW (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Bug in Windows. If the shell is hidden while the parent
+ * is iconic, Windows shows the shell when the parent is
+ * deiconified. This does not happen if the shell is hidden
+ * while the parent is not an icon. The fix is to track
+ * visible state for the shell and refuse to show the shell
+ * when the parent is shown.
+ */
+ if (lParam == OS.SW_PARENTOPENING) {
+ Control control = this;
+ while (control != null) {
+ Shell shell = control.getShell ();
+ if (!shell.showWithParent) return LRESULT.ZERO;
+ control = control.parent;
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_WINDOWPOSCHANGING (long wParam, long lParam) {
+ LRESULT result = super.WM_WINDOWPOSCHANGING (wParam,lParam);
+ if (result != null) return result;
+ WINDOWPOS lpwp = new WINDOWPOS ();
+ OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
+ if ((lpwp.flags & OS.SWP_NOSIZE) == 0) {
+ lpwp.cx = Math.max (lpwp.cx, minWidth);
+ int trim = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX;
+ if ((style & SWT.NO_TRIM) == 0 && (style & trim) != 0) {
+ lpwp.cx = Math.max (lpwp.cx, OS.GetSystemMetrics (OS.SM_CXMINTRACK));
+ }
+ lpwp.cy = Math.max (lpwp.cy, minHeight);
+ if ((style & SWT.NO_TRIM) == 0 && (style & trim) != 0) {
+ if ((style & SWT.RESIZE) != 0) {
+ lpwp.cy = Math.max (lpwp.cy, OS.GetSystemMetrics (OS.SM_CYMINTRACK));
+ } else {
+ RECT rect = new RECT ();
+ int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ int bits2 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
+ OS.AdjustWindowRectEx (rect, bits1, false, bits2);
+ lpwp.cy = Math.max (lpwp.cy, rect.bottom - rect.top);
+ }
+ }
+ OS.MoveMemory (lParam, lpwp, WINDOWPOS.sizeof);
+ }
+ return result;
+}
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Slider.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Slider.java
new file mode 100644
index 000000000..eece94732
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Slider.java
@@ -0,0 +1,803 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * Instances of this class are selectable user interface
+ * objects that represent a range of positive, numeric values.
+ *
+ *
+ * HORIZONTAL
+ * (which have a left facing button for decrementing the value and a
+ * right facing button for incrementing it) or VERTICAL
+ * (which have an upward facing button for decrementing the value
+ * and a downward facing buttons for incrementing it).
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#HORIZONTAL
+ * @see SWT#VERTICAL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Slider (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's value, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called, the event object detail field contains one of the following values:
+ * SWT.NONE
- for the end of a drag.
+ * SWT.DRAG
.
+ * SWT.HOME
.
+ * SWT.END
.
+ * SWT.ARROW_DOWN
.
+ * SWT.ARROW_UP
.
+ * SWT.PAGE_DOWN
.
+ * SWT.PAGE_UP
.
+ * widgetDefaultSelected
is not called.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ /*
+ * Feature in Windows. Windows runs a modal message
+ * loop when the user drags a scroll bar. This means
+ * that mouse down events won't get delivered until
+ * after the loop finishes. The fix is to run any
+ * deferred messages, including mouse down messages
+ * before calling the scroll bar window proc.
+ */
+ switch (msg) {
+ case OS.WM_LBUTTONDOWN:
+ case OS.WM_LBUTTONDBLCLK:
+ display.runDeferredEvents ();
+ }
+ return OS.CallWindowProc (ScrollBarProc, hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int border = getBorderWidthInPixels ();
+ int width = border * 2, height = border * 2;
+ if ((style & SWT.HORIZONTAL) != 0) {
+ width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10;
+ height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
+ } else {
+ width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
+ height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10;
+ }
+ if (wHint != SWT.DEFAULT) width = wHint + (border * 2);
+ if (hHint != SWT.DEFAULT) height = hHint + (border * 2);
+ return new Point (width, height);
+}
+
+@Override
+void createWidget () {
+ super.createWidget ();
+ increment = 1;
+ pageIncrement = 10;
+ /*
+ * Set the initial values of the maximum
+ * to 100 and the thumb to 10. Note that
+ * info.nPage needs to be 11 in order to
+ * get a thumb that is 10.
+ */
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_ALL;
+ info.nMax = 100;
+ info.nPage = 11;
+ OS.SetScrollInfo (handle, OS.SB_CTL, info, true);
+}
+
+@Override
+int defaultBackground () {
+ return OS.GetSysColor (OS.COLOR_SCROLLBAR);
+}
+
+@Override
+int defaultForeground () {
+ return OS.GetSysColor (OS.COLOR_BTNFACE);
+}
+
+@Override
+void enableWidget (boolean enabled) {
+ super.enableWidget (enabled);
+ int flags = enabled ? OS.ESB_ENABLE_BOTH : OS.ESB_DISABLE_BOTH;
+ OS.EnableScrollBar (handle, OS.SB_CTL, flags);
+ if (enabled) {
+ state &= ~DISABLED;
+ } else {
+ state |= DISABLED;
+ }
+}
+
+@Override
+public boolean getEnabled () {
+ checkWidget ();
+ return (state & DISABLED) == 0;
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed.
+ *
+ * @return the increment
+ *
+ * @exception SWTException
+ *
+ */
+public int getIncrement () {
+ checkWidget ();
+ return increment;
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMaximum () {
+ checkWidget ();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_RANGE;
+ OS.GetScrollInfo (handle, OS.SB_CTL, info);
+ return info.nMax;
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMinimum () {
+ checkWidget ();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_RANGE;
+ OS.GetScrollInfo (handle, OS.SB_CTL, info);
+ return info.nMin;
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected.
+ *
+ * @return the page increment
+ *
+ * @exception SWTException
+ *
+ */
+public int getPageIncrement () {
+ checkWidget ();
+ return pageIncrement;
+}
+
+/**
+ * Returns the 'selection', which is the receiver's value.
+ *
+ * @return the selection
+ *
+ * @exception SWTException
+ *
+ */
+public int getSelection () {
+ checkWidget ();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_POS;
+ OS.GetScrollInfo (handle, OS.SB_CTL, info);
+ return info.nPos;
+}
+
+/**
+ * Returns the receiver's thumb value.
+ *
+ * @return the thumb value
+ *
+ * @exception SWTException
+ *
+ */
+public int getThumb () {
+ checkWidget ();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_PAGE;
+ OS.GetScrollInfo (handle, OS.SB_CTL, info);
+ if (info.nPage != 0) --info.nPage;
+ return info.nPage;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's value.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+@Override
+void setBoundsInPixels (int x, int y, int width, int height, int flags) {
+ super.setBoundsInPixels (x, y, width, height, flags);
+ /*
+ * Bug in Windows. If the scroll bar is resized when it has focus,
+ * the flashing cursor that is used to show that the scroll bar has
+ * focus is not moved. The fix is to send a fake WM_SETFOCUS to
+ * get the scroll bar to recompute the size of the flashing cursor.
+ */
+ if (OS.GetFocus () == handle) {
+ ignoreFocus = true;
+ OS.SendMessage (handle, OS.WM_SETFOCUS, 0, 0);
+ ignoreFocus = false;
+ }
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the up/down (or right/left) arrows
+ * are pressed to the argument, which must be at least
+ * one.
+ *
+ * @param value the new increment (must be greater than zero)
+ *
+ * @exception SWTException
+ *
+ */
+public void setIncrement (int value) {
+ checkWidget ();
+ if (value < 1) return;
+ increment = value;
+}
+
+/**
+ * Sets the maximum. If this value is negative or less than or
+ * equal to the minimum, the value is ignored. If necessary, first
+ * the thumb and then the selection are adjusted to fit within the
+ * new range.
+ *
+ * @param value the new maximum, which must be greater than the current minimum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMaximum (int value) {
+ checkWidget ();
+ if (value < 0) return;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
+ OS.GetScrollInfo (handle, OS.SB_CTL, info);
+ if (value - info.nMin - info.nPage < 1) return;
+ info.nMax = value;
+ SetScrollInfo (handle, OS.SB_CTL, info, true);
+}
+
+/**
+ * Sets the minimum value. If this value is negative or greater
+ * than or equal to the maximum, the value is ignored. If necessary,
+ * first the thumb and then the selection are adjusted to fit within
+ * the new range.
+ *
+ * @param value the new minimum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMinimum (int value) {
+ checkWidget ();
+ if (value < 0) return;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
+ OS.GetScrollInfo (handle, OS.SB_CTL, info);
+ if (info.nMax - value - info.nPage < 1) return;
+ info.nMin = value;
+ SetScrollInfo (handle, OS.SB_CTL, info, true);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the page increment/decrement areas
+ * are selected to the argument, which must be at least
+ * one.
+ *
+ * @param value the page increment (must be greater than zero)
+ *
+ * @exception SWTException
+ *
+ */
+public void setPageIncrement (int value) {
+ checkWidget ();
+ if (value < 1) return;
+ pageIncrement = value;
+}
+
+boolean SetScrollInfo (long hwnd, int flags, SCROLLINFO info, boolean fRedraw) {
+ /*
+ * Feature in Windows. Using SIF_DISABLENOSCROLL,
+ * SetScrollInfo () can change enabled and disabled
+ * state of the scroll bar causing a scroll bar that
+ * was disabled by the application to become enabled.
+ * The fix is to disable the scroll bar (again) when
+ * the application has disabled the scroll bar.
+ */
+ if ((state & DISABLED) != 0) fRedraw = false;
+ boolean result = OS.SetScrollInfo (hwnd, flags, info, fRedraw);
+ if ((state & DISABLED) != 0) {
+ OS.EnableWindow (handle, false);
+ OS.EnableScrollBar (handle, OS.SB_CTL, OS.ESB_DISABLE_BOTH);
+ }
+
+ /*
+ * Bug in Windows. If the thumb is resized when it has focus,
+ * the flashing cursor that is used to show that the scroll bar
+ * has focus is not moved. The fix is to send a fake WM_SETFOCUS
+ * to get the scroll bar to recompute the size of the flashing
+ * cursor.
+ */
+ if (OS.GetFocus () == handle) {
+ ignoreFocus = true;
+ OS.SendMessage (handle, OS.WM_SETFOCUS, 0, 0);
+ ignoreFocus = false;
+ }
+ return result;
+}
+
+/**
+ * Sets the 'selection', which is the receiver's
+ * value, to the argument which must be greater than or equal
+ * to zero.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (int value) {
+ checkWidget ();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_POS;
+ info.nPos = value;
+ SetScrollInfo (handle, OS.SB_CTL, info, true);
+}
+
+/**
+ * Sets the thumb value. The thumb value should be used to represent
+ * the size of the visual portion of the current range. This value is
+ * usually the same as the page increment value.
+ *
+ *
+ */
+public void setThumb (int value) {
+ checkWidget ();
+ if (value < 1) return;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
+ OS.GetScrollInfo (handle, OS.SB_CTL, info);
+ info.nPage = value;
+ if (info.nPage != 0) info.nPage++;
+ SetScrollInfo (handle, OS.SB_CTL, info, true);
+}
+
+/**
+ * Sets the receiver's selection, minimum value, maximum
+ * value, thumb, increment and page increment all at once.
+ *
+ *
+ */
+public void setValues (int selection, int minimum, int maximum, int thumb, int increment, int pageIncrement) {
+ checkWidget ();
+ if (minimum < 0) return;
+ if (maximum < 0) return;
+ if (thumb < 1) return;
+ if (increment < 1) return;
+ if (pageIncrement < 1) return;
+ this.increment = increment;
+ this.pageIncrement = pageIncrement;
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_POS | OS.SIF_PAGE | OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
+ info.nPos = selection;
+ info.nMin = minimum;
+ info.nMax = maximum;
+ info.nPage = thumb;
+ if (info.nPage != 0) info.nPage++;
+ SetScrollInfo (handle, OS.SB_CTL, info, true);
+}
+
+@Override
+int widgetExtStyle () {
+ /*
+ * Bug in Windows. If a scroll bar control is given a border,
+ * dragging the scroll bar thumb eats away parts of the border
+ * while the thumb is dragged. The fix is to clear border for
+ * all scroll bars.
+ */
+ int bits = super.widgetExtStyle ();
+ if ((style & SWT.BORDER) != 0) bits &= ~OS.WS_EX_CLIENTEDGE;
+ return bits;
+}
+
+@Override
+int widgetStyle () {
+ int bits = super.widgetStyle () | OS.WS_TABSTOP;
+ /*
+ * Bug in Windows. If a scroll bar control is given a border,
+ * dragging the scroll bar thumb eats away parts of the border
+ * while the thumb is dragged. The fix is to clear WS_BORDER.
+ */
+ if ((style & SWT.BORDER) != 0) bits &= ~OS.WS_BORDER;
+ if ((style & SWT.HORIZONTAL) != 0) return bits | OS.SBS_HORZ;
+ return bits | OS.SBS_VERT;
+}
+
+@Override
+TCHAR windowClass () {
+ return ScrollBarClass;
+}
+
+@Override
+long windowProc () {
+ return ScrollBarProc;
+}
+
+@Override
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_KEYDOWN (wParam, lParam);
+ if (result != null) return result;
+ if ((style & SWT.VERTICAL) != 0) return result;
+ /*
+ * Bug in Windows. When a horizontal scroll bar is mirrored,
+ * the native control does not correctly swap the arrow keys.
+ * The fix is to swap them before calling the scroll bar window
+ * proc.
+ *
+ * NOTE: This fix is not ideal. It breaks when the bug is fixed
+ * in the operating system.
+ */
+ if ((style & SWT.MIRRORED) != 0) {
+ switch ((int)wParam) {
+ case OS.VK_LEFT:
+ case OS.VK_RIGHT: {
+ int key = wParam == OS.VK_LEFT ? OS.VK_RIGHT : OS.VK_LEFT;
+ long code = callWindowProc (handle, OS.WM_KEYDOWN, key, lParam);
+ return new LRESULT (code);
+ }
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONDBLCLK (long wParam, long lParam) {
+ /*
+ * Feature in Windows. Windows uses the WS_TABSTOP
+ * style for the scroll bar to decide that focus
+ * should be set during WM_LBUTTONDBLCLK. This is
+ * not the desired behavior. The fix is to clear
+ * and restore WS_TABSTOP so that Windows will not
+ * assign focus.
+ */
+ int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ int newBits = oldBits & ~OS.WS_TABSTOP;
+ OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
+ LRESULT result = super.WM_LBUTTONDBLCLK (wParam, lParam);
+ if (isDisposed ()) return LRESULT.ZERO;
+ OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits);
+ if (result == LRESULT.ZERO) return result;
+
+ /*
+ * Feature in Windows. Windows runs a modal message loop
+ * when the user drags a scroll bar that terminates when
+ * it sees an WM_LBUTTONUP. Unfortunately the WM_LBUTTONUP
+ * is consumed. The fix is to send a fake mouse up and
+ * release the automatic capture.
+ */
+ if (OS.GetCapture () == handle) OS.ReleaseCapture ();
+ if (!sendMouseEvent (SWT.MouseUp, 1, handle, OS.WM_LBUTTONUP, wParam, lParam)) {
+ return LRESULT.ZERO;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
+ /*
+ * Feature in Windows. Windows uses the WS_TABSTOP
+ * style for the scroll bar to decide that focus
+ * should be set during WM_LBUTTONDOWN. This is
+ * not the desired behavior. The fix is to clear
+ * and restore WS_TABSTOP so that Windows will not
+ * assign focus.
+ */
+ int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ int newBits = oldBits & ~OS.WS_TABSTOP;
+ OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
+ LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
+ if (isDisposed ()) return LRESULT.ZERO;
+ OS.SetWindowLong (handle, OS.GWL_STYLE, oldBits);
+ if (result == LRESULT.ZERO) return result;
+
+ /*
+ * Feature in Windows. Windows runs a modal message loop
+ * when the user drags a scroll bar that terminates when
+ * it sees an WM_LBUTTONUP. Unfortunately the WM_LBUTTONUP
+ * is consumed. The fix is to send a fake mouse up and
+ * release the automatic capture.
+ */
+ if (OS.GetCapture () == handle) OS.ReleaseCapture ();
+ if (!sendMouseEvent (SWT.MouseUp, 1, handle, OS.WM_LBUTTONUP, wParam, lParam)) {
+ return LRESULT.ONE;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_SETFOCUS (long wParam, long lParam) {
+ if (ignoreFocus) return null;
+ return super.WM_SETFOCUS (wParam, lParam);
+}
+
+@Override
+LRESULT wmScrollChild (long wParam, long lParam) {
+
+ /* Do nothing when scrolling is ending */
+ int code = OS.LOWORD (wParam);
+ if (code == OS.SB_ENDSCROLL) return null;
+
+ /* Move the thumb */
+ Event event = new Event ();
+ SCROLLINFO info = new SCROLLINFO ();
+ info.cbSize = SCROLLINFO.sizeof;
+ info.fMask = OS.SIF_TRACKPOS | OS.SIF_POS | OS.SIF_RANGE;
+ OS.GetScrollInfo (handle, OS.SB_CTL, info);
+ info.fMask = OS.SIF_POS;
+ switch (code) {
+ case OS.SB_THUMBPOSITION:
+ event.detail = SWT.NONE;
+ info.nPos = info.nTrackPos;
+ break;
+ case OS.SB_THUMBTRACK:
+ event.detail = SWT.DRAG;
+ info.nPos = info.nTrackPos;
+ break;
+ case OS.SB_TOP:
+ event.detail = SWT.HOME;
+ info.nPos = info.nMin;
+ break;
+ case OS.SB_BOTTOM:
+ event.detail = SWT.END;
+ info.nPos = info.nMax;
+ break;
+ case OS.SB_LINEDOWN:
+ event.detail = SWT.ARROW_DOWN;
+ info.nPos += increment;
+ break;
+ case OS.SB_LINEUP:
+ event.detail = SWT.ARROW_UP;
+ info.nPos = Math.max (info.nMin, info.nPos - increment);
+ break;
+ case OS.SB_PAGEDOWN:
+ event.detail = SWT.PAGE_DOWN;
+ info.nPos += pageIncrement;
+ break;
+ case OS.SB_PAGEUP:
+ event.detail = SWT.PAGE_UP;
+ info.nPos = Math.max (info.nMin, info.nPos - pageIncrement);
+ break;
+ }
+ OS.SetScrollInfo (handle, OS.SB_CTL, info, true);
+
+ /*
+ * Feature in Windows. Windows runs a modal message
+ * loop when the user drags a scroll bar. This means
+ * that selection event must be sent because WM_HSCROLL
+ * and WM_VSCROLL are sent from the modal message loop
+ * so that they are delivered during inside the loop.
+ */
+ sendSelectionEvent (SWT.Selection, event, true);
+ // the widget could be destroyed at this point
+ return null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Spinner.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Spinner.java
new file mode 100644
index 000000000..ba046b9e1
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Spinner.java
@@ -0,0 +1,1487 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class are selectable user interface
+ * objects that allow the user to enter and modify numeric
+ * values.
+ * Composite
,
+ * it does not make sense to add children to it, or set a layout on it.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#READ_ONLY
+ * @see SWT#WRAP
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Spinner (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ if (hwnd == hwndText) {
+ return OS.CallWindowProc (EditProc, hwnd, msg, wParam, lParam);
+ }
+ if (hwnd == hwndUpDown) {
+ return OS.CallWindowProc (UpDownProc, hwnd, msg, wParam, lParam);
+ }
+ return OS.DefWindowProc (handle, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
+}
+
+@Override
+boolean checkHandle (long hwnd) {
+ return hwnd == handle || hwnd == hwndText || hwnd == hwndUpDown;
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state &= ~(CANVAS | THEME_BACKGROUND);
+ long hInstance = OS.GetModuleHandle (null);
+ int textExStyle = (style & SWT.BORDER) != 0 ? OS.WS_EX_CLIENTEDGE : 0;
+ int textStyle = OS.WS_CHILD | OS.WS_VISIBLE | OS.ES_AUTOHSCROLL | OS.WS_CLIPSIBLINGS;
+ if ((style & SWT.READ_ONLY) != 0) textStyle |= OS.ES_READONLY;
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) textExStyle |= OS.WS_EX_LAYOUTRTL;
+ hwndText = OS.CreateWindowEx (
+ textExStyle,
+ EditClass,
+ null,
+ textStyle,
+ 0, 0, 0, 0,
+ handle,
+ 0,
+ hInstance,
+ null);
+ if (hwndText == 0) error (SWT.ERROR_NO_HANDLES);
+ OS.SetWindowLongPtr (hwndText, OS.GWLP_ID, hwndText);
+ int upDownStyle = OS.WS_CHILD | OS.WS_VISIBLE | OS.UDS_AUTOBUDDY;
+ if ((style & SWT.WRAP) != 0) upDownStyle |= OS.UDS_WRAP;
+ if ((style & SWT.BORDER) != 0) {
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ upDownStyle |= OS.UDS_ALIGNLEFT;
+ } else {
+ upDownStyle |= OS.UDS_ALIGNRIGHT;
+ }
+ }
+ hwndUpDown = OS.CreateWindowEx (
+ 0,
+ UpDownClass,
+ null,
+ upDownStyle,
+ 0, 0, 0, 0,
+ handle,
+ 0,
+ hInstance,
+ null);
+ if (hwndUpDown == 0) error (SWT.ERROR_NO_HANDLES);
+ int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (hwndText, hwndUpDown, 0, 0, 0, 0, flags);
+ OS.SetWindowLongPtr (hwndUpDown, OS.GWLP_ID, hwndUpDown);
+ if (OS.IsDBLocale) {
+ long hIMC = OS.ImmGetContext (handle);
+ OS.ImmAssociateContext (hwndText, hIMC);
+ OS.ImmAssociateContext (hwndUpDown, hIMC);
+ OS.ImmReleaseContext (handle, hIMC);
+ }
+ OS.SendMessage (hwndUpDown, OS.UDM_SETRANGE32, 0, 100);
+ OS.SendMessage (hwndUpDown, OS.UDM_SETPOS32, 0, 0);
+ pageIncrement = 10;
+ digits = 0;
+ OS.SetWindowText (hwndText, new char [] {'0', '\0'});
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is modified, by sending
+ * it one of the messages defined in the ModifyListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ModifyListener
+ * @see #removeModifyListener
+ */
+public void addModifyListener (ModifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Modify, typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the control is selected by the user, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is not called for texts.
+ * widgetDefaultSelected
is typically called when ENTER is pressed in a single-line text.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is verified, by sending
+ * it one of the messages defined in the VerifyListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see VerifyListener
+ * @see #removeVerifyListener
+ */
+void addVerifyListener (VerifyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Verify, typedListener);
+}
+
+@Override
+long borderHandle () {
+ return hwndText;
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ int width = 0, height = 0;
+ if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
+ long newFont, oldFont = 0;
+ long hDC = OS.GetDC (hwndText);
+ newFont = OS.SendMessage (hwndText, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ TEXTMETRIC tm = new TEXTMETRIC ();
+ OS.GetTextMetrics (hDC, tm);
+ height = tm.tmHeight;
+ RECT rect = new RECT ();
+ int [] max = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, null, max);
+ String string = String.valueOf (max [0]);
+ if (digits > 0) {
+ StringBuilder buffer = new StringBuilder ();
+ buffer.append (string);
+ buffer.append (getDecimalSeparator ());
+ int count = digits - string.length ();
+ while (count >= 0) {
+ buffer.append ("0");
+ count--;
+ }
+ string = buffer.toString ();
+ }
+ char [] buffer = string.toCharArray ();
+ int flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_NOPREFIX;
+ OS.DrawText (hDC, buffer, buffer.length, rect, flags);
+ width = rect.right - rect.left;
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (hwndText, hDC);
+ }
+ if (width == 0) width = DEFAULT_WIDTH;
+ if (height == 0) height = DEFAULT_HEIGHT;
+ if (wHint != SWT.DEFAULT) width = wHint;
+ if (hHint != SWT.DEFAULT) height = hHint;
+ Rectangle trim = computeTrimInPixels (0, 0, width, height);
+ if (hHint == SWT.DEFAULT) {
+ int upDownHeight = OS.GetSystemMetrics (OS.SM_CYVSCROLL) + 2 * getBorderWidthInPixels ();
+ upDownHeight += (style & SWT.BORDER) != 0 ? 1 : 3;
+ trim.height = Math.max (trim.height, upDownHeight);
+ }
+ return new Point (trim.width, trim.height);
+}
+
+@Override Rectangle computeTrimInPixels (int x, int y, int width, int height) {
+ checkWidget ();
+
+ /* Get the trim of the text control */
+ RECT rect = new RECT ();
+ OS.SetRect (rect, x, y, x + width, y + height);
+ int bits0 = OS.GetWindowLong (hwndText, OS.GWL_STYLE);
+ int bits1 = OS.GetWindowLong (hwndText, OS.GWL_EXSTYLE);
+ OS.AdjustWindowRectEx (rect, bits0, false, bits1);
+ width = rect.right - rect.left;
+ height = rect.bottom - rect.top;
+
+ /*
+ * The preferred height of a single-line text widget
+ * has been hand-crafted to be the same height as
+ * the single-line text widget in an editable combo
+ * box.
+ */
+ long margins = OS.SendMessage (hwndText, OS.EM_GETMARGINS, 0, 0);
+ x -= OS.LOWORD (margins);
+ width += OS.LOWORD (margins) + OS.HIWORD (margins);
+ if ((style & SWT.BORDER) != 0) {
+ x -= 1;
+ y -= 1;
+ width += 2;
+ height += 2;
+ }
+ width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
+ return new Rectangle (x, y, width, height);
+}
+
+/**
+ * Copies the selected text.
+ *
+ *
+ */
+public void copy () {
+ checkWidget ();
+ OS.SendMessage (hwndText, OS.WM_COPY, 0, 0);
+}
+
+/**
+ * Cuts the selected text.
+ *
+ *
+ */
+public void cut () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ OS.SendMessage (hwndText, OS.WM_CUT, 0, 0);
+}
+
+@Override
+int defaultBackground () {
+ return OS.GetSysColor (OS.COLOR_WINDOW);
+}
+
+@Override
+void enableWidget (boolean enabled) {
+ super.enableWidget (enabled);
+ OS.EnableWindow (hwndText, enabled);
+ OS.EnableWindow (hwndUpDown, enabled);
+}
+
+@Override
+void deregister () {
+ super.deregister ();
+ display.removeControl (hwndText);
+ display.removeControl (hwndUpDown);
+}
+
+@Override
+boolean hasFocus () {
+ long hwndFocus = OS.GetFocus ();
+ if (hwndFocus == handle) return true;
+ if (hwndFocus == hwndText) return true;
+ if (hwndFocus == hwndUpDown) return true;
+ return false;
+}
+
+/**
+ * Returns the number of decimal places used by the receiver.
+ *
+ * @return the digits
+ *
+ * @exception SWTException
+ *
+ */
+public int getDigits () {
+ checkWidget ();
+ return digits;
+}
+
+String getDecimalSeparator () {
+ char [] data = new char [4];
+ int size = OS.GetLocaleInfo (OS.LOCALE_USER_DEFAULT, OS.LOCALE_SDECIMAL, data, 4);
+ return size != 0 ? new String (data, 0, size - 1) : ".";
+}
+
+/**
+ * Returns the amount that the receiver's value will be
+ * modified by when the up/down arrows are pressed.
+ *
+ * @return the increment
+ *
+ * @exception SWTException
+ *
+ */
+public int getIncrement () {
+ checkWidget ();
+ UDACCEL udaccel = new UDACCEL ();
+ OS.SendMessage (hwndUpDown, OS.UDM_GETACCEL, 1, udaccel);
+ return udaccel.nInc;
+}
+
+/**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMaximum () {
+ checkWidget ();
+ int [] max = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, null, max);
+ return max [0];
+}
+
+/**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException
+ *
+ */
+public int getMinimum () {
+ checkWidget ();
+ int [] min = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, min, null);
+ return min [0];
+}
+
+/**
+ * Returns the amount that the receiver's position will be
+ * modified by when the page up/down keys are pressed.
+ *
+ * @return the page increment
+ *
+ * @exception SWTException
+ *
+ */
+public int getPageIncrement () {
+ checkWidget ();
+ return pageIncrement;
+}
+
+/**
+ * Returns the selection, which is the receiver's position.
+ *
+ * @return the selection
+ *
+ * @exception SWTException
+ *
+ */
+public int getSelection () {
+ checkWidget ();
+ return (int)OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
+}
+
+int getSelectionText (boolean [] parseFail) {
+ int length = OS.GetWindowTextLength (hwndText);
+ char [] buffer = new char [length + 1];
+ OS.GetWindowText (hwndText, buffer, length + 1);
+ String string = new String (buffer, 0, length);
+ try {
+ int value;
+ if (digits > 0) {
+ String decimalSeparator = getDecimalSeparator ();
+ int index = string.indexOf (decimalSeparator);
+ if (index != -1) {
+ int startIndex = string.startsWith ("+") || string.startsWith ("-") ? 1 : 0;
+ String wholePart = startIndex != index ? string.substring (startIndex, index) : "0";
+ String decimalPart = string.substring (index + 1);
+ if (decimalPart.length () > digits) {
+ decimalPart = decimalPart.substring (0, digits);
+ } else {
+ int i = digits - decimalPart.length ();
+ for (int j = 0; j < i; j++) {
+ decimalPart = decimalPart + "0";
+ }
+ }
+ int wholeValue = Integer.parseInt (wholePart);
+ int decimalValue = Integer.parseInt (decimalPart);
+ for (int i = 0; i < digits; i++) wholeValue *= 10;
+ value = wholeValue + decimalValue;
+ if (string.startsWith ("-")) value = -value;
+ } else {
+ value = Integer.parseInt (string);
+ for (int i = 0; i < digits; i++) value *= 10;
+ }
+ } else {
+ value = Integer.parseInt (string);
+ }
+ int [] max = new int [1], min = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, min, max);
+ if (min [0] <= value && value <= max [0]) return value;
+ } catch (NumberFormatException e) {
+ }
+ parseFail [0] = true;
+ return -1;
+}
+
+/**
+ * Returns a string containing a copy of the contents of the
+ * receiver's text field, or an empty string if there are no
+ * contents.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public String getText () {
+ checkWidget ();
+ int length = OS.GetWindowTextLength (hwndText);
+ if (length == 0) return "";
+ char [] buffer = new char [length + 1];
+ OS.GetWindowText (hwndText, buffer, length + 1);
+ return new String (buffer, 0, length);
+}
+
+/**
+ * Returns the maximum number of characters that the receiver's
+ * text field is capable of holding. If this has not been changed
+ * by setTextLimit()
, it will be the constant
+ * Spinner.LIMIT
.
+ *
+ * @return the text limit
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #LIMIT
+ *
+ * @since 3.4
+ */
+public int getTextLimit () {
+ checkWidget ();
+ return (int)OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
+}
+
+/**
+ * Pastes text from clipboard.
+ *
+ *
+ */
+public void paste () {
+ checkWidget ();
+ if ((style & SWT.READ_ONLY) != 0) return;
+ OS.SendMessage (hwndText, OS.WM_PASTE, 0, 0);
+}
+
+@Override
+void register () {
+ super.register ();
+ display.addControl (hwndText, this);
+ display.addControl (hwndUpDown, this);
+}
+
+@Override
+void releaseHandle () {
+ super.releaseHandle ();
+ hwndText = hwndUpDown = 0;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver's text is modified.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see ModifyListener
+ * @see #addModifyListener
+ */
+public void removeModifyListener (ModifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Modify, listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is verified.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see VerifyListener
+ * @see #addVerifyListener
+ */
+void removeVerifyListener (VerifyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Verify, listener);
+}
+
+@Override
+boolean sendKeyEvent (int type, int msg, long wParam, long lParam, Event event) {
+ if (!super.sendKeyEvent (type, msg, wParam, lParam, event)) {
+ return false;
+ }
+ if ((style & SWT.READ_ONLY) != 0) return true;
+ if (type != SWT.KeyDown) return true;
+ if (msg != OS.WM_CHAR && msg != OS.WM_KEYDOWN && msg != OS.WM_IME_CHAR) {
+ return true;
+ }
+ if (event.character == 0) return true;
+// if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return true;
+ char key = event.character;
+ int stateMask = event.stateMask;
+
+ /*
+ * Disable all magic keys that could modify the text
+ * and don't send events when Alt, Shift or Ctrl is
+ * pressed.
+ */
+ switch (msg) {
+ case OS.WM_CHAR:
+ if (key != 0x08 && key != 0x7F && key != '\r' && key != '\t' && key != '\n') break;
+ // FALL THROUGH
+ case OS.WM_KEYDOWN:
+ if ((stateMask & (SWT.ALT | SWT.SHIFT | SWT.CONTROL)) != 0) return false;
+ break;
+ }
+
+ /*
+ * If the left button is down, the text widget refuses the character.
+ */
+ if (OS.GetKeyState (OS.VK_LBUTTON) < 0) {
+ return true;
+ }
+
+ /* Verify the character */
+ String oldText = "";
+ int [] start = new int [1], end = new int [1];
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ switch (key) {
+ case 0x08: /* Bs */
+ if (start [0] == end [0]) {
+ if (start [0] == 0) return true;
+ start [0] = start [0] - 1;
+ start [0] = Math.max (start [0], 0);
+ }
+ break;
+ case 0x7F: /* Del */
+ if (start [0] == end [0]) {
+ int length = OS.GetWindowTextLength (hwndText);
+ if (start [0] == length) return true;
+ end [0] = end [0] + 1;
+ end [0] = Math.min (end [0], length);
+ }
+ break;
+ case '\r': /* Return */
+ return true;
+ default: /* Tab and other characters */
+ if (key != '\t' && key < 0x20) return true;
+ oldText = new String (new char [] {key});
+ break;
+ }
+ String newText = verifyText (oldText, start [0], end [0], event);
+ if (newText == null) return false;
+ if (newText == oldText) return true;
+ TCHAR buffer = new TCHAR (getCodePage (), newText, true);
+ OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], end [0]);
+ OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, buffer);
+ return false;
+}
+
+@Override
+void setBackgroundImage (long hBitmap) {
+ super.setBackgroundImage (hBitmap);
+ OS.InvalidateRect (hwndText, null, true);
+}
+
+@Override
+void setBackgroundPixel (int pixel) {
+ super.setBackgroundPixel (pixel);
+ OS.InvalidateRect (hwndText, null, true);
+}
+
+/**
+ * Sets the number of decimal places used by the receiver.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setDigits (int value) {
+ checkWidget ();
+ if (value < 0) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (value == this.digits) return;
+ this.digits = value;
+ int pos = (int)OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
+ setSelection (pos, false, true, false);
+}
+
+@Override
+void setForegroundPixel (int pixel) {
+ super.setForegroundPixel (pixel);
+ OS.InvalidateRect (hwndText, null, true);
+}
+
+/**
+ * Sets the amount that the receiver's value will be
+ * modified by when the up/down arrows are pressed to
+ * the argument, which must be at least one.
+ *
+ * @param value the new increment (must be greater than zero)
+ *
+ * @exception SWTException
+ *
+ */
+public void setIncrement (int value) {
+ checkWidget ();
+ if (value < 1) return;
+ long hHeap = OS.GetProcessHeap ();
+ int count = (int)OS.SendMessage (hwndUpDown, OS.UDM_GETACCEL, 0, (UDACCEL)null);
+ long udaccels = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, UDACCEL.sizeof * count);
+ OS.SendMessage (hwndUpDown, OS.UDM_GETACCEL, count, udaccels);
+ int first = -1;
+ UDACCEL udaccel = new UDACCEL ();
+ for (int i = 0; i < count; i++) {
+ long offset = udaccels + (i * UDACCEL.sizeof);
+ OS.MoveMemory (udaccel, offset, UDACCEL.sizeof);
+ if (first == -1) first = udaccel.nInc;
+ udaccel.nInc = udaccel.nInc / first * value;
+ OS.MoveMemory (offset, udaccel, UDACCEL.sizeof);
+ }
+ OS.SendMessage (hwndUpDown, OS.UDM_SETACCEL, count, udaccels);
+ OS.HeapFree (hHeap, 0, udaccels);
+}
+
+/**
+ * Sets the maximum value that the receiver will allow. This new
+ * value will be ignored if it is less than the receiver's current
+ * minimum value. If the new maximum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new maximum, which must be greater than or equal to the current minimum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMaximum (int value) {
+ checkWidget ();
+ int [] min = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, min, null);
+ if (value < min [0]) return;
+ int pos = (int)OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
+ OS.SendMessage (hwndUpDown , OS.UDM_SETRANGE32, min [0], value);
+ if (pos > value) setSelection (value, true, true, false);
+}
+
+/**
+ * Sets the minimum value that the receiver will allow. This new
+ * value will be ignored if it is greater than the receiver's
+ * current maximum value. If the new minimum is applied then the receiver's
+ * selection value will be adjusted if necessary to fall within its new range.
+ *
+ * @param value the new minimum, which must be less than or equal to the current maximum
+ *
+ * @exception SWTException
+ *
+ */
+public void setMinimum (int value) {
+ checkWidget ();
+ int [] max = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, null, max);
+ if (value > max [0]) return;
+ int pos = (int)OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
+ OS.SendMessage (hwndUpDown , OS.UDM_SETRANGE32, value, max [0]);
+ if (pos < value) setSelection (value, true, true, false);
+}
+
+/**
+ * Sets the amount that the receiver's position will be
+ * modified by when the page up/down keys are pressed
+ * to the argument, which must be at least one.
+ *
+ * @param value the page increment (must be greater than zero)
+ *
+ * @exception SWTException
+ *
+ */
+public void setPageIncrement (int value) {
+ checkWidget ();
+ if (value < 1) return;
+ pageIncrement = value;
+}
+
+/**
+ * Sets the selection, which is the receiver's
+ * position, to the argument. If the argument is not within
+ * the range specified by minimum and maximum, it will be
+ * adjusted to fall within this range.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (int value) {
+ checkWidget ();
+ int [] max = new int [1], min = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, min, max);
+ value = Math.min (Math.max (min [0], value), max [0]);
+ setSelection (value, true, true, false);
+}
+
+void setSelection (int value, boolean setPos, boolean setText, boolean notify) {
+ if (setPos) {
+ OS.SendMessage (hwndUpDown, OS.UDM_SETPOS32, 0, value);
+ }
+ if (setText) {
+ String string;
+ if (digits == 0) {
+ string = String.valueOf (value);
+ } else {
+ string = String.valueOf (Math.abs (value));
+ String decimalSeparator = getDecimalSeparator ();
+ int index = string.length () - digits;
+ StringBuilder buffer = new StringBuilder ();
+ if (value < 0) buffer.append ("-");
+ if (index > 0) {
+ buffer.append (string.substring (0, index));
+ buffer.append (decimalSeparator);
+ buffer.append (string.substring (index));
+ } else {
+ buffer.append ("0");
+ buffer.append (decimalSeparator);
+ while (index++ < 0) buffer.append ("0");
+ buffer.append (string);
+ }
+ string = buffer.toString ();
+ }
+ if (hooks (SWT.Verify) || filters (SWT.Verify)) {
+ int length = OS.GetWindowTextLength (hwndText);
+ string = verifyText (string, 0, length, null);
+ if (string == null) return;
+ }
+ TCHAR buffer = new TCHAR (getCodePage (), string, true);
+ OS.SetWindowText (hwndText, buffer);
+ OS.SendMessage (hwndText, OS.EM_SETSEL, 0, -1);
+ OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, hwndText, OS.OBJID_CLIENT, 0);
+ }
+ if (notify) sendSelectionEvent (SWT.Selection);
+}
+
+/**
+ * Sets the maximum number of characters that the receiver's
+ * text field is capable of holding to be the argument.
+ * setTextLimit(Spinner.LIMIT)
.
+ * Specifying a limit value larger than Spinner.LIMIT
sets the
+ * receiver's limit to Spinner.LIMIT
.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #LIMIT
+ *
+ * @since 3.4
+ */
+public void setTextLimit (int limit) {
+ checkWidget ();
+ if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO);
+ OS.SendMessage (hwndText, OS.EM_SETLIMITTEXT, limit, 0);
+}
+
+@Override
+void setToolTipText (Shell shell, String string) {
+ shell.setToolTipText (hwndText, string);
+ shell.setToolTipText (hwndUpDown, string);
+}
+
+/**
+ * Sets the receiver's selection, minimum value, maximum
+ * value, digits, increment and page increment all at once.
+ *
+ *
+ *
+ * @since 3.2
+ */
+public void setValues (int selection, int minimum, int maximum, int digits, int increment, int pageIncrement) {
+ checkWidget ();
+ if (maximum < minimum) return;
+ if (digits < 0) return;
+ if (increment < 1) return;
+ if (pageIncrement < 1) return;
+ selection = Math.min (Math.max (minimum, selection), maximum);
+ setIncrement (increment);
+ this.pageIncrement = pageIncrement;
+ this.digits = digits;
+ OS.SendMessage (hwndUpDown , OS.UDM_SETRANGE32, minimum, maximum);
+ setSelection (selection, true, true, false);
+}
+
+@Override
+void subclass () {
+ super.subclass ();
+ long newProc = display.windowProc;
+ OS.SetWindowLongPtr (hwndText, OS.GWLP_WNDPROC, newProc);
+ OS.SetWindowLongPtr (hwndUpDown, OS.GWLP_WNDPROC, newProc);
+}
+
+@Override
+void unsubclass () {
+ super.unsubclass ();
+ OS.SetWindowLongPtr (hwndText, OS.GWLP_WNDPROC, EditProc);
+ OS.SetWindowLongPtr (hwndUpDown, OS.GWLP_WNDPROC, UpDownProc);
+}
+
+@Override
+void updateOrientation () {
+ super.updateOrientation ();
+ int bits = OS.GetWindowLong (hwndText, OS.GWL_EXSTYLE);
+ int bits1 = OS.GetWindowLong (hwndText, OS.GWL_STYLE);
+ if ((style & SWT.RIGHT_TO_LEFT) != 0){
+ bits |= OS.WS_EX_RIGHT;
+ bits1 |= OS.ES_RIGHT;
+ }
+ else{
+ bits &= ~OS.WS_EX_RIGHT;
+ bits1 &= ~OS.ES_RIGHT;
+ }
+ OS.SetWindowLong (hwndText, OS.GWL_STYLE, bits1);
+ OS.SetWindowLong (hwndText, OS.GWL_EXSTYLE, bits);
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ int width = rect.right - rect.left, height = rect.bottom - rect.top;
+ OS.SetWindowPos (handle, 0, 0, 0, width - 1, height - 1, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
+ OS.SetWindowPos (handle, 0, 0, 0, width, height, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
+}
+
+String verifyText (String string, int start, int end, Event keyEvent) {
+ Event event = new Event ();
+ event.text = string;
+ event.start = start;
+ event.end = end;
+ if (keyEvent != null) {
+ event.character = keyEvent.character;
+ event.keyCode = keyEvent.keyCode;
+ event.stateMask = keyEvent.stateMask;
+ }
+ int index = 0;
+ if (digits > 0) {
+ String decimalSeparator = getDecimalSeparator ();
+ index = string.indexOf (decimalSeparator);
+ if (index != -1) {
+ string = string.substring (0, index) + string.substring (index + 1);
+ }
+ index = 0;
+ }
+ if (string.length() > 0) {
+ int [] min = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, min, null);
+ if (min [0] < 0 && string.charAt (0) == '-') index++;
+ }
+ while (index < string.length ()) {
+ if (!Character.isDigit (string.charAt (index))) break;
+ index++;
+ }
+ event.doit = index == string.length ();
+ sendEvent (SWT.Verify, event);
+ if (!event.doit || isDisposed ()) return null;
+ return event.text;
+}
+
+@Override
+int widgetExtStyle () {
+ return super.widgetExtStyle () & ~OS.WS_EX_CLIENTEDGE;
+}
+
+@Override
+long windowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (hwnd == hwndText || hwnd == hwndUpDown) {
+ LRESULT result = null;
+ switch (msg) {
+ /* Keyboard messages */
+ case OS.WM_CHAR: result = wmChar (hwnd, wParam, lParam); break;
+ case OS.WM_IME_CHAR: result = wmIMEChar (hwnd, wParam, lParam); break;
+ case OS.WM_KEYDOWN: result = wmKeyDown (hwnd, wParam, lParam); break;
+ case OS.WM_KEYUP: result = wmKeyUp (hwnd, wParam, lParam); break;
+ case OS.WM_SYSCHAR: result = wmSysChar (hwnd, wParam, lParam); break;
+ case OS.WM_SYSKEYDOWN: result = wmSysKeyDown (hwnd, wParam, lParam); break;
+ case OS.WM_SYSKEYUP: result = wmSysKeyUp (hwnd, wParam, lParam); break;
+
+ /* Mouse Messages */
+ case OS.WM_CAPTURECHANGED: result = wmCaptureChanged (hwnd, wParam, lParam); break;
+ case OS.WM_LBUTTONDBLCLK: result = wmLButtonDblClk (hwnd, wParam, lParam); break;
+ case OS.WM_LBUTTONDOWN: result = wmLButtonDown (hwnd, wParam, lParam); break;
+ case OS.WM_LBUTTONUP: result = wmLButtonUp (hwnd, wParam, lParam); break;
+ case OS.WM_MBUTTONDBLCLK: result = wmMButtonDblClk (hwnd, wParam, lParam); break;
+ case OS.WM_MBUTTONDOWN: result = wmMButtonDown (hwnd, wParam, lParam); break;
+ case OS.WM_MBUTTONUP: result = wmMButtonUp (hwnd, wParam, lParam); break;
+ case OS.WM_MOUSEHOVER: result = wmMouseHover (hwnd, wParam, lParam); break;
+ case OS.WM_MOUSELEAVE: result = wmMouseLeave (hwnd, wParam, lParam); break;
+ case OS.WM_MOUSEMOVE: result = wmMouseMove (hwnd, wParam, lParam); break;
+// case OS.WM_MOUSEWHEEL: result = wmMouseWheel (hwnd, wParam, lParam); break;
+ case OS.WM_RBUTTONDBLCLK: result = wmRButtonDblClk (hwnd, wParam, lParam); break;
+ case OS.WM_RBUTTONDOWN: result = wmRButtonDown (hwnd, wParam, lParam); break;
+ case OS.WM_RBUTTONUP: result = wmRButtonUp (hwnd, wParam, lParam); break;
+ case OS.WM_XBUTTONDBLCLK: result = wmXButtonDblClk (hwnd, wParam, lParam); break;
+ case OS.WM_XBUTTONDOWN: result = wmXButtonDown (hwnd, wParam, lParam); break;
+ case OS.WM_XBUTTONUP: result = wmXButtonUp (hwnd, wParam, lParam); break;
+
+ /* Focus Messages */
+ case OS.WM_SETFOCUS: result = wmSetFocus (hwnd, wParam, lParam); break;
+ case OS.WM_KILLFOCUS: result = wmKillFocus (hwnd, wParam, lParam); break;
+
+ /* Paint messages */
+ case OS.WM_PAINT: result = wmPaint (hwnd, wParam, lParam); break;
+ case OS.WM_PRINT: result = wmPrint (hwnd, wParam, lParam); break;
+
+ /* Menu messages */
+ case OS.WM_CONTEXTMENU: result = wmContextMenu (hwnd, wParam, lParam); break;
+
+ /* Clipboard messages */
+ case OS.WM_CLEAR:
+ case OS.WM_CUT:
+ case OS.WM_PASTE:
+ case OS.WM_UNDO:
+ case OS.EM_UNDO:
+ if (hwnd == hwndText) {
+ result = wmClipboard (hwnd, msg, wParam, lParam);
+ }
+ break;
+ }
+ if (result != null) return result.value;
+ return callWindowProc (hwnd, msg, wParam, lParam);
+ }
+ return super.windowProc (hwnd, msg, wParam, lParam);
+}
+
+@Override
+LRESULT WM_ERASEBKGND (long wParam, long lParam) {
+ super.WM_ERASEBKGND (wParam, lParam);
+ drawBackground (wParam);
+ return LRESULT.ONE;
+}
+
+@Override
+LRESULT WM_KILLFOCUS (long wParam, long lParam) {
+ return null;
+}
+
+@Override
+LRESULT WM_SETFOCUS (long wParam, long lParam) {
+ OS.SetFocus (hwndText);
+ OS.SendMessage (hwndText, OS.EM_SETSEL, 0, -1);
+ return null;
+}
+
+@Override
+LRESULT WM_SETFONT (long wParam, long lParam) {
+ LRESULT result = super.WM_SETFONT (wParam, lParam);
+ if (result != null) return result;
+ OS.SendMessage (hwndText, OS.WM_SETFONT, wParam, lParam);
+ return result;
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ if (isDisposed ()) return result;
+ int width = OS.LOWORD (lParam), height = OS.HIWORD (lParam);
+ int upDownWidth = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
+ int textWidth = width - upDownWidth;
+ int border = OS.GetSystemMetrics (OS.SM_CXEDGE);
+ int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
+ OS.SetWindowPos (hwndText, 0, 0, 0, textWidth + border, height, flags);
+ OS.SetWindowPos (hwndUpDown, 0, textWidth, 0, upDownWidth, height, flags);
+ return result;
+}
+
+@Override
+LRESULT wmIMEChar(long hwnd, long wParam, long lParam) {
+
+ /* Process a DBCS character */
+ Display display = this.display;
+ display.lastKey = 0;
+ display.lastAscii = (int)wParam;
+ display.lastVirtual = display.lastNull = display.lastDead = false;
+ if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
+ return LRESULT.ZERO;
+ }
+
+ /*
+ * Feature in Windows. The Windows text widget uses
+ * two 2 WM_CHAR's to process a DBCS key instead of
+ * using WM_IME_CHAR. The fix is to allow the text
+ * widget to get the WM_CHAR's but ignore sending
+ * them to the application.
+ */
+ ignoreCharacter = true;
+ long result = callWindowProc (hwnd, OS.WM_IME_CHAR, wParam, lParam);
+ MSG msg = new MSG ();
+ int flags = OS.PM_REMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
+ while (OS.PeekMessage (msg, hwnd, OS.WM_CHAR, OS.WM_CHAR, flags)) {
+ OS.TranslateMessage (msg);
+ OS.DispatchMessage (msg);
+ }
+ ignoreCharacter = false;
+
+ sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
+ // widget could be disposed at this point
+ display.lastKey = display.lastAscii = 0;
+ return new LRESULT (result);
+}
+
+@Override
+LRESULT wmChar (long hwnd, long wParam, long lParam) {
+ if (ignoreCharacter) return null;
+ LRESULT result = super.wmChar (hwnd, wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. For some reason, when the
+ * widget is a single line text widget, when the
+ * user presses tab, return or escape, Windows beeps.
+ * The fix is to look for these keys and not call
+ * the window proc.
+ */
+ switch ((int)wParam) {
+ case SWT.CR:
+ sendSelectionEvent (SWT.DefaultSelection);
+ // FALL THROUGH
+ case SWT.TAB:
+ case SWT.ESC: return LRESULT.ZERO;
+ }
+ return result;
+}
+
+LRESULT wmClipboard (long hwndText, int msg, long wParam, long lParam) {
+ if ((style & SWT.READ_ONLY) != 0) return null;
+// if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return null;
+ boolean call = false;
+ int [] start = new int [1], end = new int [1];
+ String newText = null;
+ switch (msg) {
+ case OS.WM_CLEAR:
+ case OS.WM_CUT:
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ if (start [0] != end [0]) {
+ newText = "";
+ call = true;
+ }
+ break;
+ case OS.WM_PASTE:
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ newText = getClipboardText ();
+ break;
+ case OS.EM_UNDO:
+ case OS.WM_UNDO:
+ if (OS.SendMessage (hwndText, OS.EM_CANUNDO, 0, 0) != 0) {
+ ignoreModify = true;
+ OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
+ int length = OS.GetWindowTextLength (hwndText);
+ int [] newStart = new int [1], newEnd = new int [1];
+ OS.SendMessage (hwndText, OS.EM_GETSEL, newStart, newEnd);
+ if (length != 0 && newStart [0] != newEnd [0]) {
+ char [] buffer = new char [length + 1];
+ OS.GetWindowText (hwndText, buffer, length + 1);
+ newText = new String (buffer, newStart [0], newEnd [0] - newStart [0]);
+ } else {
+ newText = "";
+ }
+ OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
+ OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
+ ignoreModify = false;
+ }
+ break;
+ }
+ if (newText != null) {
+ String oldText = newText;
+ newText = verifyText (newText, start [0], end [0], null);
+ if (newText == null) return LRESULT.ZERO;
+ if (!newText.equals (oldText)) {
+ if (call) {
+ OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
+ }
+ TCHAR buffer = new TCHAR (getCodePage (), newText, true);
+ if (msg == OS.WM_SETTEXT) {
+ long hHeap = OS.GetProcessHeap ();
+ int byteCount = buffer.length () * TCHAR.sizeof;
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ OS.MoveMemory (pszText, buffer, byteCount);
+ long code = OS.CallWindowProc (EditProc, hwndText, msg, wParam, pszText);
+ OS.HeapFree (hHeap, 0, pszText);
+ return new LRESULT (code);
+ } else {
+ OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, buffer);
+ return LRESULT.ZERO;
+ }
+ }
+ }
+ return null;
+}
+
+@Override
+LRESULT wmCommandChild (long wParam, long lParam) {
+ int code = OS.HIWORD (wParam);
+ switch (code) {
+ case OS.EN_CHANGE:
+ if (ignoreModify) break;
+ boolean [] parseFail = new boolean [1];
+ int value = getSelectionText (parseFail);
+ if (!parseFail [0]) {
+ int pos = (int)OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
+ if (pos != value) setSelection (value, true, false, true);
+ }
+ sendEvent (SWT.Modify);
+ if (isDisposed ()) return LRESULT.ZERO;
+ break;
+ }
+ return super.wmCommandChild (wParam, lParam);
+}
+
+@Override
+LRESULT wmKeyDown (long hwnd, long wParam, long lParam) {
+ if (ignoreCharacter) return null;
+ LRESULT result = super.wmKeyDown (hwnd, wParam, lParam);
+ if (result != null) return result;
+
+ /* Increment the value */
+ UDACCEL udaccel = new UDACCEL ();
+ OS.SendMessage (hwndUpDown, OS.UDM_GETACCEL, 1, udaccel);
+ int delta = 0;
+ switch ((int)wParam) {
+ case OS.VK_UP: delta = udaccel.nInc; break;
+ case OS.VK_DOWN: delta = -udaccel.nInc; break;
+ case OS.VK_PRIOR: delta = pageIncrement; break;
+ case OS.VK_NEXT: delta = -pageIncrement; break;
+ }
+ if (delta != 0) {
+ boolean [] parseFail = new boolean [1];
+ int value = getSelectionText (parseFail);
+ if (parseFail [0]) {
+ value = (int)OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
+ }
+ int newValue = value + delta;
+ int [] max = new int [1], min = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, min, max);
+ if ((style & SWT.WRAP) != 0) {
+ if (newValue < min [0]) newValue = max [0];
+ if (newValue > max [0]) newValue = min [0];
+ }
+ newValue = Math.min (Math.max (min [0], newValue), max [0]);
+ if (value != newValue) setSelection (newValue, true, true, true);
+ }
+
+ /* Stop the edit control from moving the caret */
+ switch ((int)wParam) {
+ case OS.VK_UP:
+ case OS.VK_DOWN:
+ return LRESULT.ZERO;
+ }
+ return result;
+}
+
+@Override
+LRESULT wmKillFocus (long hwnd, long wParam, long lParam) {
+ boolean [] parseFail = new boolean [1];
+ int value = getSelectionText (parseFail);
+ if (parseFail [0]) {
+ value = (int)OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
+ setSelection (value, false, true, false);
+ }
+ return super.wmKillFocus (hwnd, wParam, lParam);
+}
+
+@Override
+LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
+ switch (hdr.code) {
+ case OS.UDN_DELTAPOS:
+ NMUPDOWN lpnmud = new NMUPDOWN ();
+ OS.MoveMemory (lpnmud, lParam, NMUPDOWN.sizeof);
+ int value = lpnmud.iPos + lpnmud.iDelta;
+ int [] max = new int [1], min = new int [1];
+ OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, min, max);
+ if ((style & SWT.WRAP) != 0) {
+ if (value < min [0]) value = max [0];
+ if (value > max [0]) value = min [0];
+ }
+ /*
+ * The SWT.Modify event is sent after the widget has been
+ * updated with the new state. Rather than allowing
+ * the default updown window proc to set the value
+ * when the user clicks on the updown control, set
+ * the value explicitly and stop the window proc
+ * from running.
+ */
+ value = Math.min (Math.max (min [0], value), max [0]);
+ if (value != lpnmud.iPos) {
+ setSelection (value, true, true, true);
+ }
+ return LRESULT.ONE;
+ }
+ return super.wmNotifyChild (hdr, wParam, lParam);
+}
+
+@Override
+LRESULT wmScrollChild (long wParam, long lParam) {
+ int code = OS.LOWORD (wParam);
+ switch (code) {
+ case OS.SB_THUMBPOSITION:
+ sendSelectionEvent (SWT.Selection);
+ break;
+ }
+ return super.wmScrollChild (wParam, lParam);
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Synchronizer.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Synchronizer.java
new file mode 100644
index 000000000..2546b364b
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Synchronizer.java
@@ -0,0 +1,267 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class provide synchronization support
+ * for displays. A default instance is created automatically
+ * for each display, and this instance is sufficient for almost
+ * all applications.
+ * run()
method of the runnable to
+ * be invoked by the user-interface thread at the next
+ * reasonable opportunity. The caller of this method continues
+ * to run in parallel, and is not notified when the
+ * runnable has completed.
+ *
+ * @param runnable code to run on the user-interface thread.
+ *
+ * @see #syncExec
+ */
+protected void asyncExec (Runnable runnable) {
+ if (runnable == null) {
+ //TEMPORARY CODE
+ if (!(IS_GTK || IS_COCOA)) {
+ display.wake ();
+ return;
+ }
+ }
+ addLast (new RunnableLock (runnable));
+}
+
+int getMessageCount () {
+ synchronized (messageLock) {
+ return messageCount;
+ }
+}
+
+void releaseSynchronizer () {
+ display = null;
+ messages = null;
+ messageLock = null;
+ syncThread = null;
+}
+
+RunnableLock removeFirst () {
+ synchronized (messageLock) {
+ if (messageCount == 0) return null;
+ RunnableLock lock = messages [0];
+ System.arraycopy (messages, 1, messages, 0, --messageCount);
+ messages [messageCount] = null;
+ if (messageCount == 0) {
+ if (messages.length > MESSAGE_LIMIT) messages = null;
+ }
+ return lock;
+ }
+}
+
+boolean runAsyncMessages () {
+ return runAsyncMessages (false);
+}
+
+boolean runAsyncMessages (boolean all) {
+ boolean run = false;
+ do {
+ RunnableLock lock = removeFirst ();
+ if (lock == null) return run;
+ run = true;
+ synchronized (lock) {
+ syncThread = lock.thread;
+ display.sendPreEvent(SWT.None);
+ try {
+ lock.run (display);
+ } catch (Throwable t) {
+ lock.throwable = t;
+ SWT.error (SWT.ERROR_FAILED_EXEC, t);
+ } finally {
+ if (display != null && !display.isDisposed()) {
+ display.sendPostEvent(SWT.None);
+ }
+ syncThread = null;
+ lock.notifyAll ();
+ }
+ }
+ } while (all);
+ return run;
+}
+
+/**
+ * Causes the run()
method of the runnable to
+ * be invoked by the user-interface thread at the next
+ * reasonable opportunity. The thread which calls this method
+ * is suspended until the runnable completes.
+ *
+ * @param runnable code to run on the user-interface thread.
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #asyncExec
+ */
+protected void syncExec (Runnable runnable) {
+ RunnableLock lock = null;
+ synchronized (Device.class) {
+ if (display == null || display.isDisposed ()) SWT.error (SWT.ERROR_DEVICE_DISPOSED);
+ if (!display.isValidThread ()) {
+ if (runnable == null) {
+ display.wake ();
+ return;
+ }
+ lock = new RunnableLock (runnable);
+ /*
+ * Only remember the syncThread for syncExec.
+ */
+ lock.thread = Thread.currentThread();
+ addLast (lock);
+ }
+ }
+ if (lock == null) {
+ if (runnable != null) {
+ display.sendPreEvent(SWT.None);
+ try {
+ runnable.run();
+ } catch (RuntimeException exception) {
+ display.getRuntimeExceptionHandler ().accept (exception);
+ } catch (Error error) {
+ display.getErrorHandler ().accept (error);
+ } finally {
+ if (display != null && !display.isDisposed()) {
+ display.sendPostEvent(SWT.None);
+ }
+ }
+ }
+ return;
+ }
+ synchronized (lock) {
+ boolean interrupted = false;
+ while (!lock.done ()) {
+ try {
+ lock.wait ();
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ if (lock.throwable != null) {
+ SWT.error (SWT.ERROR_FAILED_EXEC, lock.throwable);
+ }
+ }
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TabFolder.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TabFolder.java
new file mode 100644
index 000000000..ce6d7e3ee
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TabFolder.java
@@ -0,0 +1,1136 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class implement the notebook user interface
+ * metaphor. It allows the user to select a notebook page from
+ * set of pages.
+ * TabItem
.
+ * Control
children are created and then set into a
+ * tab item using TabItem#setControl
.
+ * Composite
,
+ * it does not make sense to set a layout on it.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see SWT#TOP
+ * @see SWT#BOTTOM
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TabFolder (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the SelectionListener
+ * interface.
+ * widgetSelected
is called, the item field of the event object is valid.
+ * widgetDefaultSelected
is not called.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener(listener);
+ addListener(SWT.Selection,typedListener);
+ addListener(SWT.DefaultSelection,typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ if (handle == 0) return 0;
+ return OS.CallWindowProc (TabFolderProc, hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+ style = checkBits (style, SWT.TOP, SWT.BOTTOM, 0, 0, 0, 0);
+
+ /*
+ * Even though it is legal to create this widget
+ * with scroll bars, they serve no useful purpose
+ * because they do not automatically scroll the
+ * widget's client area. The fix is to clear
+ * the SWT style.
+ */
+ return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+@Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
+ checkWidget ();
+ Point size = super.computeSizeInPixels (wHint, hHint, changed);
+ RECT insetRect = new RECT (), itemRect = new RECT ();
+ OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 0, insetRect);
+ int width = insetRect.left - insetRect.right;
+ int count = (int)OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
+ if (count != 0) {
+ OS.SendMessage (handle, OS.TCM_GETITEMRECT, count - 1, itemRect);
+ width = Math.max (width, itemRect.right - insetRect.right);
+ }
+ RECT rect = new RECT ();
+ OS.SetRect (rect, 0, 0, width, size.y);
+ OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 1, rect);
+ int border = getBorderWidthInPixels ();
+ rect.left -= border; rect.right += border;
+ width = rect.right - rect.left;
+ size.x = Math.max (width, size.x);
+ return size;
+}
+
+@Override Rectangle computeTrimInPixels (int x, int y, int width, int height) {
+ checkWidget ();
+ RECT rect = new RECT ();
+ OS.SetRect (rect, x, y, x + width, y + height);
+ OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 1, rect);
+ int border = getBorderWidthInPixels ();
+ rect.left -= border; rect.right += border;
+ rect.top -= border; rect.bottom += border;
+ int newWidth = rect.right - rect.left;
+ int newHeight = rect.bottom - rect.top;
+ return new Rectangle (rect.left, rect.top, newWidth, newHeight);
+}
+
+void createItem (TabItem item, int index) {
+ int count = (int)OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
+ if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
+ if (count == items.length) {
+ TabItem [] newItems = new TabItem [items.length + 4];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ TCITEM tcItem = new TCITEM ();
+ if (OS.SendMessage (handle, OS.TCM_INSERTITEM, index, tcItem) == -1) {
+ error (SWT.ERROR_ITEM_NOT_ADDED);
+ }
+ System.arraycopy (items, index, items, index + 1, count - index);
+ items [index] = item;
+
+ /*
+ * Send a selection event when the item that is added becomes
+ * the new selection. This only happens when the first item
+ * is added.
+ */
+ if (count == 0) {
+ Event event = new Event ();
+ event.item = items [0];
+ sendSelectionEvent (SWT.Selection, event, true);
+ // the widget could be destroyed at this point
+ }
+}
+
+@Override
+void createHandle () {
+ super.createHandle ();
+ state &= ~(CANVAS | THEME_BACKGROUND);
+
+ /*
+ * Feature in Windows. Despite the fact that the
+ * tool tip text contains \r\n, the tooltip will
+ * not honour the new line unless TTM_SETMAXTIPWIDTH
+ * is set. The fix is to set TTM_SETMAXTIPWIDTH to
+ * a large value.
+ */
+ long hwndToolTip = OS.SendMessage (handle, OS.TCM_GETTOOLTIPS, 0, 0);
+ OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
+
+ createdAsRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
+}
+
+@Override
+void createWidget () {
+ super.createWidget ();
+ items = new TabItem [4];
+}
+
+void destroyItem (TabItem item) {
+ int count = (int)OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
+ int index = 0;
+ while (index < count) {
+ if (items [index] == item) break;
+ index++;
+ }
+ if (index == count) return;
+ int selectionIndex = (int)OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
+ if (OS.SendMessage (handle, OS.TCM_DELETEITEM, index, 0) == 0) {
+ error (SWT.ERROR_ITEM_NOT_REMOVED);
+ }
+ System.arraycopy (items, index + 1, items, index, --count - index);
+ items [count] = null;
+ if (count == 0) {
+ if (imageList != null) {
+ OS.SendMessage (handle, OS.TCM_SETIMAGELIST, 0, 0);
+ display.releaseImageList (imageList);
+ }
+ imageList = null;
+ items = new TabItem [4];
+ }
+ if (count > 0 && index == selectionIndex) {
+ setSelection (Math.max (0, selectionIndex - 1), true);
+ }
+}
+
+@Override
+void drawThemeBackground (long hDC, long hwnd, RECT rect) {
+ RECT rect2 = new RECT ();
+ OS.GetClientRect (handle, rect2);
+ OS.MapWindowPoints (handle, hwnd, rect2, 2);
+ if (OS.IntersectRect (new RECT (), rect2, rect)) {
+ OS.DrawThemeBackground (display.hTabTheme (), hDC, OS.TABP_BODY, 0, rect2, null);
+ }
+}
+
+@Override
+Control findThemeControl () {
+ /* It is not possible to change the background of this control */
+ return this;
+}
+
+@Override Rectangle getClientAreaInPixels () {
+ checkWidget ();
+ forceResize ();
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 0, rect);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ return new Rectangle (rect.left, rect.top, width, height);
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public TabItem getItem (int index) {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
+ if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
+ return items [index];
+}
+
+/**
+ * Returns the tab item at the given point in the receiver
+ * or null if no such item exists. The point is in the
+ * coordinate system of the receiver.
+ *
+ * @param point the point used to locate the item
+ * @return the tab item at the given point, or null if the point is not in a tab item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public TabItem getItem (Point point) {
+ checkWidget ();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TCHITTESTINFO pinfo = new TCHITTESTINFO ();
+ pinfo.x = point.x;
+ pinfo.y = point.y;
+ int index = (int)OS.SendMessage (handle, OS.TCM_HITTEST, 0, pinfo);
+ if (index == -1) return null;
+ return items [index];
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemCount () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
+}
+
+/**
+ * Returns an array of TabItem
s which are the items
+ * in the receiver.
+ *
+ *
+ */
+public TabItem [] getItems () {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
+ TabItem [] result = new TabItem [count];
+ System.arraycopy (items, 0, result, 0, count);
+ return result;
+}
+
+/**
+ * Returns an array of TabItem
s that are currently
+ * selected in the receiver. An empty array indicates that no
+ * items are selected.
+ *
+ *
+ */
+public TabItem [] getSelection () {
+ checkWidget ();
+ int index = (int)OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
+ if (index == -1) return new TabItem [0];
+ return new TabItem [] {items [index]};
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * selected in the receiver, or -1 if no item is selected.
+ *
+ * @return the index of the selected item
+ *
+ * @exception SWTException
+ *
+ */
+public int getSelectionIndex () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
+}
+
+int imageIndex (Image image) {
+ /*
+ * Bug 497387: Return -1 if there is no image for the tab, for more details
+ * refer: https://msdn.microsoft.com/pt-br/library/windows/hardware/bb760554
+ */
+ if (image == null) return -1;
+ if (imageList == null) {
+ Rectangle bounds = image.getBoundsInPixels ();
+ imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
+ int index = imageList.add (image);
+ long hImageList = imageList.getHandle ();
+ OS.SendMessage (handle, OS.TCM_SETIMAGELIST, 0, hImageList);
+ return index;
+ }
+ int index = imageList.indexOf (image);
+ if (index == -1) {
+ index = imageList.add (image);
+ } else {
+ imageList.put (index, image);
+ }
+ return index;
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public int indexOf (TabItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int count = (int)OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
+ for (int i=0; i
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+
+@Override
+void reskinChildren (int flags) {
+ if (items != null) {
+ int count = (int)OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
+ for (int i=0; i
+ *
+ *
+ * @since 3.2
+ */
+public void setSelection (TabItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ setSelection (new TabItem [] {item});
+}
+
+/**
+ * Sets the receiver's selection to be the given array of items.
+ * The current selected is first cleared, then the new items are
+ * selected.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (TabItem [] items) {
+ checkWidget ();
+ if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (items.length == 0) {
+ setSelection (-1, false);
+ } else {
+ for (int i=items.length-1; i>=0; --i) {
+ int index = indexOf (items [i]);
+ if (index != -1) setSelection (index, false);
+ }
+ }
+}
+
+@Override
+public void setFont (Font font) {
+ checkWidget ();
+ Rectangle oldRect = getClientAreaInPixels ();
+ super.setFont (font);
+ Rectangle newRect = getClientAreaInPixels ();
+ if (!oldRect.equals (newRect)) {
+ sendResize ();
+ int index = (int)OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
+ if (index != -1) {
+ TabItem item = items [index];
+ Control control = item.control;
+ if (control != null && !control.isDisposed ()) {
+ control.setBoundsInPixels (getClientAreaInPixels ());
+ }
+ }
+ }
+}
+
+/**
+ * Selects the item at the given zero-relative index in the receiver.
+ * If the item at the index was already selected, it remains selected.
+ * The current selection is first cleared, then the new items are
+ * selected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception SWTException
+ *
+ */
+public void setSelection (int index) {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.TCM_GETITEMCOUNT, 0, 0);
+ if (!(0 <= index && index < count)) return;
+ setSelection (index, false);
+}
+
+void setSelection (int index, boolean notify) {
+ int oldIndex = (int)OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
+ if (oldIndex == index) return;
+ if (oldIndex != -1) {
+ TabItem item = items [oldIndex];
+ Control control = item.control;
+ if (control != null && !control.isDisposed ()) {
+ control.setVisible (false);
+ }
+ }
+ OS.SendMessage (handle, OS.TCM_SETCURSEL, index, 0);
+ int newIndex = (int)OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
+ if (newIndex != -1) {
+ TabItem item = items [newIndex];
+ Control control = item.control;
+ if (control != null && !control.isDisposed ()) {
+ control.setBoundsInPixels (getClientAreaInPixels ());
+ control.setVisible (true);
+ }
+ if (notify) {
+ Event event = new Event ();
+ event.item = item;
+ sendSelectionEvent (SWT.Selection, event, true);
+ }
+ }
+}
+
+@Override
+boolean updateTextDirection(int textDirection) {
+ if (super.updateTextDirection(textDirection)) {
+ if (textDirection != AUTO_TEXT_DIRECTION) {
+ textDirection = style & SWT.FLIP_TEXT_DIRECTION;
+ }
+ for (int i = 0, n = items.length; i < n && items[i] != null; i++) {
+ items[i].updateTextDirection (textDirection);
+ }
+ return true;
+ }
+ return false;
+}
+
+@Override
+String toolTipText (NMTTDISPINFO hdr) {
+ if ((hdr.uFlags & OS.TTF_IDISHWND) != 0) {
+ return null;
+ }
+ int index = (int)hdr.idFrom;
+ long hwndToolTip = OS.SendMessage (handle, OS.TCM_GETTOOLTIPS, 0, 0);
+ if (hwndToolTip == hdr.hwndFrom) {
+ /*
+ * Bug in Windows. For some reason the reading order
+ * in NMTTDISPINFO is sometimes set incorrectly. The
+ * reading order seems to change every time the mouse
+ * enters the control from the top edge. The fix is
+ * to explicitly set TTF_RTLREADING.
+ */
+ int flags = SWT.RIGHT_TO_LEFT | SWT.FLIP_TEXT_DIRECTION;
+ if ((style & flags) != 0 && (style & flags) != flags) {
+ hdr.uFlags |= OS.TTF_RTLREADING;
+ } else {
+ hdr.uFlags &= ~OS.TTF_RTLREADING;
+ }
+ if (toolTipText != null) return "";
+ if (0 <= index && index < items.length) {
+ TabItem item = items [index];
+ if (item != null) return item.toolTipText;
+ }
+ }
+ return super.toolTipText (hdr);
+}
+
+@Override
+boolean traversePage (boolean next) {
+ int count = getItemCount ();
+ if (count <= 1) return false;
+ int index = getSelectionIndex ();
+ if (index == -1) {
+ index = 0;
+ } else {
+ int offset = (next) ? 1 : -1;
+ index = (index + offset + count) % count;
+ }
+ setSelection (index, true);
+ if (index == getSelectionIndex ()) {
+ OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
+ return true;
+ }
+ return false;
+}
+
+@Override
+void updateOrientation () {
+ super.updateOrientation ();
+ long hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
+ while (hwndChild != 0) {
+ char [] buffer = new char [128];
+ int length = OS.GetClassName (hwndChild, buffer, buffer.length);
+ String className = new String (buffer, 0, length);
+ if (className.equals ("msctls_updown32")) { //$NON-NLS-1$
+ int bits = OS.GetWindowLong (hwndChild, OS.GWL_EXSTYLE);
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ bits |= OS.WS_EX_LAYOUTRTL;
+ } else {
+ bits &= ~OS.WS_EX_LAYOUTRTL;
+ }
+ bits &= ~OS.WS_EX_RTLREADING;
+ OS.SetWindowLong (hwndChild, OS.GWL_EXSTYLE, bits);
+ OS.InvalidateRect (hwndChild, null, true);
+ break;
+ }
+ hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
+ }
+ RECT rect = new RECT ();
+ OS.GetWindowRect (handle, rect);
+ int width = rect.right - rect.left, height = rect.bottom - rect.top;
+ OS.SetWindowPos (handle, 0, 0, 0, width - 1, height - 1, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
+ OS.SetWindowPos (handle, 0, 0, 0, width, height, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
+ if (imageList != null) {
+ Point size = imageList.getImageSize ();
+ display.releaseImageList (imageList);
+ imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, size.x, size.y);
+ long hImageList = imageList.getHandle ();
+ OS.SendMessage (handle, OS.TCM_SETIMAGELIST, 0, hImageList);
+ TCITEM tcItem = new TCITEM ();
+ tcItem.mask = OS.TCIF_IMAGE;
+ for (int i = 0; i < items.length; i++) {
+ TabItem item = items [i];
+ if (item == null) break;
+ Image image = item.image;
+ if (image != null) {
+ tcItem.iImage = imageIndex (image);
+ OS.SendMessage (handle, OS.TCM_SETITEM, i, tcItem);
+ }
+ }
+ }
+}
+
+@Override
+int widgetStyle () {
+ /*
+ * Bug in Windows. Under certain circumstances,
+ * when TCM_SETITEM is used to change the text
+ * in a tab item, the tab folder draws on top
+ * of the client area. The fix is ensure that
+ * this cannot happen by setting WS_CLIPCHILDREN.
+ */
+ int bits = super.widgetStyle () | OS.WS_CLIPCHILDREN;
+ if ((style & SWT.NO_FOCUS) != 0) bits |= OS.TCS_FOCUSNEVER;
+ if ((style & SWT.BOTTOM) != 0) bits |= OS.TCS_BOTTOM;
+ return bits | OS.TCS_TABS | OS.TCS_TOOLTIPS;
+}
+
+@Override
+TCHAR windowClass () {
+ return TabFolderClass;
+}
+
+@Override
+long windowProc () {
+ return TabFolderProc;
+}
+
+@Override
+LRESULT WM_GETDLGCODE (long wParam, long lParam) {
+ LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
+ /*
+ * Return DLGC_BUTTON so that mnemonics will be
+ * processed without needing to press the ALT key
+ * when the widget has focus.
+ */
+ if (result != null) return result;
+ return new LRESULT (OS.DLGC_BUTTON | OS.DLGC_WANTARROWS);
+}
+
+@Override
+LRESULT WM_GETOBJECT (long wParam, long lParam) {
+ /*
+ * Ensure that there is an accessible object created for this
+ * control because support for publishing the keyboard shortcut
+ * for page switching is implemented in the accessibility package.
+ */
+ if (accessible == null) accessible = new_Accessible (this);
+ return super.WM_GETOBJECT (wParam, lParam);
+}
+
+@Override
+LRESULT WM_KEYDOWN (long wParam, long lParam) {
+ LRESULT result = super.WM_KEYDOWN (wParam, lParam);
+ if (result != null) return result;
+ switch ((int)wParam) {
+ case OS.VK_LEFT:
+ case OS.VK_RIGHT:
+ /*
+ * Bug in Windows. The behavior for the left and right keys is not
+ * changed if the orientation changes after the control was created.
+ * The fix is to replace VK_LEFT by VK_RIGHT and VK_RIGHT by VK_LEFT
+ * when the current orientation differs from the orientation used to
+ * create the control.
+ */
+ boolean isRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
+ if (isRTL != createdAsRTL) {
+ long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam == OS.VK_RIGHT ? OS.VK_LEFT : OS.VK_RIGHT, lParam);
+ return new LRESULT (code);
+ }
+ break;
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_MOUSELEAVE (long wParam, long lParam) {
+ LRESULT result = super.WM_MOUSELEAVE (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Bug in Windows. On XP, when a tooltip is
+ * hidden due to a time out or mouse press,
+ * the tooltip remains active although no
+ * longer visible and won't show again until
+ * another tooltip becomes active. If there
+ * is only one tooltip in the window, it will
+ * never show again. The fix is to remove the
+ * current tooltip and add it again every time
+ * the mouse leaves the control.
+ */
+ TOOLINFO lpti = new TOOLINFO ();
+ lpti.cbSize = TOOLINFO.sizeof;
+ long hwndToolTip = OS.SendMessage (handle, OS.TCM_GETTOOLTIPS, 0, 0);
+ if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, lpti) != 0) {
+ if ((lpti.uFlags & OS.TTF_IDISHWND) == 0) {
+ OS.SendMessage (hwndToolTip, OS.TTM_DELTOOL, 0, lpti);
+ OS.SendMessage (hwndToolTip, OS.TTM_ADDTOOL, 0, lpti);
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_NCHITTEST (long wParam, long lParam) {
+ LRESULT result = super.WM_NCHITTEST (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. The tab control implements
+ * WM_NCHITTEST to return HTCLIENT when the cursor
+ * is inside the tab buttons. This causes mouse
+ * events like WM_MOUSEMOVE to be delivered to the
+ * parent. Also, tool tips for the tab control are
+ * never invoked because tool tips rely on mouse
+ * events to be delivered to the window that wants
+ * to display the tool tip. The fix is to call the
+ * default window proc that returns HTCLIENT when
+ * the mouse is in the client area.
+ */
+ long hittest = OS.DefWindowProc (handle, OS.WM_NCHITTEST, wParam, lParam);
+ return new LRESULT (hittest);
+}
+
+@Override
+LRESULT WM_NOTIFY (long wParam, long lParam) {
+ /*
+ * Feature in Windows. When the tab folder window
+ * proc processes WM_NOTIFY, it forwards this
+ * message to its parent. This is done so that
+ * children of this control that send this message
+ * type to their parent will notify not only
+ * this control but also the parent of this control,
+ * which is typically the application window and
+ * the window that is looking for the message.
+ * If the control did not forward the message,
+ * applications would have to subclass the control
+ * window to see the message. Because the control
+ * window is subclassed by SWT, the message
+ * is delivered twice, once by SWT and once when
+ * the message is forwarded by the window proc.
+ * The fix is to avoid calling the window proc
+ * for this control.
+ */
+ LRESULT result = super.WM_NOTIFY (wParam, lParam);
+ if (result != null) return result;
+ return LRESULT.ZERO;
+}
+
+@Override
+LRESULT WM_PARENTNOTIFY (long wParam, long lParam) {
+ LRESULT result = super.WM_PARENTNOTIFY (wParam, lParam);
+ if (result != null) return result;
+ /*
+ * Feature in Windows. Windows does not explicitly set the orientation of
+ * the buddy control. Instead, the orientation is inherited when WS_EX_LAYOUTRTL
+ * is specified for the tab folder. This means that when both WS_EX_LAYOUTRTL
+ * and WS_EX_NOINHERITLAYOUT are specified for the tab folder, the buddy control
+ * will not be oriented correctly. The fix is to explicitly set the orientation
+ * for the buddy control.
+ */
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ int code = OS.LOWORD (wParam);
+ switch (code) {
+ case OS.WM_CREATE: {
+ int id = OS.HIWORD (wParam);
+ long hwnd = lParam;
+ if (id == ID_UPDOWN) {
+ int bits = OS.GetWindowLong (hwnd, OS.GWL_EXSTYLE);
+ OS.SetWindowLong (hwnd, OS.GWL_EXSTYLE, bits | OS.WS_EX_LAYOUTRTL);
+ }
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_SIZE (long wParam, long lParam) {
+ LRESULT result = super.WM_SIZE (wParam, lParam);
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the resize
+ * event. If this happens, end the processing of the
+ * Windows message by returning the result of the
+ * WM_SIZE message.
+ */
+ if (isDisposed ()) return result;
+ int index = (int)OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
+ if (index != -1) {
+ TabItem item = items [index];
+ Control control = item.control;
+ if (control != null && !control.isDisposed ()) {
+ control.setBoundsInPixels (getClientAreaInPixels ());
+ }
+ }
+ return result;
+}
+
+@Override
+LRESULT WM_WINDOWPOSCHANGING (long wParam, long lParam) {
+ LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
+ if (result != null) return result;
+ if (!OS.IsWindowVisible (handle)) return result;
+ WINDOWPOS lpwp = new WINDOWPOS ();
+ OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
+ if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) != 0) {
+ return result;
+ }
+ // TEMPORARY CODE
+// if (OS.IsAppThemed ()) {
+// OS.InvalidateRect (handle, null, true);
+// return result;
+// }
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.TCS_MULTILINE) != 0) {
+ OS.InvalidateRect (handle, null, true);
+ return result;
+ }
+ RECT rect = new RECT ();
+ OS.SetRect (rect, 0, 0, lpwp.cx, lpwp.cy);
+ OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, rect);
+ int newWidth = rect.right - rect.left;
+ int newHeight = rect.bottom - rect.top;
+ OS.GetClientRect (handle, rect);
+ int oldWidth = rect.right - rect.left;
+ int oldHeight = rect.bottom - rect.top;
+ if (newWidth == oldWidth && newHeight == oldHeight) {
+ return result;
+ }
+ RECT inset = new RECT ();
+ OS.SendMessage (handle, OS.TCM_ADJUSTRECT, 0, inset);
+ int marginX = -inset.right, marginY = -inset.bottom;
+ if (newWidth != oldWidth) {
+ int left = oldWidth;
+ if (newWidth < oldWidth) left = newWidth;
+ OS.SetRect (rect, left - marginX, 0, newWidth, newHeight);
+ OS.InvalidateRect (handle, rect, true);
+ }
+ if (newHeight != oldHeight) {
+ int bottom = oldHeight;
+ if (newHeight < oldHeight) bottom = newHeight;
+ if (newWidth < oldWidth) oldWidth -= marginX;
+ OS.SetRect (rect, 0, bottom - marginY, oldWidth, newHeight);
+ OS.InvalidateRect (handle, rect, true);
+ }
+ return result;
+}
+
+@Override
+LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
+ int code = hdr.code;
+ switch (code) {
+ case OS.TCN_SELCHANGE:
+ case OS.TCN_SELCHANGING:
+ TabItem item = null;
+ int index = (int)OS.SendMessage (handle, OS.TCM_GETCURSEL, 0, 0);
+ if (index != -1) item = items [index];
+ if (item != null) {
+ Control control = item.control;
+ if (control != null && !control.isDisposed ()) {
+ if (code == OS.TCN_SELCHANGE) {
+ control.setBoundsInPixels (getClientAreaInPixels ());
+ }
+ control.setVisible (code == OS.TCN_SELCHANGE);
+ }
+ }
+ if (code == OS.TCN_SELCHANGE) {
+ Event event = new Event ();
+ event.item = item;
+ sendSelectionEvent (SWT.Selection, event, false);
+ }
+ }
+ return super.wmNotifyChild (hdr, wParam, lParam);
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TabItem.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TabItem.java
new file mode 100644
index 000000000..ac4a3f89b
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TabItem.java
@@ -0,0 +1,414 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent a selectable user interface object
+ * corresponding to a tab for a page in a tab folder.
+ *
+ *
+ * TabFolder
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TabItem (TabFolder parent, int style) {
+ super (parent, style);
+ this.parent = parent;
+ parent.createItem (this, parent.getItemCount ());
+}
+
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a TabFolder
), a style value
+ * describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public TabItem (TabFolder parent, int style, int index) {
+ super (parent, style);
+ this.parent = parent;
+ parent.createItem (this, index);
+}
+
+void _setText (int index, String string) {
+ /*
+ * Bug in Windows. In version 6.00 of COMCTL32.DLL, tab
+ * items with an image and a label that includes '&' cause
+ * the tab to draw incorrectly (even when doubled '&&').
+ * The image overlaps the label. The fix is to remove
+ * all '&' characters from the string.
+ */
+ if (image != null) {
+ if (string.indexOf ('&') != -1) {
+ int length = string.length ();
+ char[] text = new char [length];
+ string.getChars ( 0, length, text, 0);
+ int i = 0, j = 0;
+ for (i=0; i
+ *
+ */
+public Control getControl () {
+ checkWidget();
+ return control;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent.
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 3.4
+ */
+public Rectangle getBounds () {
+ checkWidget();
+ return DPIUtil.autoScaleDown(getBoundsInPixels());
+}
+
+Rectangle getBoundsInPixels() {
+ int index = parent.indexOf(this);
+ if (index == -1) return new Rectangle (0, 0, 0, 0);
+ RECT itemRect = new RECT ();
+ OS.SendMessage (parent.handle, OS.TCM_GETITEMRECT, index, itemRect);
+ return new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top);
+}
+
+/**
+ * Returns the receiver's parent, which must be a TabFolder
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException
+ *
+ */
+public TabFolder getParent () {
+ checkWidget();
+ return parent;
+}
+
+/**
+ * Returns the receiver's tool tip text, or null if it has
+ * not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception SWTException
+ *
+ */
+public String getToolTipText () {
+ checkWidget();
+ return toolTipText;
+}
+
+@Override
+void releaseHandle () {
+ super.releaseHandle ();
+ parent = null;
+}
+
+@Override
+void releaseParent () {
+ super.releaseParent ();
+ int index = parent.indexOf (this);
+ if (index == parent.getSelectionIndex ()) {
+ if (control != null) control.setVisible (false);
+ }
+}
+
+@Override
+void releaseWidget () {
+ super.releaseWidget ();
+ control = null;
+}
+
+/**
+ * Sets the control that is used to fill the client area of
+ * the tab folder when the user selects the tab item.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public void setControl (Control control) {
+ checkWidget();
+ if (control != null) {
+ if (control.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+ if (control.parent != parent) error (SWT.ERROR_INVALID_PARENT);
+ }
+ if (this.control != null && this.control.isDisposed ()) {
+ this.control = null;
+ }
+ Control oldControl = this.control, newControl = control;
+ this.control = control;
+ int index = parent.indexOf (this), selectionIndex = parent.getSelectionIndex();
+ if (index != selectionIndex) {
+ if (newControl != null) {
+ if (selectionIndex != -1) {
+ Control selectedControl = parent.getItem(selectionIndex).getControl();
+ if (selectedControl == newControl) return;
+ }
+ newControl.setVisible(false);
+ return;
+ }
+ }
+ if (newControl != null) {
+ newControl.setBounds (parent.getClientAreaInPixels ());
+ newControl.setVisible (true);
+ }
+ if (oldControl != null && newControl != null && oldControl != newControl)
+ oldControl.setVisible (false);
+}
+
+@Override
+public void setImage (Image image) {
+ checkWidget();
+ int index = parent.indexOf (this);
+ if (index == -1) return;
+ super.setImage (image);
+ /*
+ * Bug in Windows. In version 6.00 of COMCTL32.DLL, tab
+ * items with an image and a label that includes '&' cause
+ * the tab to draw incorrectly (even when doubled '&&').
+ * The image overlaps the label. The fix is to remove
+ * all '&' characters from the string and set the text
+ * whenever the image or text is changed.
+ */
+ if (text.indexOf ('&') != -1) _setText (index, text);
+ long hwnd = parent.handle;
+ TCITEM tcItem = new TCITEM ();
+ tcItem.mask = OS.TCIF_IMAGE;
+ tcItem.iImage = parent.imageIndex (image);
+ OS.SendMessage (hwnd, OS.TCM_SETITEM, index, tcItem);
+}
+/**
+ * Sets the receiver's text. The string may include
+ * the mnemonic character.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ */
+@Override
+public void setText (String string) {
+ checkWidget();
+ if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (string.equals (text)) return;
+ int index = parent.indexOf (this);
+ if (index == -1) return;
+ super.setText (string);
+ /*
+ * Need to update direction since it is set via UCC which the new text
+ * overrides
+ */
+ int textDirection = (state & HAS_AUTO_DIRECTION) != 0 ? AUTO_TEXT_DIRECTION : style & SWT.FLIP_TEXT_DIRECTION;
+ if (!updateTextDirection (textDirection)) {
+ _setText (index, string);
+ }
+}
+
+@Override
+boolean updateTextDirection(int textDirection) {
+ /* AUTO is handled by super */
+ if (super.updateTextDirection(textDirection)) {
+ int index = parent.indexOf (this);
+ if (index != -1) {
+ if ((textDirection & SWT.RIGHT_TO_LEFT) != 0) {
+ _setText(index, RLE + text);
+ return true;
+ } else if ((textDirection & SWT.LEFT_TO_RIGHT) != 0) {
+ _setText(index, LRE + text);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Sets the receiver's tool tip text to the argument, which
+ * may be null indicating that the default tool tip for the
+ * control will be shown. For a control that has a default
+ * tool tip, such as the Tree control on Windows, setting
+ * the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ *
+ *
+ */
+public void setToolTipText (String string) {
+ checkWidget();
+ toolTipText = string;
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Table.java
new file mode 100644
index 000000000..f9f18ba78
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Table.java
@@ -0,0 +1,7347 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Roland Oldenburg TableItem
.
+ * VIRTUAL
is used to create a Table
whose
+ * TableItem
s are to be populated by the client on an on-demand basis
+ * instead of up-front. This can provide significant performance improvements for
+ * tables that are very large or for which TableItem
population is
+ * expensive (for example, retrieving values from an external source).
+ * Table
with style VIRTUAL
:
+ *
+ * final Table table = new Table (parent, SWT.VIRTUAL | SWT.BORDER);
+ * table.setItemCount (1000000);
+ * table.addListener (SWT.SetData, new Listener () {
+ * public void handleEvent (Event event) {
+ * TableItem item = (TableItem) event.item;
+ * int index = table.indexOf (item);
+ * item.setText ("Item " + index);
+ * System.out.println (item.getText ());
+ * }
+ * });
+ *
Composite
,
+ * it does not normally make sense to add Control
children to
+ * it, or set a layout on it, unless implementing something like a cell
+ * editor.
+ *
+ *
+ * SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#SINGLE
+ * @see SWT#MULTI
+ * @see SWT#CHECK
+ * @see SWT#FULL_SELECTION
+ * @see SWT#HIDE_SELECTION
+ * @see SWT#VIRTUAL
+ * @see SWT#NO_SCROLL
+ * @see Widget#checkSubclass
+ * @see Widget#getStyle
+ */
+public Table (Composite parent, int style) {
+ super (parent, checkStyle (style));
+}
+
+@Override
+void _addListener (int eventType, Listener listener) {
+ super._addListener (eventType, listener);
+ switch (eventType) {
+ case SWT.MeasureItem:
+ case SWT.EraseItem:
+ case SWT.PaintItem:
+ setCustomDraw (true);
+ setBackgroundTransparent (true);
+ break;
+ }
+}
+
+boolean _checkGrow (int count) {
+ //TODO - code could be shared but it would mix keyed and non-keyed logic
+ if (keys == null) {
+ if (count == items.length) {
+ /*
+ * Grow the array faster when redraw is off or the
+ * table is not visible. When the table is painted,
+ * the items array is resized to be smaller to reduce
+ * memory usage.
+ */
+ boolean small = getDrawing () && OS.IsWindowVisible (handle);
+ int length = small ? items.length + 4 : Math.max (4, items.length * 3 / 2);
+ TableItem [] newItems = new TableItem [length];
+ System.arraycopy (items, 0, newItems, 0, items.length);
+ items = newItems;
+ }
+ } else {
+ //TODO - don't shrink when count is very small (ie. 2 or 4 elements)?
+ //TODO - why? if setItemCount(1000000) is used after a shrink, then we won't compress
+ //TODO - get rid of ignoreShrink?
+ if (!ignoreShrink && keyCount > count / 2) {
+ boolean small = getDrawing () && OS.IsWindowVisible (handle);
+ int length = small ? count + 4 : Math.max (4, count * 3 / 2);
+ TableItem [] newItems = new TableItem [length];
+ for (int i=0; iwidgetSelected
is called, the item field of the event object is valid.
+ * If the receiver has the SWT.CHECK
style and the check selection changes,
+ * the event object detail field contains the value SWT.CHECK
.
+ * widgetDefaultSelected
is typically called when an item is double-clicked.
+ * The item field of the event object is valid for default selection, but the detail field is not used.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener (SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.Selection,typedListener);
+ addListener (SWT.DefaultSelection,typedListener);
+}
+
+@Override
+long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
+ return callWindowProc (hwnd, msg, wParam, lParam, false);
+}
+
+long callWindowProc (long hwnd, int msg, long wParam, long lParam, boolean forceSelect) {
+ if (handle == 0) return 0;
+ if (hwndHeader != 0 && hwnd == hwndHeader) {
+ return OS.CallWindowProc (HeaderProc, hwnd, msg, wParam, lParam);
+ }
+ int topIndex = 0;
+ boolean checkSelection = false, checkActivate = false, redraw = false;
+ switch (msg) {
+ /* Keyboard messages */
+ /*
+ * Feature in Windows. Windows sends LVN_ITEMACTIVATE from WM_KEYDOWN
+ * instead of WM_CHAR. This means that application code that expects
+ * to consume the key press and therefore avoid a SWT.DefaultSelection
+ * event will fail. The fix is to ignore LVN_ITEMACTIVATE when it is
+ * caused by WM_KEYDOWN and send SWT.DefaultSelection from WM_CHAR.
+ */
+ case OS.WM_KEYDOWN:
+ checkActivate = true;
+ //FALL THROUGH
+ case OS.WM_CHAR:
+ case OS.WM_IME_CHAR:
+ case OS.WM_KEYUP:
+ case OS.WM_SYSCHAR:
+ case OS.WM_SYSKEYDOWN:
+ case OS.WM_SYSKEYUP:
+ //FALL THROUGH
+
+ /* Scroll messages */
+ case OS.WM_HSCROLL:
+ case OS.WM_VSCROLL:
+ //FALL THROUGH
+
+ /* Resize messages */
+ case OS.WM_WINDOWPOSCHANGED:
+ redraw = findImageControl () != null && getDrawing () && OS.IsWindowVisible (handle);
+ if (redraw) {
+ /*
+ * Feature in Windows. When LVM_SETBKCOLOR is used with CLR_NONE
+ * to make the background of the table transparent, drawing becomes
+ * slow. The fix is to temporarily clear CLR_NONE when redraw is
+ * turned off.
+ */
+ OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
+ OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, 0xFFFFFF);
+ }
+ //FALL THROUGH
+
+ /* Mouse messages */
+ case OS.WM_LBUTTONDBLCLK:
+ case OS.WM_LBUTTONDOWN:
+ case OS.WM_LBUTTONUP:
+ case OS.WM_MBUTTONDBLCLK:
+ case OS.WM_MBUTTONDOWN:
+ case OS.WM_MBUTTONUP:
+ case OS.WM_MOUSEHOVER:
+ case OS.WM_MOUSELEAVE:
+ case OS.WM_MOUSEMOVE:
+ case OS.WM_MOUSEWHEEL:
+ case OS.WM_RBUTTONDBLCLK:
+ case OS.WM_RBUTTONDOWN:
+ case OS.WM_RBUTTONUP:
+ case OS.WM_XBUTTONDBLCLK:
+ case OS.WM_XBUTTONDOWN:
+ case OS.WM_XBUTTONUP:
+ checkSelection = true;
+ //FALL THROUGH
+
+ /* Other messages */
+ case OS.WM_SETFONT:
+ case OS.WM_TIMER: {
+ if (findImageControl () != null) {
+ topIndex = (int)OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0);
+ }
+ }
+ }
+ boolean oldSelected = wasSelected;
+ if (checkSelection) wasSelected = false;
+ if (checkActivate) ignoreActivate = true;
+
+ /*
+ * Bug in Windows. For some reason, when the WS_EX_COMPOSITED
+ * style is set in a parent of a table and the header is visible,
+ * Windows issues an endless stream of WM_PAINT messages. The
+ * fix is to call BeginPaint() and EndPaint() outside of WM_PAINT
+ * and pass the paint HDC in to the window proc.
+ */
+ boolean fixPaint = false;
+ if (msg == OS.WM_PAINT) {
+ int bits0 = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits0 & OS.LVS_NOCOLUMNHEADER) == 0) {
+ long hwndParent = OS.GetParent (handle), hwndOwner = 0;
+ while (hwndParent != 0) {
+ int bits1 = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
+ if ((bits1 & OS.WS_EX_COMPOSITED) != 0) {
+ fixPaint = true;
+ break;
+ }
+ hwndOwner = OS.GetWindow (hwndParent, OS.GW_OWNER);
+ if (hwndOwner != 0) break;
+ hwndParent = OS.GetParent (hwndParent);
+ }
+ }
+ }
+
+ /* Remove the scroll bars that Windows keeps automatically adding */
+ boolean fixScroll = false;
+ if ((style & SWT.H_SCROLL) == 0 || (style & SWT.V_SCROLL) == 0) {
+ switch (msg) {
+ case OS.WM_PAINT:
+ case OS.WM_NCPAINT:
+ case OS.WM_WINDOWPOSCHANGING: {
+ int bits = OS.GetWindowLong (hwnd, OS.GWL_STYLE);
+ if ((style & SWT.H_SCROLL) == 0 && (bits & OS.WS_HSCROLL) != 0) {
+ fixScroll = true;
+ bits &= ~OS.WS_HSCROLL;
+ }
+ if ((style & SWT.V_SCROLL) == 0 && (bits & OS.WS_VSCROLL) != 0) {
+ fixScroll = true;
+ bits &= ~OS.WS_VSCROLL;
+ }
+ if (fixScroll) OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+ }
+ }
+ }
+ long code = 0;
+ if (fixPaint) {
+ PAINTSTRUCT ps = new PAINTSTRUCT ();
+ long hDC = OS.BeginPaint (hwnd, ps);
+ code = OS.CallWindowProc (TableProc, hwnd, OS.WM_PAINT, hDC, lParam);
+ OS.EndPaint (hwnd, ps);
+ } else {
+ code = OS.CallWindowProc (TableProc, hwnd, msg, wParam, lParam);
+ }
+ if (fixScroll) {
+ int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE;
+ OS.RedrawWindow (handle, null, 0, flags);
+ }
+
+ if (checkActivate) ignoreActivate = false;
+ if (checkSelection) {
+ if (wasSelected || forceSelect) {
+ Event event = new Event ();
+ int index = (int)OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED);
+ if (index != -1) event.item = _getItem (index);
+ sendSelectionEvent (SWT.Selection, event, false);
+ }
+ wasSelected = oldSelected;
+ }
+ switch (msg) {
+ /* Keyboard messages */
+ case OS.WM_KEYDOWN:
+ case OS.WM_CHAR:
+ case OS.WM_IME_CHAR:
+ case OS.WM_KEYUP:
+ case OS.WM_SYSCHAR:
+ case OS.WM_SYSKEYDOWN:
+ case OS.WM_SYSKEYUP:
+ //FALL THROUGH
+
+ /* Scroll messages */
+ case OS.WM_HSCROLL:
+ case OS.WM_VSCROLL:
+ //FALL THROUGH
+
+ /* Resize messages */
+ case OS.WM_WINDOWPOSCHANGED:
+ if (redraw) {
+ OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, OS.CLR_NONE);
+ OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
+ OS.InvalidateRect (handle, null, true);
+ long hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
+ if (hwndHeader != 0) OS.InvalidateRect (hwndHeader, null, true);
+ }
+ //FALL THROUGH
+
+ /* Mouse messages */
+ case OS.WM_LBUTTONDBLCLK:
+ case OS.WM_LBUTTONDOWN:
+ case OS.WM_LBUTTONUP:
+ case OS.WM_MBUTTONDBLCLK:
+ case OS.WM_MBUTTONDOWN:
+ case OS.WM_MBUTTONUP:
+ case OS.WM_MOUSEHOVER:
+ case OS.WM_MOUSELEAVE:
+ case OS.WM_MOUSEMOVE:
+ case OS.WM_MOUSEWHEEL:
+ case OS.WM_RBUTTONDBLCLK:
+ case OS.WM_RBUTTONDOWN:
+ case OS.WM_RBUTTONUP:
+ case OS.WM_XBUTTONDBLCLK:
+ case OS.WM_XBUTTONDOWN:
+ case OS.WM_XBUTTONUP:
+ //FALL THROUGH
+
+ /* Other messages */
+ case OS.WM_SETFONT:
+ case OS.WM_TIMER: {
+ if (findImageControl () != null) {
+ if (topIndex != OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0)) {
+ OS.InvalidateRect (handle, null, true);
+ }
+ }
+ break;
+ }
+
+ case OS.WM_PAINT:
+ painted = true;
+ break;
+ }
+ return code;
+}
+
+static int checkStyle (int style) {
+ /*
+ * Feature in Windows. Even when WS_HSCROLL or
+ * WS_VSCROLL is not specified, Windows creates
+ * trees and tables with scroll bars. The fix
+ * is to set H_SCROLL and V_SCROLL.
+ *
+ * NOTE: This code appears on all platforms so that
+ * applications have consistent scroll bar behavior.
+ */
+ if ((style & SWT.NO_SCROLL) == 0) {
+ style |= SWT.H_SCROLL | SWT.V_SCROLL;
+ }
+ return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
+}
+
+LRESULT CDDS_ITEMPOSTPAINT (NMLVCUSTOMDRAW nmcd, long wParam, long lParam) {
+ long hDC = nmcd.hdc;
+ if (explorerTheme && !ignoreCustomDraw) {
+ hotIndex = -1;
+ if (hooks (SWT.EraseItem) && nmcd.left != nmcd.right) {
+ OS.RestoreDC (hDC, -1);
+ }
+ }
+ /*
+ * Bug in Windows. When the table has the extended style
+ * LVS_EX_FULLROWSELECT and LVM_SETBKCOLOR is used with
+ * CLR_NONE to make the table transparent, Windows fills
+ * a black rectangle around any column that contains an
+ * image. The fix is clear LVS_EX_FULLROWSELECT during
+ * custom draw.
+ *
+ * NOTE: Since CDIS_FOCUS is cleared during custom draw,
+ * it is necessary to draw the focus rectangle after the
+ * item has been drawn.
+ */
+ if (!ignoreCustomDraw && !ignoreDrawFocus && nmcd.left != nmcd.right) {
+ if (OS.IsWindowVisible (handle) && OS.IsWindowEnabled (handle)) {
+ if (!explorerTheme && (style & SWT.FULL_SELECTION) != 0) {
+ if ((int)OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0) == OS.CLR_NONE) {
+ int dwExStyle = (int)OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
+ if ((dwExStyle & OS.LVS_EX_FULLROWSELECT) == 0) {
+// if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
+ if (OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED) == nmcd.dwItemSpec) {
+ if (handle == OS.GetFocus ()) {
+ int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
+ if ((uiState & OS.UISF_HIDEFOCUS) == 0) {
+ RECT rect = new RECT ();
+ rect.left = OS.LVIR_BOUNDS;
+ boolean oldIgnore = ignoreCustomDraw;
+ ignoreCustomDraw = true;
+ OS.SendMessage (handle, OS. LVM_GETITEMRECT, nmcd.dwItemSpec, rect);
+ long hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
+ int index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
+ RECT itemRect = new RECT ();
+ if (index == 0) {
+ itemRect.left = OS.LVIR_LABEL;
+ OS.SendMessage (handle, OS. LVM_GETITEMRECT, index, itemRect);
+ } else {
+ itemRect.top = index;
+ itemRect.left = OS.LVIR_ICON;
+ OS.SendMessage (handle, OS. LVM_GETSUBITEMRECT, nmcd.dwItemSpec, itemRect);
+ }
+ ignoreCustomDraw = oldIgnore;
+ rect.left = itemRect.left;
+ OS.DrawFocusRect (nmcd.hdc, rect);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+}
+
+LRESULT CDDS_ITEMPREPAINT (NMLVCUSTOMDRAW nmcd, long wParam, long lParam) {
+ /*
+ * Bug in Windows. When the table has the extended style
+ * LVS_EX_FULLROWSELECT and LVM_SETBKCOLOR is used with
+ * CLR_NONE to make the table transparent, Windows fills
+ * a black rectangle around any column that contains an
+ * image. The fix is clear LVS_EX_FULLROWSELECT during
+ * custom draw.
+ *
+ * NOTE: It is also necessary to clear CDIS_FOCUS to stop
+ * the table from drawing the focus rectangle around the
+ * first item instead of the full row.
+ */
+ if (!ignoreCustomDraw) {
+ if (OS.IsWindowVisible (handle) && OS.IsWindowEnabled (handle)) {
+ if (!explorerTheme && (style & SWT.FULL_SELECTION) != 0) {
+ if ((int)OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0) == OS.CLR_NONE) {
+ int dwExStyle = (int)OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
+ if ((dwExStyle & OS.LVS_EX_FULLROWSELECT) == 0) {
+ if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
+ nmcd.uItemState &= ~OS.CDIS_FOCUS;
+ OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (explorerTheme && !ignoreCustomDraw) {
+ hotIndex = (nmcd.uItemState & OS.CDIS_HOT) != 0 ? (int)nmcd.dwItemSpec : -1;
+ if (hooks (SWT.EraseItem) && nmcd.left != nmcd.right) {
+ OS.SaveDC (nmcd.hdc);
+ long hrgn = OS.CreateRectRgn (0, 0, 0, 0);
+ OS.SelectClipRgn (nmcd.hdc, hrgn);
+ OS.DeleteObject (hrgn);
+ }
+ }
+ return new LRESULT (OS.CDRF_NOTIFYSUBITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT);
+}
+
+LRESULT CDDS_POSTPAINT (NMLVCUSTOMDRAW nmcd, long wParam, long lParam) {
+ if (ignoreCustomDraw) return null;
+ /*
+ * Bug in Windows. When the table has the extended style
+ * LVS_EX_FULLROWSELECT and LVM_SETBKCOLOR is used with
+ * CLR_NONE to make the table transparent, Windows fills
+ * a black rectangle around any column that contains an
+ * image. The fix is clear LVS_EX_FULLROWSELECT during
+ * custom draw.
+ */
+ if (--customCount == 0 && OS.IsWindowVisible (handle)) {
+ if (!explorerTheme && (style & SWT.FULL_SELECTION) != 0) {
+ if ((int)OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0) == OS.CLR_NONE) {
+ int dwExStyle = (int)OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
+ if ((dwExStyle & OS.LVS_EX_FULLROWSELECT) == 0) {
+ int bits = OS.LVS_EX_FULLROWSELECT;
+ /*
+ * Feature in Windows. When LVM_SETEXTENDEDLISTVIEWSTYLE is
+ * used to set or clear the extended style bits and the table
+ * has a tooltip, the tooltip is hidden. The fix is to clear
+ * the tooltip before setting the bits and then reset it.
+ */
+ long hwndToolTip = OS.SendMessage (handle, OS.LVM_SETTOOLTIPS, 0, 0);
+ long rgn = OS.CreateRectRgn (0, 0, 0, 0);
+ int result = OS.GetUpdateRgn (handle, rgn, true);
+ OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, bits, bits);
+ OS.ValidateRect (handle, null);
+ if (result != OS.NULLREGION) OS.InvalidateRgn (handle, rgn, true);
+ OS.DeleteObject (rgn);
+ /*
+ * Bug in Windows. Despite the documentation, LVM_SETTOOLTIPS
+ * uses WPARAM instead of LPARAM for the new tooltip The fix
+ * is to put the tooltip in both parameters.
+ */
+ hwndToolTip = OS.SendMessage (handle, OS.LVM_SETTOOLTIPS, hwndToolTip, hwndToolTip);
+ }
+ }
+ }
+ }
+ return null;
+}
+
+LRESULT CDDS_PREPAINT (NMLVCUSTOMDRAW nmcd, long wParam, long lParam) {
+ if (ignoreCustomDraw) {
+ return new LRESULT (OS.CDRF_NOTIFYITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT);
+ }
+ /*
+ * Bug in Windows. When the table has the extended style
+ * LVS_EX_FULLROWSELECT and LVM_SETBKCOLOR is used with
+ * CLR_NONE to make the table transparent, Windows fills
+ * a black rectangle around any column that contains an
+ * image. The fix is clear LVS_EX_FULLROWSELECT during
+ * custom draw.
+ */
+ if (customCount++ == 0 && OS.IsWindowVisible (handle)) {
+ if (!explorerTheme && (style & SWT.FULL_SELECTION) != 0) {
+ if ((int)OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0) == OS.CLR_NONE) {
+ int dwExStyle = (int)OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
+ if ((dwExStyle & OS.LVS_EX_FULLROWSELECT) != 0) {
+ int bits = OS.LVS_EX_FULLROWSELECT;
+ /*
+ * Feature in Windows. When LVM_SETEXTENDEDLISTVIEWSTYLE is
+ * used to set or clear the extended style bits and the table
+ * has a tooltip, the tooltip is hidden. The fix is to clear
+ * the tooltip before setting the bits and then reset it.
+ */
+ long hwndToolTip = OS.SendMessage (handle, OS.LVM_SETTOOLTIPS, 0, 0);
+ long rgn = OS.CreateRectRgn (0, 0, 0, 0);
+ int result = OS.GetUpdateRgn (handle, rgn, true);
+ OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, bits, 0);
+ OS.ValidateRect (handle, null);
+ if (result != OS.NULLREGION) OS.InvalidateRgn (handle, rgn, true);
+ OS.DeleteObject (rgn);
+ /*
+ * Bug in Windows. Despite the documentation, LVM_SETTOOLTIPS
+ * uses WPARAM instead of LPARAM for the new tooltip The fix
+ * is to put the tooltip in both parameters.
+ */
+ hwndToolTip = OS.SendMessage (handle, OS.LVM_SETTOOLTIPS, hwndToolTip, hwndToolTip);
+ }
+ }
+ }
+ }
+ if (OS.IsWindowVisible (handle)) {
+ /*
+ * Feature in Windows. On Vista using the explorer theme,
+ * Windows draws a vertical line to separate columns. When
+ * there is only a single column, the line looks strange.
+ * The fix is to draw the background using custom draw.
+ */
+ RECT rect = new RECT ();
+ OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
+ if (explorerTheme && columnCount == 0) {
+ long hDC = nmcd.hdc;
+ if (OS.IsWindowEnabled (handle) || findImageControl () != null) {
+ drawBackground (hDC, rect);
+ } else {
+ fillBackground (hDC, OS.GetSysColor (OS.COLOR_3DFACE), rect);
+ }
+ } else {
+ Control control = findBackgroundControl ();
+ if (control != null && control.backgroundImage != null) {
+ fillImageBackground (nmcd.hdc, control, rect, 0, 0);
+ } else {
+ final boolean enabled = OS.IsWindowEnabled (handle);
+ if (enabled && (int)OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0) == OS.CLR_NONE || !enabled && hasCustomBackground()) {
+ if (control == null) control = this;
+ fillBackground (nmcd.hdc, control.getBackgroundPixel (), rect);
+ if (OS.IsAppThemed ()) {
+ if (sortColumn != null && sortDirection != SWT.NONE) {
+ int index = indexOf (sortColumn);
+ if (index != -1) {
+ parent.forceResize ();
+ int clrSortBk = getSortColumnPixel ();
+ RECT columnRect = new RECT (), headerRect = new RECT ();
+ OS.GetClientRect (handle, columnRect);
+ long hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
+ if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect) != 0) {
+ OS.MapWindowPoints (hwndHeader, handle, headerRect, 2);
+ columnRect.left = headerRect.left;
+ columnRect.right = headerRect.right;
+ if (OS.IntersectRect(columnRect, columnRect, rect)) {
+ fillBackground (nmcd.hdc, clrSortBk, columnRect);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return new LRESULT (OS.CDRF_NOTIFYITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT);
+}
+
+LRESULT CDDS_SUBITEMPOSTPAINT (NMLVCUSTOMDRAW nmcd, long wParam, long lParam) {
+ if (ignoreCustomDraw) return null;
+ if (nmcd.left == nmcd.right) return new LRESULT (OS.CDRF_DODEFAULT);
+ long hDC = nmcd.hdc;
+ if (ignoreDrawForeground) OS.RestoreDC (hDC, -1);
+ if (OS.IsWindowVisible (handle)) {
+ /*
+ * Feature in Windows. When there is a sort column, the sort column
+ * color draws on top of the background color for an item. The fix
+ * is to clear the sort column in CDDS_SUBITEMPREPAINT, and reset it
+ * in CDDS_SUBITEMPOSTPAINT.
+ *
+ * Update region is saved and restored around LVM_SETSELECTEDCOLUMN
+ * to prevent infinite WM_PAINT on Vista.
+ */
+ if ((int)OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0) != OS.CLR_NONE) {
+ if ((sortDirection & (SWT.UP | SWT.DOWN)) != 0) {
+ if (sortColumn != null && !sortColumn.isDisposed ()) {
+ int oldColumn = (int)OS.SendMessage (handle, OS.LVM_GETSELECTEDCOLUMN, 0, 0);
+ if (oldColumn == -1) {
+ int newColumn = indexOf (sortColumn);
+ long rgn = OS.CreateRectRgn (0, 0, 0, 0);
+ int result = OS.GetUpdateRgn (handle, rgn, true);
+ OS.SendMessage (handle, OS.LVM_SETSELECTEDCOLUMN, newColumn, 0);
+ OS.ValidateRect (handle, null);
+ if (result != OS.NULLREGION) OS.InvalidateRgn (handle, rgn, true);
+ OS.DeleteObject (rgn);
+ }
+ }
+ }
+ }
+ if (hooks (SWT.PaintItem)) {
+ TableItem item = _getItem ((int)nmcd.dwItemSpec);
+ sendPaintItemEvent (item, nmcd);
+ //widget could be disposed at this point
+ }
+ if (!ignoreDrawFocus && focusRect != null) {
+ OS.SetTextColor (nmcd.hdc, 0);
+ OS.SetBkColor (nmcd.hdc, 0xFFFFFF);
+ OS.DrawFocusRect (nmcd.hdc, focusRect);
+ focusRect = null;
+ }
+ }
+ return null;
+}
+
+LRESULT CDDS_SUBITEMPREPAINT (NMLVCUSTOMDRAW nmcd, long wParam, long lParam) {
+ long hDC = nmcd.hdc;
+ if (explorerTheme && !ignoreCustomDraw && hooks (SWT.EraseItem) && (nmcd.left != nmcd.right)) {
+ OS.RestoreDC (hDC, -1);
+ }
+ /*
+ * Feature in Windows. When a new table item is inserted
+ * using LVM_INSERTITEM in a table that is transparent
+ * (ie. LVM_SETBKCOLOR has been called with CLR_NONE),
+ * TVM_INSERTITEM calls NM_CUSTOMDRAW before the new item
+ * has been added to the array. The fix is to check for
+ * null.
+ *
+ * NOTE: Force the item to be created if it does not exist.
+ */
+ TableItem item = _getItem ((int)nmcd.dwItemSpec);
+ if (item == null || item.isDisposed ()) return null;
+ long hFont = item.fontHandle (nmcd.iSubItem);
+ if (hFont != -1) OS.SelectObject (hDC, hFont);
+ if (ignoreCustomDraw || (nmcd.left == nmcd.right)) {
+ return new LRESULT (hFont == -1 ? OS.CDRF_DODEFAULT : OS.CDRF_NEWFONT);
+ }
+ int code = OS.CDRF_DODEFAULT;
+ selectionForeground = -1;
+ ignoreDrawForeground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawBackground = false;
+ if (OS.IsWindowVisible (handle)) {
+ Event measureEvent = null;
+ if (hooks (SWT.MeasureItem)) {
+ measureEvent = sendMeasureItemEvent (item, (int)nmcd.dwItemSpec, nmcd.iSubItem, nmcd.hdc);
+ if (isDisposed () || item.isDisposed ()) return null;
+ }
+ if (hooks (SWT.EraseItem)) {
+ sendEraseItemEvent (item, nmcd, lParam, measureEvent);
+ if (isDisposed () || item.isDisposed ()) return null;
+ code |= OS.CDRF_NOTIFYPOSTPAINT;
+ }
+ if (ignoreDrawForeground || hooks (SWT.PaintItem)) code |= OS.CDRF_NOTIFYPOSTPAINT;
+ }
+ int clrText = item.cellForeground != null ? item.cellForeground [nmcd.iSubItem] : -1;
+ if (clrText == -1) clrText = item.foreground;
+ int clrTextBk = item.cellBackground != null ? item.cellBackground [nmcd.iSubItem] : -1;
+ if (clrTextBk == -1) clrTextBk = item.background;
+ if (selectionForeground != -1) clrText = selectionForeground;
+ /*
+ * Bug in Windows. When the table has the extended style
+ * LVS_EX_FULLROWSELECT and LVM_SETBKCOLOR is used with
+ * CLR_NONE to make the table transparent, Windows draws
+ * a black rectangle around any column that contains an
+ * image. The fix is emulate LVS_EX_FULLROWSELECT by
+ * drawing the selection.
+ */
+ final boolean enabled = OS.IsWindowEnabled (handle);
+ if (OS.IsWindowVisible (handle) && enabled) {
+ if (!explorerTheme && !ignoreDrawSelection && (style & SWT.FULL_SELECTION) != 0) {
+ int bits = (int)OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
+ if ((bits & OS.LVS_EX_FULLROWSELECT) == 0) {
+ /*
+ * Bug in Windows. For some reason, CDIS_SELECTED always set,
+ * even for items that are not selected. The fix is to get
+ * the selection state from the item.
+ */
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_STATE;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ lvItem.iItem = (int)nmcd.dwItemSpec;
+ long result = OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
+ if ((result != 0 && (lvItem.state & OS.LVIS_SELECTED) != 0)) {
+ int clrSelection = -1;
+ if (nmcd.iSubItem == 0) {
+ if (OS.GetFocus () == handle || display.getHighContrast ()) {
+ clrSelection = OS.GetSysColor (OS.COLOR_HIGHLIGHT);
+ } else {
+ if ((style & SWT.HIDE_SELECTION) == 0) {
+ clrSelection = OS.GetSysColor (OS.COLOR_3DFACE);
+ }
+ }
+ } else {
+ if (OS.GetFocus () == handle || display.getHighContrast ()) {
+ clrText = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
+ clrTextBk = clrSelection = OS.GetSysColor (OS.COLOR_HIGHLIGHT);
+ } else {
+ if ((style & SWT.HIDE_SELECTION) == 0) {
+ clrTextBk = clrSelection = OS.GetSysColor (OS.COLOR_3DFACE);
+ }
+ }
+ }
+ if (clrSelection != -1) {
+ RECT rect = item.getBounds ((int)nmcd.dwItemSpec, nmcd.iSubItem, true, nmcd.iSubItem != 0, true, false, hDC);
+ fillBackground (hDC, clrSelection, rect);
+ }
+ }
+ }
+ }
+ }
+ if (!ignoreDrawForeground) {
+ /*
+ * Bug in Windows. When the attributes are for one cell in a table,
+ * Windows does not reset them for the next cell. As a result, all
+ * subsequent cells are drawn using the previous font, foreground and
+ * background colors. The fix is to set the all attributes when any
+ * attribute could have changed.
+ */
+ boolean hasAttributes = true;
+ if (hFont == -1 && clrText == -1 && clrTextBk == -1) {
+ if (item.cellForeground == null && item.cellBackground == null && item.cellFont == null) {
+ int count = (int)OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
+ if (count == 1) hasAttributes = false;
+ }
+ }
+ if (hasAttributes) {
+ if (hFont == -1) hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ OS.SelectObject (hDC, hFont);
+ if (enabled) {
+ nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText;
+ if (clrTextBk == -1) {
+ nmcd.clrTextBk = OS.CLR_NONE;
+ if (selectionForeground == -1) {
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ if (control.backgroundImage == null) {
+ if ((int)OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0) != OS.CLR_NONE) {
+ nmcd.clrTextBk = control.getBackgroundPixel ();
+ }
+ }
+ }
+ } else {
+ nmcd.clrTextBk = selectionForeground != -1 ? OS.CLR_NONE : clrTextBk;
+ }
+ OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof);
+ }
+ code |= OS.CDRF_NEWFONT;
+ }
+ }
+ /*
+ * Feature in Windows. When there is a sort column, the sort column
+ * color draws on top of the background color for an item. The fix
+ * is to clear the sort column in CDDS_SUBITEMPREPAINT, and reset it
+ * in CDDS_SUBITEMPOSTPAINT.
+ *
+ * Update region is saved and restored around LVM_SETSELECTEDCOLUMN
+ * to prevent infinite WM_PAINT on Vista.
+ */
+ if ((enabled && clrTextBk != -1) || (!enabled && hasCustomBackground())) {
+ int oldColumn = (int)OS.SendMessage (handle, OS.LVM_GETSELECTEDCOLUMN, 0, 0);
+ if (oldColumn != -1 && oldColumn == nmcd.iSubItem) {
+ long rgn = OS.CreateRectRgn (0, 0, 0, 0);
+ int result = OS.GetUpdateRgn (handle, rgn, true);
+ OS.SendMessage (handle, OS.LVM_SETSELECTEDCOLUMN, -1, 0);
+ OS.ValidateRect (handle, null);
+ if (result != OS.NULLREGION) OS.InvalidateRgn (handle, rgn, true);
+ OS.DeleteObject (rgn);
+ code |= OS.CDRF_NOTIFYPOSTPAINT;
+ }
+ }
+ if (!enabled) {
+ /*
+ * Feature in Windows. When the table is disabled, it draws
+ * with a gray background but does not gray the text. The fix
+ * is to explicitly gray the text, but only, when it wasn't customized.
+ */
+ nmcd.clrText = OS.GetSysColor (OS.COLOR_GRAYTEXT);
+ if (findImageControl () != null || hasCustomBackground()) {
+ nmcd.clrTextBk = OS.CLR_NONE;
+ }
+ nmcd.uItemState &= ~OS.CDIS_SELECTED;
+ OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof);
+ code |= OS.CDRF_NEWFONT;
+ }
+ return new LRESULT (code);
+}
+
+@Override
+void checkBuffered () {
+ super.checkBuffered ();
+ style |= SWT.DOUBLE_BUFFERED;
+}
+
+boolean checkData (TableItem item, boolean redraw) {
+ if ((style & SWT.VIRTUAL) == 0) return true;
+ return checkData (item, indexOf (item), redraw);
+}
+
+boolean checkData (TableItem item, int index, boolean redraw) {
+ if ((style & SWT.VIRTUAL) == 0) return true;
+ if (!item.cached) {
+ item.cached = true;
+ Event event = new Event ();
+ event.item = item;
+ event.index = index;
+ currentItem = item;
+ sendEvent (SWT.SetData, event);
+ //widget could be disposed at this point
+ currentItem = null;
+ if (isDisposed () || item.isDisposed ()) return false;
+ if (redraw) {
+ if (!setScrollWidth (item, false)) {
+ item.redraw ();
+ }
+ }
+ }
+ return true;
+}
+
+@Override
+boolean checkHandle (long hwnd) {
+ if (hwnd == handle) return true;
+ return hwnd == OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
+}
+
+@Override
+protected void checkSubclass () {
+ if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+/**
+ * Clears the item at the given zero-relative index in the receiver.
+ * The text, icon and other attributes of the item are set to the default
+ * value. If the table was created with the SWT.VIRTUAL
style,
+ * these attributes are requested again as needed.
+ *
+ * @param index the index of the item to clear
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.0
+ */
+public void clear (int index) {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
+ TableItem item = _getItem (index, false);
+ if (item != null) {
+ if (item != currentItem) item.clear ();
+ /*
+ * Bug in Windows. Despite the fact that every item in the
+ * table always has LPSTR_TEXTCALLBACK, Windows caches the
+ * bounds for the selected items. This means that
+ * when you change the string to be something else, Windows
+ * correctly asks you for the new string but when the item
+ * is selected, the selection draws using the bounds of the
+ * previous item. The fix is to reset LPSTR_TEXTCALLBACK
+ * even though it has not changed, causing Windows to flush
+ * cached bounds.
+ */
+ if ((style & SWT.VIRTUAL) == 0 && item.cached) {
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_TEXT | OS.LVIF_INDENT;
+ lvItem.pszText = OS.LPSTR_TEXTCALLBACK;
+ lvItem.iItem = index;
+ OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
+ item.cached = false;
+ }
+ if (currentItem == null && getDrawing () && OS.IsWindowVisible (handle)) {
+ OS.SendMessage (handle, OS.LVM_REDRAWITEMS, index, index);
+ }
+ setScrollWidth (item, false);
+ }
+}
+
+/**
+ * Removes the items from the receiver which are between the given
+ * zero-relative start and end indices (inclusive). The text, icon
+ * and other attributes of the items are set to their default values.
+ * If the table was created with the SWT.VIRTUAL
style,
+ * these attributes are requested again as needed.
+ *
+ * @param start the start index of the item to clear
+ * @param end the end index of the item to clear
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.0
+ */
+public void clear (int start, int end) {
+ checkWidget ();
+ if (start > end) return;
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (!(0 <= start && start <= end && end < count)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ if (start == 0 && end == count - 1) {
+ clearAll ();
+ } else {
+ LVITEM lvItem = null;
+ boolean cleared = false;
+ for (int i=start; i<=end; i++) {
+ TableItem item = _getItem (i, false);
+ if (item != null) {
+ if (item != currentItem) {
+ cleared = true;
+ item.clear ();
+ }
+ /*
+ * Bug in Windows. Despite the fact that every item in the
+ * table always has LPSTR_TEXTCALLBACK, Windows caches the
+ * bounds for the selected items. This means that
+ * when you change the string to be something else, Windows
+ * correctly asks you for the new string but when the item
+ * is selected, the selection draws using the bounds of the
+ * previous item. The fix is to reset LPSTR_TEXTCALLBACK
+ * even though it has not changed, causing Windows to flush
+ * cached bounds.
+ */
+ if ((style & SWT.VIRTUAL) == 0 && item.cached) {
+ if (lvItem == null) {
+ lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_TEXT | OS.LVIF_INDENT;
+ lvItem.pszText = OS.LPSTR_TEXTCALLBACK;
+ }
+ lvItem.iItem = i;
+ OS.SendMessage (handle, OS.LVM_SETITEM, 0, lvItem);
+ item.cached = false;
+ }
+ }
+ }
+ if (cleared) {
+ if (currentItem == null && getDrawing () && OS.IsWindowVisible (handle)) {
+ OS.SendMessage (handle, OS.LVM_REDRAWITEMS, start, end);
+ }
+ TableItem item = start == end ? _getItem (start, false) : null;
+ setScrollWidth (item, false);
+ }
+ }
+}
+
+/**
+ * Clears the items at the given zero-relative indices in the receiver.
+ * The text, icon and other attributes of the items are set to their default
+ * values. If the table was created with the SWT.VIRTUAL
style,
+ * these attributes are requested again as needed.
+ *
+ * @param indices the array of indices of the items
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.0
+ */
+public void clear (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (indices.length == 0) return;
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ for (int i=0; i
+ *
+ *
+ * @see SWT#VIRTUAL
+ * @see SWT#SetData
+ *
+ * @since 3.0
+ */
+public void clearAll () {
+ checkWidget ();
+ LVITEM lvItem = null;
+ boolean cleared = false;
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ for (int i=0; i
+ *
+ */
+public void deselect (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (indices.length == 0) return;
+ LVITEM lvItem = new LVITEM ();
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ for (int i=0; i
+ *
+ */
+public void deselect (int index) {
+ checkWidget ();
+ /*
+ * An index of -1 will apply the change to all
+ * items. Ensure that index is greater than -1.
+ */
+ if (index < 0) return;
+ LVITEM lvItem = new LVITEM ();
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ ignoreSelect = true;
+ OS.SendMessage (handle, OS.LVM_SETITEMSTATE, index, lvItem);
+ ignoreSelect = false;
+}
+
+/**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver
+ * is selected, it is deselected. If the item at the index
+ * was not selected, it remains deselected. The range of the
+ * indices is inclusive. Indices that are out of range are ignored.
+ *
+ * @param start the start index of the items to deselect
+ * @param end the end index of the items to deselect
+ *
+ * @exception SWTException
+ *
+ */
+public void deselect (int start, int end) {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (start == 0 && end == count - 1) {
+ deselectAll ();
+ } else {
+ LVITEM lvItem = new LVITEM ();
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ /*
+ * An index of -1 will apply the change to all
+ * items. Ensure that indices are greater than -1.
+ */
+ start = Math.max (0, start);
+ for (int i=start; i<=end; i++) {
+ ignoreSelect = true;
+ OS.SendMessage (handle, OS.LVM_SETITEMSTATE, i, lvItem);
+ ignoreSelect = false;
+ }
+ }
+}
+
+/**
+ * Deselects all selected items in the receiver.
+ *
+ * @exception SWTException
+ *
+ */
+public void deselectAll () {
+ checkWidget ();
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_STATE;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ ignoreSelect = true;
+ OS.SendMessage (handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+ ignoreSelect = false;
+}
+
+void destroyItem (TableColumn column) {
+ int index = 0;
+ while (index < columnCount) {
+ if (columns [index] == column) break;
+ index++;
+ }
+ int oldColumn = (int)OS.SendMessage (handle, OS.LVM_GETSELECTEDCOLUMN, 0, 0);
+ if (oldColumn == index) {
+ OS.SendMessage (handle, OS.LVM_SETSELECTEDCOLUMN, -1, 0);
+ } else {
+ if (oldColumn > index) {
+ OS.SendMessage (handle, OS.LVM_SETSELECTEDCOLUMN, oldColumn - 1, 0);
+ }
+ }
+ int orderIndex = 0;
+ int [] oldOrder = new int [columnCount];
+ OS.SendMessage (handle, OS.LVM_GETCOLUMNORDERARRAY, columnCount, oldOrder);
+ while (orderIndex < columnCount) {
+ if (oldOrder [orderIndex] == index) break;
+ orderIndex++;
+ }
+ ignoreColumnResize = true;
+ boolean first = false;
+ if (index == 0) {
+ first = true;
+ /*
+ * Changing the content of a column using LVM_SETCOLUMN causes
+ * the table control to send paint events. At this point the
+ * partially disposed column is still part of the table and
+ * paint handler can try to access it. This can cause exceptions.
+ * The fix is to turn redraw off.
+ */
+ setRedraw (false);
+ if (columnCount > 1) {
+ index = 1;
+ int cchTextMax = 1024;
+ long hHeap = OS.GetProcessHeap ();
+ int byteCount = cchTextMax * TCHAR.sizeof;
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
+ LVCOLUMN lvColumn = new LVCOLUMN ();
+ lvColumn.mask = OS.LVCF_TEXT | OS.LVCF_IMAGE | OS.LVCF_WIDTH | OS.LVCF_FMT;
+ lvColumn.pszText = pszText;
+ lvColumn.cchTextMax = cchTextMax;
+ OS.SendMessage (handle, OS.LVM_GETCOLUMN, 1, lvColumn);
+ lvColumn.fmt &= ~(OS.LVCFMT_CENTER | OS.LVCFMT_RIGHT);
+ lvColumn.fmt |= OS.LVCFMT_LEFT;
+ OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn);
+ if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
+ } else {
+ long hHeap = OS.GetProcessHeap ();
+ long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof);
+ LVCOLUMN lvColumn = new LVCOLUMN ();
+ lvColumn.mask = OS.LVCF_TEXT | OS.LVCF_IMAGE | OS.LVCF_WIDTH | OS.LVCF_FMT;
+ lvColumn.pszText = pszText;
+ lvColumn.iImage = OS.I_IMAGENONE;
+ lvColumn.fmt = OS.LVCFMT_LEFT;
+ OS.SendMessage (handle, OS.LVM_SETCOLUMN, 0, lvColumn);
+ if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
+ HDITEM hdItem = new HDITEM ();
+ hdItem.mask = OS.HDI_FORMAT;
+ hdItem.fmt = OS.HDF_LEFT;
+ long hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
+ OS.SendMessage (hwndHeader, OS.HDM_SETITEM, index, hdItem);
+ }
+ setRedraw (true);
+ /*
+ * Bug in Windows. Despite the fact that every item in the
+ * table always has LPSTR_TEXTCALLBACK, Windows caches the
+ * bounds for the selected items. This means that
+ * when you change the string to be something else, Windows
+ * correctly asks you for the new string but when the item
+ * is selected, the selection draws using the bounds of the
+ * previous item. The fix is to reset LPSTR_TEXTCALLBACK
+ * even though it has not changed, causing Windows to flush
+ * cached bounds.
+ */
+ if ((style & SWT.VIRTUAL) == 0) {
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_TEXT | OS.LVIF_IMAGE;
+ lvItem.pszText = OS.LPSTR_TEXTCALLBACK;
+ lvItem.iImage = OS.I_IMAGECALLBACK;
+ int itemCount = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ for (int i=0; iERROR_INVALID_RANGE
despite
+ * the fact that a single column of data may be visible in the table.
+ * This occurs when the programmer uses the table like a list, adding
+ * items but never creating a column.
+ *
+ * @param index the index of the column to return
+ * @return the column at the given index
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Table#getColumnOrder()
+ * @see Table#setColumnOrder(int[])
+ * @see TableColumn#getMoveable()
+ * @see TableColumn#setMoveable(boolean)
+ * @see SWT#Move
+ */
+public TableColumn getColumn (int index) {
+ checkWidget ();
+ if (!(0 <= index && index < columnCount)) error (SWT.ERROR_INVALID_RANGE);
+ return columns [index];
+}
+
+/**
+ * Returns the number of columns contained in the receiver.
+ * If no TableColumn
s were created by the programmer,
+ * this value is zero, despite the fact that visually, one column
+ * of items may be visible. This occurs when the programmer uses
+ * the table like a list, adding items but never creating a column.
+ *
+ * @return the number of columns
+ *
+ * @exception SWTException
+ *
+ */
+public int getColumnCount () {
+ checkWidget ();
+ return columnCount;
+}
+
+/**
+ * Returns an array of zero-relative integers that map
+ * the creation order of the receiver's items to the
+ * order in which they are currently being displayed.
+ *
+ *
+ *
+ * @see Table#setColumnOrder(int[])
+ * @see TableColumn#getMoveable()
+ * @see TableColumn#setMoveable(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.1
+ */
+public int[] getColumnOrder () {
+ checkWidget ();
+ if (columnCount == 0) return new int [0];
+ int [] order = new int [columnCount];
+ OS.SendMessage (handle, OS.LVM_GETCOLUMNORDERARRAY, columnCount, order);
+ return order;
+}
+
+/**
+ * Returns an array of TableColumn
s which are the
+ * columns in the receiver. Columns are returned in the order
+ * that they were created. If no TableColumn
s were
+ * created by the programmer, the array is empty, despite the fact
+ * that visually, one column of items may be visible. This occurs
+ * when the programmer uses the table like a list, adding items but
+ * never creating a column.
+ *
+ *
+ *
+ * @see Table#getColumnOrder()
+ * @see Table#setColumnOrder(int[])
+ * @see TableColumn#getMoveable()
+ * @see TableColumn#setMoveable(boolean)
+ * @see SWT#Move
+ */
+public TableColumn [] getColumns () {
+ checkWidget ();
+ TableColumn [] result = new TableColumn [columnCount];
+ System.arraycopy (columns, 0, result, 0, columnCount);
+ return result;
+}
+
+int getFocusIndex () {
+// checkWidget ();
+ return (int)OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED);
+}
+
+/**
+ * Returns the width in points of a grid line.
+ *
+ * @return the width of a grid line in points
+ *
+ * @exception SWTException
+ *
+ */
+public int getGridLineWidth () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getGridLineWidthInPixels());
+}
+
+int getGridLineWidthInPixels () {
+ return GRID_WIDTH;
+}
+
+/**
+ * Returns the header background color.
+ *
+ * @return the receiver's header background color.
+ *
+ * @exception SWTException
+ *
+ * @since 3.106
+ */
+public Color getHeaderBackground () {
+ checkWidget ();
+ return Color.win32_new (display, getHeaderBackgroundPixel());
+}
+
+private int getHeaderBackgroundPixel() {
+ return headerBackground != -1 ? headerBackground : defaultBackground();
+}
+
+/**
+ * Returns the header foreground color.
+ *
+ * @return the receiver's header foreground color.
+ *
+ * @exception SWTException
+ *
+ * @since 3.106
+ */
+public Color getHeaderForeground () {
+ checkWidget ();
+ return Color.win32_new (display, getHeaderForegroundPixel());
+}
+
+private int getHeaderForegroundPixel() {
+ return headerForeground != -1 ? headerForeground : defaultForeground();
+}
+
+/**
+ * Returns the height of the receiver's header
+ *
+ * @return the height of the header or zero if the header is not visible
+ *
+ * @exception SWTException
+ *
+ *
+ * @since 2.0
+ */
+public int getHeaderHeight () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getHeaderHeightInPixels ());
+}
+
+int getHeaderHeightInPixels () {
+ if (hwndHeader == 0) return 0;
+ RECT rect = new RECT ();
+ OS.GetWindowRect (hwndHeader, rect);
+ return rect.bottom - rect.top;
+}
+
+/**
+ * Returns true
if the receiver's header is visible,
+ * and false
otherwise.
+ *
+ *
+ */
+public boolean getHeaderVisible () {
+ checkWidget ();
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ return (bits & OS.LVS_NOCOLUMNHEADER) == 0;
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public TableItem getItem (int index) {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
+ return _getItem (index);
+}
+
+/**
+ * Returns the item at the given point in the receiver
+ * or null if no such item exists. The point is in the
+ * coordinate system of the receiver.
+ *
+ *
+ * @exception SWTException
+ *
+ */
+public TableItem getItem (Point point) {
+ checkWidget ();
+ if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+ return getItemInPixels (DPIUtil.autoScaleUp(point));
+}
+
+TableItem getItemInPixels (Point point) {
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (count == 0) return null;
+ LVHITTESTINFO pinfo = new LVHITTESTINFO ();
+ pinfo.x = point.x;
+ pinfo.y = point.y;
+ if ((style & SWT.FULL_SELECTION) == 0) {
+ if (hooks (SWT.MeasureItem)) {
+ /*
+ * Bug in Windows. When LVM_SUBITEMHITTEST is used to hittest
+ * a point that is above the table, instead of returning -1 to
+ * indicate that the hittest failed, a negative index is returned.
+ * The fix is to consider any value that is negative a failure.
+ */
+ if (OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, pinfo) < 0) {
+ RECT rect = new RECT ();
+ rect.left = OS.LVIR_ICON;
+ ignoreCustomDraw = true;
+ long code = OS.SendMessage (handle, OS.LVM_GETITEMRECT, 0, rect);
+ ignoreCustomDraw = false;
+ if (code != 0) {
+ pinfo.x = rect.left;
+ /*
+ * Bug in Windows. When LVM_SUBITEMHITTEST is used to hittest
+ * a point that is above the table, instead of returning -1 to
+ * indicate that the hittest failed, a negative index is returned.
+ * The fix is to consider any value that is negative a failure.
+ */
+ OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, pinfo);
+ if (pinfo.iItem < 0) pinfo.iItem = -1;
+ }
+ }
+ if (pinfo.iItem != -1 && pinfo.iSubItem == 0) {
+ if (hitTestSelection (pinfo.iItem, pinfo.x, pinfo.y)) {
+ return _getItem (pinfo.iItem);
+ }
+ }
+ return null;
+ }
+ }
+ OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo);
+ if (pinfo.iItem != -1) {
+ /*
+ * Bug in Windows. When the point that is used by
+ * LVM_HITTEST is inside the header, Windows returns
+ * the first item in the table. The fix is to check
+ * when LVM_HITTEST returns the first item and make
+ * sure that when the point is within the header,
+ * the first item is not returned.
+ */
+ if (pinfo.iItem == 0) {
+ int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+ if ((bits & OS.LVS_NOCOLUMNHEADER) == 0) {
+ if (hwndHeader != 0) {
+ RECT rect = new RECT ();
+ OS.GetWindowRect (hwndHeader, rect);
+ POINT pt = new POINT ();
+ pt.x = pinfo.x;
+ pt.y = pinfo.y;
+ OS.MapWindowPoints (handle, 0, pt, 1);
+ if (OS.PtInRect (rect, pt)) return null;
+ }
+ }
+ }
+ return _getItem (pinfo.iItem);
+ }
+ return null;
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemCount () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+}
+
+/**
+ * Returns the height of the area which would be used to
+ * display one of the items in the receiver.
+ *
+ * @return the height of one item
+ *
+ * @exception SWTException
+ *
+ */
+public int getItemHeight () {
+ checkWidget ();
+ return DPIUtil.autoScaleDown(getItemHeightInPixels());
+}
+
+int getItemHeightInPixels () {
+ if (!painted && hooks (SWT.MeasureItem)) hitTestSelection (0, 0, 0);
+ long empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0);
+ long oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0);
+ return OS.HIWORD (oneItem) - OS.HIWORD (empty);
+}
+
+/**
+ * Returns a (possibly empty) array of TableItem
s which
+ * are the items in the receiver.
+ *
+ *
+ */
+public TableItem [] getItems () {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ TableItem [] result = new TableItem [count];
+ if ((style & SWT.VIRTUAL) != 0) {
+ for (int i=0; ifalse
otherwise. Note that some platforms draw
+ * grid lines while others may draw alternating row colors.
+ *
+ *
+ */
+public boolean getLinesVisible () {
+ checkWidget ();
+ return _getLinesVisible();
+}
+
+private boolean _getLinesVisible() {
+ int bits = (int)OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
+ return (bits & OS.LVS_EX_GRIDLINES) != 0;
+}
+
+/**
+ * Returns an array of TableItem
s that are currently
+ * selected in the receiver. The order of the items is unspecified.
+ * An empty array indicates that no items are selected.
+ *
+ *
+ */
+public TableItem [] getSelection () {
+ checkWidget ();
+ int i = -1, j = 0, count = (int)OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0);
+ TableItem [] result = new TableItem [count];
+ while ((i = (int)OS.SendMessage (handle, OS.LVM_GETNEXTITEM, i, OS.LVNI_SELECTED)) != -1) {
+ result [j++] = _getItem (i);
+ }
+ return result;
+}
+
+/**
+ * Returns the number of selected items contained in the receiver.
+ *
+ * @return the number of selected items
+ *
+ * @exception SWTException
+ *
+ */
+public int getSelectionCount () {
+ checkWidget ();
+ return (int)OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0);
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * selected in the receiver, or -1 if no item is selected.
+ *
+ * @return the index of the selected item
+ *
+ * @exception SWTException
+ *
+ */
+public int getSelectionIndex () {
+ checkWidget ();
+ int focusIndex = (int)OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED);
+ int selectedIndex = (int)OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_SELECTED);
+ if (focusIndex == selectedIndex) return selectedIndex;
+ int i = -1;
+ while ((i = (int)OS.SendMessage (handle, OS.LVM_GETNEXTITEM, i, OS.LVNI_SELECTED)) != -1) {
+ if (i == focusIndex) return i;
+ }
+ return selectedIndex;
+}
+
+/**
+ * Returns the zero-relative indices of the items which are currently
+ * selected in the receiver. The order of the indices is unspecified.
+ * The array is empty if no items are selected.
+ *
+ *
+ */
+public int [] getSelectionIndices () {
+ checkWidget ();
+ int i = -1, j = 0, count = (int)OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0);
+ int [] result = new int [count];
+ while ((i = (int)OS.SendMessage (handle, OS.LVM_GETNEXTITEM, i, OS.LVNI_SELECTED)) != -1) {
+ result [j++] = i;
+ }
+ return result;
+}
+
+/**
+ * Returns the column which shows the sort indicator for
+ * the receiver. The value may be null if no column shows
+ * the sort indicator.
+ *
+ * @return the sort indicator
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #setSortColumn(TableColumn)
+ *
+ * @since 3.2
+ */
+public TableColumn getSortColumn () {
+ checkWidget ();
+ return sortColumn;
+}
+
+int getSortColumnPixel () {
+ int pixel = OS.IsWindowEnabled (handle) || hasCustomBackground() ? getBackgroundPixel () : OS.GetSysColor (OS.COLOR_3DFACE);
+ return getSlightlyDifferentBackgroundColor(pixel);
+}
+
+/**
+ * Returns the direction of the sort indicator for the receiver.
+ * The value will be one of UP
, DOWN
+ * or NONE
.
+ *
+ * @return the sort direction
+ *
+ * @exception SWTException
+ *
+ *
+ * @see #setSortDirection(int)
+ *
+ * @since 3.2
+ */
+public int getSortDirection () {
+ checkWidget ();
+ return sortDirection;
+}
+
+/**
+ * Returns the zero-relative index of the item which is currently
+ * at the top of the receiver. This index can change when items are
+ * scrolled or new items are added or removed.
+ *
+ * @return the index of the top item
+ *
+ * @exception SWTException
+ *
+ */
+public int getTopIndex () {
+ checkWidget ();
+ /*
+ * Bug in Windows. Under rare circumstances, LVM_GETTOPINDEX
+ * can return a negative number. When this happens, the table
+ * is displaying blank lines at the top of the controls. The
+ * fix is to check for a negative number and return zero instead.
+ */
+ return Math.max (0, (int)OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0));
+}
+
+boolean hasChildren () {
+ long hwndChild = OS.GetWindow (handle, OS.GW_CHILD);
+ while (hwndChild != 0) {
+ if (hwndChild != hwndHeader) return true;
+ hwndChild = OS.GetWindow (hwndChild, OS.GW_HWNDNEXT);
+ }
+ return false;
+}
+
+boolean hitTestSelection (int index, int x, int y) {
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (count == 0) return false;
+ if (!hooks (SWT.MeasureItem)) return false;
+ boolean result = false;
+ if (0 <= index && index < count) {
+ TableItem item = _getItem (index);
+ long hDC = OS.GetDC (handle);
+ long oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+ if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
+ long hFont = item.fontHandle (0);
+ if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
+ Event event = sendMeasureItemEvent (item, index, 0, hDC);
+ if (event.getBoundsInPixels ().contains (x, y)) result = true;
+ if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
+ if (newFont != 0) OS.SelectObject (hDC, oldFont);
+ OS.ReleaseDC (handle, hDC);
+// if (isDisposed () || item.isDisposed ()) return false;
+ }
+ return result;
+}
+
+int imageIndex (Image image, int column) {
+ if (image == null) return OS.I_IMAGENONE;
+ if (column == 0) {
+ firstColumnImage = true;
+ } else {
+ setSubImagesVisible (true);
+ }
+ if (imageList == null) {
+ Rectangle bounds = image.getBoundsInPixels ();
+ imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
+ int index = imageList.indexOf (image);
+ if (index == -1) index = imageList.add (image);
+ long hImageList = imageList.getHandle ();
+ /*
+ * Bug in Windows. Making any change to an item that
+ * changes the item height of a table while the table
+ * is scrolled can cause the lines to draw incorrectly.
+ * This happens even when the lines are not currently
+ * visible and are shown afterwards. The fix is to
+ * save the top index, scroll to the top of the table
+ * and then restore the original top index.
+ */
+ int topIndex = getTopIndex ();
+ if (topIndex != 0) {
+ setRedraw (false);
+ setTopIndex (0);
+ }
+ OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, hImageList);
+ if (headerImageList != null) {
+ long hHeaderImageList = headerImageList.getHandle ();
+ OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, hHeaderImageList);
+ }
+ fixCheckboxImageList (false);
+ setItemHeight (false);
+ if (topIndex != 0) {
+ setTopIndex (topIndex);
+ setRedraw (true);
+ }
+ return index;
+ }
+ int index = imageList.indexOf (image);
+ if (index != -1) return index;
+ return imageList.add (image);
+}
+
+int imageIndexHeader (Image image) {
+ if (image == null) return OS.I_IMAGENONE;
+ if (headerImageList == null) {
+ Rectangle bounds = image.getBoundsInPixels ();
+ headerImageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
+ int index = headerImageList.indexOf (image);
+ if (index == -1) index = headerImageList.add (image);
+ long hImageList = headerImageList.getHandle ();
+ OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, hImageList);
+ return index;
+ }
+ int index = headerImageList.indexOf (image);
+ if (index != -1) return index;
+ return headerImageList.add (image);
+}
+
+/**
+ * Searches the receiver's list starting at the first column
+ * (index 0) until a column is found that is equal to the
+ * argument, and returns the index of that column. If no column
+ * is found, returns -1.
+ *
+ * @param column the search column
+ * @return the index of the column
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public int indexOf (TableColumn column) {
+ checkWidget ();
+ if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
+ for (int i=0; i
+ *
+ */
+public int indexOf (TableItem item) {
+ checkWidget ();
+ if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
+ //TODO - find other loops that can be optimized
+ if (keys == null) {
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (1 <= lastIndexOf && lastIndexOf < count - 1) {
+ if (_getItem (lastIndexOf, false) == item) return lastIndexOf;
+ if (_getItem (lastIndexOf + 1, false) == item) return ++lastIndexOf;
+ if (_getItem (lastIndexOf - 1, false) == item) return --lastIndexOf;
+ }
+ if (lastIndexOf < count / 2) {
+ for (int i=0; ifalse
otherwise. Indices out of
+ * range are ignored.
+ *
+ * @param index the index of the item
+ * @return the selection state of the item at the index
+ *
+ * @exception SWTException
+ *
+ */
+public boolean isSelected (int index) {
+ checkWidget ();
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_STATE;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ lvItem.iItem = index;
+ long result = OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
+ return (result != 0) && ((lvItem.state & OS.LVIS_SELECTED) != 0);
+}
+
+@Override
+void register () {
+ super.register ();
+ if (hwndHeader != 0) display.addControl (hwndHeader, this);
+}
+
+@Override
+void releaseChildren (boolean destroy) {
+ if (_hasItems ()) {
+ int itemCount = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (keys == null) {
+ for (int i=0; i
+ *
+ */
+public void remove (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (indices.length == 0) return;
+ int [] newIndices = new int [indices.length];
+ System.arraycopy (indices, 0, newIndices, 0, indices.length);
+ sort (newIndices);
+ int start = newIndices [newIndices.length - 1], end = newIndices [0];
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (!(0 <= start && start <= end && end < count)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ setDeferResize (true);
+ int last = -1;
+ for (int i=0; i
+ *
+ */
+public void remove (int index) {
+ checkWidget ();
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
+ TableItem item = _getItem (index, false);
+ if (item != null && !item.isDisposed ()) item.release (false);
+ setDeferResize (true);
+ ignoreSelect = ignoreShrink = true;
+ long code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0);
+ ignoreSelect = ignoreShrink = false;
+ if (code == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
+ _removeItem (index, count);
+ --count;
+ if (count == 0) setTableEmpty ();
+ setDeferResize (false);
+}
+
+/**
+ * Removes the items from the receiver which are
+ * between the given zero-relative start and end
+ * indices (inclusive).
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception IllegalArgumentException
+ *
+ * @exception SWTException
+ *
+ */
+public void remove (int start, int end) {
+ checkWidget ();
+ if (start > end) return;
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (!(0 <= start && start <= end && end < count)) {
+ error (SWT.ERROR_INVALID_RANGE);
+ }
+ if (start == 0 && end == count - 1) {
+ removeAll ();
+ } else {
+ setDeferResize (true);
+ int index = start;
+ while (index <= end) {
+ TableItem item = _getItem (index, false);
+ if (item != null && !item.isDisposed ()) item.release (false);
+ ignoreSelect = ignoreShrink = true;
+ long code = OS.SendMessage (handle, OS.LVM_DELETEITEM, start, 0);
+ ignoreSelect = ignoreShrink = false;
+ if (code == 0) break;
+ index++;
+ }
+ _removeItems (start, index, count);
+ if (index <= end) error (SWT.ERROR_ITEM_NOT_REMOVED);
+ /*
+ * This code is intentionally commented. It is not necessary
+ * to check for an empty table because removeAll() was called
+ * when the start == 0 and end == count - 1.
+ */
+ //if (count - index == 0) setTableEmpty ();
+ setDeferResize (false);
+ }
+}
+
+/**
+ * Removes all of the items from the receiver.
+ *
+ * @exception SWTException
+ *
+ */
+public void removeAll () {
+ checkWidget ();
+ int itemCount = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ for (int i=0; i
+ *
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener(SelectionListener)
+ */
+public void removeSelectionListener(SelectionListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.Selection, listener);
+ eventTable.unhook (SWT.DefaultSelection,listener);
+}
+
+/**
+ * Selects the items at the given zero-relative indices in the receiver.
+ * The current selection is not cleared before the new items are selected.
+ *
+ *
+ * @exception SWTException
+ *
+ *
+ * @see Table#setSelection(int[])
+ */
+public void select (int [] indices) {
+ checkWidget ();
+ if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
+ int length = indices.length;
+ if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
+ LVITEM lvItem = new LVITEM ();
+ lvItem.state = OS.LVIS_SELECTED;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ for (int i=length-1; i>=0; --i) {
+ /*
+ * An index of -1 will apply the change to all
+ * items. Ensure that indices are greater than -1.
+ */
+ if (indices [i] >= 0) {
+ ignoreSelect = true;
+ OS.SendMessage (handle, OS.LVM_SETITEMSTATE, indices [i], lvItem);
+ ignoreSelect = false;
+ }
+ }
+}
+
+@Override
+void reskinChildren (int flags) {
+ if (_hasItems ()) {
+ int itemCount = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ for (int i=0; i
+ *
+ *
+ * @see Table#setSelection(int,int)
+ */
+public void select (int start, int end) {
+ checkWidget ();
+ if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (count == 0 || start >= count) return;
+ start = Math.max (0, start);
+ end = Math.min (end, count - 1);
+ if (start == 0 && end == count - 1) {
+ selectAll ();
+ } else {
+ /*
+ * An index of -1 will apply the change to all
+ * items. Indices must be greater than -1.
+ */
+ LVITEM lvItem = new LVITEM ();
+ lvItem.state = OS.LVIS_SELECTED;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ for (int i=start; i<=end; i++) {
+ ignoreSelect = true;
+ OS.SendMessage (handle, OS.LVM_SETITEMSTATE, i, lvItem);
+ ignoreSelect = false;
+ }
+ }
+}
+
+/**
+ * Selects all of the items in the receiver.
+ *
+ *
+ */
+public void selectAll () {
+ checkWidget ();
+ if ((style & SWT.SINGLE) != 0) return;
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_STATE;
+ lvItem.state = OS.LVIS_SELECTED;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ ignoreSelect = true;
+ OS.SendMessage (handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+ ignoreSelect = false;
+}
+
+void sendEraseItemEvent (TableItem item, NMLVCUSTOMDRAW nmcd, long lParam, Event measureEvent) {
+ long hDC = nmcd.hdc;
+ int clrText = item.cellForeground != null ? item.cellForeground [nmcd.iSubItem] : -1;
+ if (clrText == -1) clrText = item.foreground;
+ int clrTextBk = -1;
+ if (OS.IsAppThemed ()) {
+ if (sortColumn != null && sortDirection != SWT.NONE) {
+ if (findImageControl () == null) {
+ if (indexOf (sortColumn) == nmcd.iSubItem) {
+ clrTextBk = getSortColumnPixel ();
+ }
+ }
+ }
+ }
+ clrTextBk = item.cellBackground != null ? item.cellBackground [nmcd.iSubItem] : -1;
+ if (clrTextBk == -1) clrTextBk = item.background;
+ /*
+ * Bug in Windows. For some reason, CDIS_SELECTED always set,
+ * even for items that are not selected. The fix is to get
+ * the selection state from the item.
+ */
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_STATE;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ lvItem.iItem = (int)nmcd.dwItemSpec;
+ long result = OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
+ boolean selected = (result != 0 && (lvItem.state & OS.LVIS_SELECTED) != 0);
+ GCData data = new GCData ();
+ data.device = display;
+ int clrSelectionBk = -1;
+ boolean drawSelected = false, drawBackground = false, drawHot = false, drawDrophilited = false;
+ if (nmcd.iSubItem == 0 || (style & SWT.FULL_SELECTION) != 0) {
+ drawHot = hotIndex == nmcd.dwItemSpec;
+ drawDrophilited = (nmcd.uItemState & OS.CDIS_DROPHILITED) != 0;
+ }
+ if (OS.IsWindowEnabled (handle)) {
+ if (selected && (nmcd.iSubItem == 0 || (style & SWT.FULL_SELECTION) != 0)) {
+ if (OS.GetFocus () == handle || display.getHighContrast ()) {
+ drawSelected = true;
+ data.foreground = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
+ data.background = clrSelectionBk = OS.GetSysColor (OS.COLOR_HIGHLIGHT);
+ } else {
+ drawSelected = (style & SWT.HIDE_SELECTION) == 0;
+ data.foreground = OS.GetTextColor (hDC);
+ data.background = clrSelectionBk = OS.GetSysColor (OS.COLOR_3DFACE);
+ }
+ if (explorerTheme) {
+ data.foreground = clrText != -1 ? clrText : getForegroundPixel ();
+ }
+ } else {
+ drawBackground = clrTextBk != -1;
+ /*
+ * Bug in Windows. When LVM_SETTEXTBKCOLOR, LVM_SETBKCOLOR
+ * or LVM_SETTEXTCOLOR is used to set the background color of
+ * the the text or the control, the color is not set in the HDC
+ * that is provided in Custom Draw. The fix is to explicitly
+ * set the color.
+ */
+ if (clrText == -1 || clrTextBk == -1) {
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ if (clrText == -1) clrText = control.getForegroundPixel ();
+ if (clrTextBk == -1) clrTextBk = control.getBackgroundPixel ();
+ }
+ data.foreground = clrText != -1 ? clrText : OS.GetTextColor (hDC);
+ data.background = clrTextBk != -1 ? clrTextBk : OS.GetBkColor (hDC);
+ }
+ } else {
+ data.foreground = OS.GetSysColor (OS.COLOR_GRAYTEXT);
+ data.background = OS.GetSysColor (OS.COLOR_3DFACE);
+ if (selected) clrSelectionBk = data.background;
+ }
+ data.font = item.getFont (nmcd.iSubItem);
+ data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
+ int nSavedDC = OS.SaveDC (hDC);
+ GC gc = GC.win32_new (hDC, data);
+ RECT cellRect = item.getBounds ((int)nmcd.dwItemSpec, nmcd.iSubItem, true, true, true, true, hDC);
+ Event event = new Event ();
+ event.item = item;
+ event.gc = gc;
+ event.index = nmcd.iSubItem;
+ event.detail |= SWT.FOREGROUND;
+// if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
+ if (OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED) == nmcd.dwItemSpec) {
+ if (nmcd.iSubItem == 0 || (style & SWT.FULL_SELECTION) != 0) {
+ if (handle == OS.GetFocus ()) {
+ int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
+ if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED;
+ }
+ }
+ }
+ boolean focused = (event.detail & SWT.FOCUSED) != 0;
+ if (drawHot) event.detail |= SWT.HOT;
+ if (drawSelected) event.detail |= SWT.SELECTED;
+ if (drawBackground) event.detail |= SWT.BACKGROUND;
+ Rectangle boundsInPixels = new Rectangle (cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top);
+ event.setBoundsInPixels (boundsInPixels);
+ gc.setClipping (DPIUtil.autoScaleDown(boundsInPixels));
+ sendEvent (SWT.EraseItem, event);
+ event.gc = null;
+ int clrSelectionText = data.foreground;
+ gc.dispose ();
+ OS.RestoreDC (hDC, nSavedDC);
+ if (isDisposed () || item.isDisposed ()) return;
+ if (event.doit) {
+ ignoreDrawForeground = (event.detail & SWT.FOREGROUND) == 0;
+ ignoreDrawBackground = (event.detail & SWT.BACKGROUND) == 0;
+ ignoreDrawSelection = (event.detail & SWT.SELECTED) == 0;
+ ignoreDrawFocus = (event.detail & SWT.FOCUSED) == 0;
+ ignoreDrawHot = (event.detail & SWT.HOT) == 0;
+ } else {
+ ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = true;
+ }
+ if (drawSelected) {
+ if (ignoreDrawSelection) {
+ ignoreDrawHot = true;
+ if (nmcd.iSubItem == 0 || (style & SWT.FULL_SELECTION) != 0) {
+ selectionForeground = clrSelectionText;
+ }
+ nmcd.uItemState &= ~OS.CDIS_SELECTED;
+ OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof);
+ }
+ } else {
+ if (ignoreDrawSelection) {
+ nmcd.uItemState |= OS.CDIS_SELECTED;
+ OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof);
+ }
+ }
+ boolean firstColumn = nmcd.iSubItem == OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
+ if (ignoreDrawForeground && ignoreDrawHot && !drawDrophilited) {
+ if (!ignoreDrawBackground && drawBackground) {
+ RECT backgroundRect = item.getBounds ((int)nmcd.dwItemSpec, nmcd.iSubItem, true, false, true, false, hDC);
+ fillBackground (hDC, clrTextBk, backgroundRect);
+ }
+ }
+ focusRect = null;
+ if (!ignoreDrawHot || !ignoreDrawSelection || !ignoreDrawFocus || drawDrophilited) {
+ boolean fullText = (style & SWT.FULL_SELECTION) != 0 || !firstColumn;
+ RECT textRect = item.getBounds ((int)nmcd.dwItemSpec, nmcd.iSubItem, true, false, fullText, false, hDC);
+ if ((style & SWT.FULL_SELECTION) == 0) {
+ if (measureEvent != null) {
+ Rectangle boundInPixels = measureEvent.getBoundsInPixels();
+ textRect.right = Math.min (cellRect.right, boundInPixels.x + boundInPixels.width);
+ }
+ if (!ignoreDrawFocus) {
+ nmcd.uItemState &= ~OS.CDIS_FOCUS;
+ OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof);
+ focusRect = textRect;
+ }
+ }
+ if (explorerTheme) {
+ if (!ignoreDrawHot || drawDrophilited || (!ignoreDrawSelection && clrSelectionBk != -1)) {
+ RECT pClipRect = new RECT ();
+ OS.SetRect (pClipRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
+ RECT rect = new RECT ();
+ OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
+ if ((style & SWT.FULL_SELECTION) != 0) {
+ int count = (int)OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
+ int index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, count - 1, 0);
+ RECT headerRect = new RECT ();
+ OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
+ OS.MapWindowPoints (hwndHeader, handle, headerRect, 2);
+ rect.right = headerRect.right;
+ index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
+ OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
+ OS.MapWindowPoints (hwndHeader, handle, headerRect, 2);
+ rect.left = headerRect.left;
+ pClipRect.left = cellRect.left;
+ pClipRect.right += EXPLORER_EXTRA;
+ } else {
+ rect.right += EXPLORER_EXTRA;
+ pClipRect.right += EXPLORER_EXTRA;
+ }
+ long hTheme = OS.OpenThemeData (handle, Display.LISTVIEW);
+ int iStateId = selected ? OS.LISS_SELECTED : OS.LISS_HOT;
+ if (OS.GetFocus () != handle && selected && !drawHot) iStateId = OS.LISS_SELECTEDNOTFOCUS;
+ if (drawDrophilited) iStateId = OS.LISS_SELECTED;
+ OS.DrawThemeBackground (hTheme, hDC, OS.LVP_LISTITEM, iStateId, rect, pClipRect);
+ OS.CloseThemeData (hTheme);
+ }
+ } else {
+ if (!ignoreDrawSelection && clrSelectionBk != -1) fillBackground (hDC, clrSelectionBk, textRect);
+ }
+ }
+ if (focused && ignoreDrawFocus) {
+ nmcd.uItemState &= ~OS.CDIS_FOCUS;
+ OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof);
+ }
+ if (ignoreDrawForeground) {
+ RECT clipRect = item.getBounds ((int)nmcd.dwItemSpec, nmcd.iSubItem, true, true, true, false, hDC);
+ OS.SaveDC (hDC);
+ OS.SelectClipRgn (hDC, 0);
+ OS.ExcludeClipRect (hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+ }
+}
+
+Event sendEraseItemEvent (TableItem item, NMTTCUSTOMDRAW nmcd, int column, RECT cellRect) {
+ int nSavedDC = OS.SaveDC (nmcd.hdc);
+ RECT insetRect = toolTipInset (cellRect);
+ OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null);
+ GCData data = new GCData ();
+ data.device = display;
+ data.foreground = OS.GetTextColor (nmcd.hdc);
+ data.background = OS.GetBkColor (nmcd.hdc);
+ data.font = item.getFont (column);
+ data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
+ GC gc = GC.win32_new (nmcd.hdc, data);
+ Event event = new Event ();
+ event.item = item;
+ event.index = column;
+ event.gc = gc;
+ event.detail |= SWT.FOREGROUND;
+ event.setBoundsInPixels(new Rectangle(cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top));
+ //gc.setClipping (event.x, event.y, event.width, event.height);
+ sendEvent (SWT.EraseItem, event);
+ event.gc = null;
+ //int newTextClr = data.foreground;
+ gc.dispose ();
+ OS.RestoreDC (nmcd.hdc, nSavedDC);
+ return event;
+}
+
+Event sendMeasureItemEvent (TableItem item, int row, int column, long hDC) {
+ GCData data = new GCData ();
+ data.device = display;
+ data.font = item.getFont (column);
+ int nSavedDC = OS.SaveDC (hDC);
+ GC gc = GC.win32_new (hDC, data);
+ RECT itemRect = item.getBounds (row, column, true, true, false, false, hDC);
+ Event event = new Event ();
+ event.item = item;
+ event.gc = gc;
+ event.index = column;
+ event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top));
+ boolean drawSelected = false;
+ if (OS.IsWindowEnabled (handle)) {
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_STATE;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ lvItem.iItem = (int)row;
+ long result = OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
+ boolean selected = (result != 0 && (lvItem.state & OS.LVIS_SELECTED) != 0);
+ if (selected && (column == 0 || (style & SWT.FULL_SELECTION) != 0)) {
+ if (OS.GetFocus () == handle || display.getHighContrast ()) {
+ drawSelected = true;
+ } else {
+ drawSelected = (style & SWT.HIDE_SELECTION) == 0;
+ }
+ }
+ }
+ if (drawSelected) event.detail |= SWT.SELECTED;
+ sendEvent (SWT.MeasureItem, event);
+ event.gc = null;
+ gc.dispose ();
+ OS.RestoreDC (hDC, nSavedDC);
+ if (!isDisposed () && !item.isDisposed ()) {
+ Rectangle boundsInPixels = event.getBoundsInPixels();
+ if (columnCount == 0) {
+ int width = (int)OS.SendMessage (handle, OS.LVM_GETCOLUMNWIDTH, 0, 0);
+ if (boundsInPixels.x + boundsInPixels.width > width) setScrollWidth (boundsInPixels.x + boundsInPixels.width);
+ }
+ long empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0);
+ long oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0);
+ int itemHeight = OS.HIWORD (oneItem) - OS.HIWORD (empty);
+ /*
+ * Possible recursion: when setItemHeight() is called during
+ * SWT.MeasureItem event processing with a non-zero table-row
+ * selection. Refer bug 400174 and 458786
+ */
+ if (!settingItemHeight && boundsInPixels.height > itemHeight) {
+ settingItemHeight = true;
+ setItemHeight (boundsInPixels.height);
+ settingItemHeight = false;
+ }
+ }
+ return event;
+}
+
+LRESULT sendMouseDownEvent (int type, int button, int msg, long wParam, long lParam) {
+ Display display = this.display;
+ display.captureChanged = false;
+ if (!sendMouseEvent (type, button, handle, msg, wParam, lParam)) {
+ if (!display.captureChanged && !isDisposed ()) {
+ if (OS.GetCapture () != handle) OS.SetCapture (handle);
+ }
+ return LRESULT.ZERO;
+ }
+
+ /*
+ * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN,
+ * the widget starts a modal loop to determine if the user wants
+ * to begin a drag/drop operation or marque select. Unfortunately,
+ * this modal loop eats the corresponding mouse up. The fix is to
+ * detect the cases when the modal loop has eaten the mouse up and
+ * issue a fake mouse up.
+ *
+ * By observation, when the mouse is clicked anywhere but the check
+ * box, the widget eats the mouse up. When the mouse is dragged,
+ * the widget does not eat the mouse up.
+ */
+ LVHITTESTINFO pinfo = new LVHITTESTINFO ();
+ pinfo.x = OS.GET_X_LPARAM (lParam);
+ pinfo.y = OS.GET_Y_LPARAM (lParam);
+ OS.SendMessage (handle, OS.LVM_HITTEST, 0, pinfo);
+ if ((style & SWT.FULL_SELECTION) == 0) {
+ if (hooks (SWT.MeasureItem)) {
+ /*
+ * Bug in Windows. When LVM_SUBITEMHITTEST is used to hittest
+ * a point that is above the table, instead of returning -1 to
+ * indicate that the hittest failed, a negative index is returned.
+ * The fix is to consider any value that is negative a failure.
+ */
+ if (OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, pinfo) < 0) {
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ if (count != 0) {
+ RECT rect = new RECT ();
+ rect.left = OS.LVIR_ICON;
+ ignoreCustomDraw = true;
+ long code = OS.SendMessage (handle, OS.LVM_GETITEMRECT, 0, rect);
+ ignoreCustomDraw = false;
+ if (code != 0) {
+ pinfo.x = rect.left;
+ /*
+ * Bug in Windows. When LVM_SUBITEMHITTEST is used to hittest
+ * a point that is above the table, instead of returning -1 to
+ * indicate that the hittest failed, a negative index is returned.
+ * The fix is to consider any value that is negative a failure.
+ */
+ OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, pinfo);
+ if (pinfo.iItem < 0) pinfo.iItem = -1;
+ pinfo.flags &= ~(OS.LVHT_ONITEMICON | OS.LVHT_ONITEMLABEL);
+ }
+ }
+ } else {
+ if (pinfo.iSubItem != 0) pinfo.iItem = -1;
+ }
+ }
+ }
+
+ /*
+ * Force the table to have focus so that when the user
+ * reselects the focus item, the LVIS_FOCUSED state bits
+ * for the item will be set. If the user did not click on
+ * an item, then set focus to the table so that it will
+ * come to the front and take focus in the work around
+ * below.
+ */
+ OS.SetFocus (handle);
+
+ /*
+ * Feature in Windows. When the user selects outside of
+ * a table item, Windows deselects all the items, even
+ * when the table is multi-select. While not strictly
+ * wrong, this is unexpected. The fix is to detect the
+ * case and avoid calling the window proc.
+ */
+ if ((style & SWT.SINGLE) != 0 || hooks (SWT.MouseDown) || hooks (SWT.MouseUp)) {
+ if (pinfo.iItem == -1) {
+ if (!display.captureChanged && !isDisposed ()) {
+ if (OS.GetCapture () != handle) OS.SetCapture (handle);
+ }
+ return LRESULT.ZERO;
+ }
+ }
+
+ /*
+ * Feature in Windows. When a table item is reselected
+ * in a single-select table, Windows does not issue a
+ * WM_NOTIFY because the item state has not changed.
+ * This is strictly correct but is inconsistent with the
+ * list widget and other widgets in Windows. The fix is
+ * to detect the case when an item is reselected and mark
+ * it as selected.
+ */
+ boolean forceSelect = false;
+ int count = (int)OS.SendMessage (handle, OS.LVM_GETSELECTEDCOUNT, 0, 0);
+ if (count == 1 && pinfo.iItem != -1) {
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_STATE;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ lvItem.iItem = pinfo.iItem;
+ OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
+ if ((lvItem.state & OS.LVIS_SELECTED) != 0) {
+ forceSelect = true;
+ }
+ }
+
+ /* Determine whether the user has selected an item based on SWT.MeasureItem */
+ fullRowSelect = false;
+ if (pinfo.iItem != -1) {
+ if ((style & SWT.FULL_SELECTION) == 0) {
+ if (hooks (SWT.MeasureItem)) {
+ fullRowSelect = hitTestSelection (pinfo.iItem, pinfo.x, pinfo.y);
+ if (fullRowSelect) {
+ int flags = OS.LVHT_ONITEMICON | OS.LVHT_ONITEMLABEL;
+ if ((pinfo.flags & flags) != 0) fullRowSelect = false;
+ }
+ }
+ }
+ }
+
+ /*
+ * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN,
+ * the widget starts a modal loop to determine if the user wants
+ * to begin a drag/drop operation or marque select. This modal
+ * loop eats mouse events until a drag is detected. The fix is
+ * to avoid this behavior by only running the drag and drop when
+ * the event is hooked and the mouse is over an item.
+ */
+ boolean dragDetect = (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect);
+ if (!dragDetect) {
+ int flags = OS.LVHT_ONITEMICON | OS.LVHT_ONITEMLABEL;
+ dragDetect = pinfo.iItem == -1 || (pinfo.flags & flags) == 0;
+ if (fullRowSelect) dragDetect = true;
+ }
+
+ /*
+ * Temporarily set LVS_EX_FULLROWSELECT to allow drag and drop
+ * and the mouse to manipulate items based on the results of
+ * the SWT.MeasureItem event.
+ */
+ if (fullRowSelect) {
+ OS.UpdateWindow (handle);
+ OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
+ OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, OS.LVS_EX_FULLROWSELECT, OS.LVS_EX_FULLROWSELECT);
+ }
+ dragStarted = false;
+ display.dragCancelled = false;
+ if (!dragDetect) display.runDragDrop = false;
+ long code = callWindowProc (handle, msg, wParam, lParam, forceSelect);
+ if (!dragDetect) display.runDragDrop = true;
+ if (fullRowSelect) {
+ fullRowSelect = false;
+ OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
+ OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, OS.LVS_EX_FULLROWSELECT, 0);
+ }
+
+ if (dragStarted || display.dragCancelled) {
+ if (!display.captureChanged && !isDisposed ()) {
+ if (OS.GetCapture () != handle) OS.SetCapture (handle);
+ }
+ } else {
+ int flags = OS.LVHT_ONITEMLABEL | OS.LVHT_ONITEMICON;
+ boolean fakeMouseUp = (pinfo.flags & flags) != 0;
+ if (!fakeMouseUp && (style & SWT.MULTI) != 0) {
+ fakeMouseUp = (pinfo.flags & OS.LVHT_ONITEMSTATEICON) == 0;
+ }
+ if (fakeMouseUp) {
+ sendMouseEvent (SWT.MouseUp, button, handle, msg, wParam, lParam);
+ }
+ }
+ return new LRESULT (code);
+}
+
+void sendPaintItemEvent (TableItem item, NMLVCUSTOMDRAW nmcd) {
+ long hDC = nmcd.hdc;
+ GCData data = new GCData ();
+ data.device = display;
+ data.font = item.getFont (nmcd.iSubItem);
+ /*
+ * Bug in Windows. For some reason, CDIS_SELECTED always set,
+ * even for items that are not selected. The fix is to get
+ * the selection state from the item.
+ */
+ LVITEM lvItem = new LVITEM ();
+ lvItem.mask = OS.LVIF_STATE;
+ lvItem.stateMask = OS.LVIS_SELECTED;
+ lvItem.iItem = (int)nmcd.dwItemSpec;
+ long result = OS.SendMessage (handle, OS.LVM_GETITEM, 0, lvItem);
+ boolean selected = result != 0 && (lvItem.state & OS.LVIS_SELECTED) != 0;
+ boolean drawSelected = false, drawBackground = false, drawHot = false;
+ if (nmcd.iSubItem == 0 || (style & SWT.FULL_SELECTION) != 0) {
+ drawHot = hotIndex == nmcd.dwItemSpec;
+ }
+ if (OS.IsWindowEnabled (handle)) {
+ if (selected && (nmcd.iSubItem == 0 || (style & SWT.FULL_SELECTION) != 0)) {
+ if (OS.GetFocus () == handle || display.getHighContrast ()) {
+ drawSelected = true;
+ if (selectionForeground != -1) {
+ data.foreground = selectionForeground;
+ } else {
+ data.foreground = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
+ }
+ data.background = OS.GetSysColor (OS.COLOR_HIGHLIGHT);
+ } else {
+ drawSelected = (style & SWT.HIDE_SELECTION) == 0;
+ data.foreground = OS.GetTextColor (hDC);
+ data.background = OS.GetSysColor (OS.COLOR_3DFACE);
+ }
+ if (explorerTheme && selectionForeground == -1) {
+ int clrText = item.cellForeground != null ? item.cellForeground [nmcd.iSubItem] : -1;
+ if (clrText == -1) clrText = item.foreground;
+ data.foreground = clrText != -1 ? clrText : getForegroundPixel ();
+ }
+ } else {
+ int clrText = item.cellForeground != null ? item.cellForeground [nmcd.iSubItem] : -1;
+ if (clrText == -1) clrText = item.foreground;
+ int clrTextBk = item.cellBackground != null ? item.cellBackground [nmcd.iSubItem] : -1;
+ if (clrTextBk == -1) clrTextBk = item.background;
+ drawBackground = clrTextBk != -1;
+ /*
+ * Bug in Windows. When LVM_SETTEXTBKCOLOR, LVM_SETBKCOLOR
+ * or LVM_SETTEXTCOLOR is used to set the background color of
+ * the the text or the control, the color is not set in the HDC
+ * that is provided in Custom Draw. The fix is to explicitly
+ * set the color.
+ */
+ if (clrText == -1 || clrTextBk == -1) {
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ if (clrText == -1) clrText = control.getForegroundPixel ();
+ if (clrTextBk == -1) clrTextBk = control.getBackgroundPixel ();
+ }
+ data.foreground = clrText != -1 ? clrText : OS.GetTextColor (hDC);
+ data.background = clrTextBk != -1 ? clrTextBk : OS.GetBkColor (hDC);
+ }
+ } else {
+ data.foreground = OS.GetSysColor (OS.COLOR_GRAYTEXT);
+ data.background = OS.GetSysColor (OS.COLOR_3DFACE);
+ }
+ data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
+ int nSavedDC = OS.SaveDC (hDC);
+ GC gc = GC.win32_new (hDC, data);
+ RECT itemRect = item.getBounds ((int)nmcd.dwItemSpec, nmcd.iSubItem, true, true, false, false, hDC);
+ Event event = new Event ();
+ event.item = item;
+ event.gc = gc;
+ event.index = nmcd.iSubItem;
+ event.detail |= SWT.FOREGROUND;
+// if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
+ if (OS.SendMessage (handle, OS.LVM_GETNEXTITEM, -1, OS.LVNI_FOCUSED) == nmcd.dwItemSpec) {
+ if (nmcd.iSubItem == 0 || (style & SWT.FULL_SELECTION) != 0) {
+ if (handle == OS.GetFocus ()) {
+ int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
+ if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED;
+ }
+ }
+ }
+ if (drawHot) event.detail |= SWT.HOT;
+ if (drawSelected) event.detail |= SWT.SELECTED;
+ if (drawBackground) event.detail |= SWT.BACKGROUND;
+ event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top));
+ RECT cellRect = item.getBounds ((int)nmcd.dwItemSpec, nmcd.iSubItem, true, true, true, true, hDC);
+ int cellWidth = cellRect.right - cellRect.left;
+ int cellHeight = cellRect.bottom - cellRect.top;
+ gc.setClipping (DPIUtil.autoScaleDown(new Rectangle (cellRect.left, cellRect.top, cellWidth, cellHeight)));
+ sendEvent (SWT.PaintItem, event);
+ if (data.focusDrawn) focusRect = null;
+ event.gc = null;
+ gc.dispose ();
+ OS.RestoreDC (hDC, nSavedDC);
+}
+
+Event sendPaintItemEvent (TableItem item, NMTTCUSTOMDRAW nmcd, int column, RECT itemRect) {
+ int nSavedDC = OS.SaveDC (nmcd.hdc);
+ RECT insetRect = toolTipInset (itemRect);
+ OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null);
+ GCData data = new GCData ();
+ data.device = display;
+ data.font = item.getFont (column);
+ data.foreground = OS.GetTextColor (nmcd.hdc);
+ data.background = OS.GetBkColor (nmcd.hdc);
+ data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
+ GC gc = GC.win32_new (nmcd.hdc, data);
+ Event event = new Event ();
+ event.item = item;
+ event.index = column;
+ event.gc = gc;
+ event.detail |= SWT.FOREGROUND;
+ event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top));
+ //gc.setClipping (cellRect.left, cellRect.top, cellWidth, cellHeight);
+ sendEvent (SWT.PaintItem, event);
+ event.gc = null;
+ gc.dispose ();
+ OS.RestoreDC (nmcd.hdc, nSavedDC);
+ return event;
+}
+
+@Override
+void setBackgroundImage (long hBitmap) {
+ super.setBackgroundImage (hBitmap);
+ if (hBitmap != 0) {
+ setBackgroundTransparent (true);
+ } else {
+ if (!hooks (SWT.MeasureItem) && !hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
+ setBackgroundTransparent (false);
+ }
+ }
+}
+
+@Override
+void setBackgroundPixel (int newPixel) {
+ int oldPixel = (int)OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0);
+ if (oldPixel != OS.CLR_NONE) {
+ if (findImageControl () != null) return;
+ if (newPixel == -1) newPixel = defaultBackground ();
+ if (oldPixel != newPixel) {
+ OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, newPixel);
+ OS.SendMessage (handle, OS.LVM_SETTEXTBKCOLOR, 0, newPixel);
+ if ((style & SWT.CHECK) != 0) fixCheckboxImageListColor (true);
+ }
+ }
+ /*
+ * Feature in Windows. When the background color is changed,
+ * the table does not redraw until the next WM_PAINT. The fix
+ * is to force a redraw.
+ */
+ OS.InvalidateRect (handle, null, true);
+}
+
+void setBackgroundTransparent (boolean transparent) {
+ /*
+ * Bug in Windows. When the table has the extended style
+ * LVS_EX_FULLROWSELECT and LVM_SETBKCOLOR is used with
+ * CLR_NONE to make the table transparent, Windows draws
+ * a black rectangle around the first column. The fix is
+ * clear LVS_EX_FULLROWSELECT.
+ *
+ * Feature in Windows. When LVM_SETBKCOLOR is used with
+ * CLR_NONE and LVM_SETSELECTEDCOLUMN is used to select
+ * a column, Windows fills the column with the selection
+ * color, drawing on top of the background image and any
+ * other custom drawing. The fix is to clear the selected
+ * column.
+ */
+ int oldPixel = (int)OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0);
+ if (transparent) {
+ if (oldPixel != OS.CLR_NONE) {
+ /*
+ * Bug in Windows. When the background color is changed,
+ * the table does not redraw until the next WM_PAINT. The
+ * fix is to force a redraw.
+ */
+ OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, OS.CLR_NONE);
+ OS.SendMessage (handle, OS.LVM_SETTEXTBKCOLOR, 0, OS.CLR_NONE);
+ OS.InvalidateRect (handle, null, true);
+
+ /* Clear LVS_EX_FULLROWSELECT */
+ if (!explorerTheme && (style & SWT.FULL_SELECTION) != 0) {
+ int bits = OS.LVS_EX_FULLROWSELECT;
+ OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, bits, 0);
+ }
+
+ /* Clear LVM_SETSELECTEDCOLUMN */
+ if ((sortDirection & (SWT.UP | SWT.DOWN)) != 0) {
+ if (sortColumn != null && !sortColumn.isDisposed ()) {
+ OS.SendMessage (handle, OS.LVM_SETSELECTEDCOLUMN, -1, 0);
+ /*
+ * Bug in Windows. When LVM_SETSELECTEDCOLUMN is set, Windows
+ * does not redraw either the new or the previous selected column.
+ * The fix is to force a redraw.
+ */
+ OS.InvalidateRect (handle, null, true);
+ }
+ }
+ }
+ } else {
+ if (oldPixel == OS.CLR_NONE) {
+ Control control = findBackgroundControl ();
+ if (control == null) control = this;
+ if (control.backgroundImage == null) {
+ int newPixel = control.getBackgroundPixel ();
+ OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, newPixel);
+ OS.SendMessage (handle, OS.LVM_SETTEXTBKCOLOR, 0, newPixel);
+ if ((style & SWT.CHECK) != 0) fixCheckboxImageListColor (true);
+ OS.InvalidateRect (handle, null, true);
+ }
+
+ /* Set LVS_EX_FULLROWSELECT */
+ if (!explorerTheme && (style & SWT.FULL_SELECTION) != 0) {
+ if (!hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
+ int bits = OS.LVS_EX_FULLROWSELECT;
+ OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, bits, bits);
+ }
+ }
+
+ /* Set LVM_SETSELECTEDCOLUMN */
+ if ((sortDirection & (SWT.UP | SWT.DOWN)) != 0) {
+ if (sortColumn != null && !sortColumn.isDisposed ()) {
+ int column = indexOf (sortColumn);
+ if (column != -1) {
+ OS.SendMessage (handle, OS.LVM_SETSELECTEDCOLUMN, column, 0);
+ /*
+ * Bug in Windows. When LVM_SETSELECTEDCOLUMN is set, Windows
+ * does not redraw either the new or the previous selected column.
+ * The fix is to force a redraw.
+ */
+ OS.InvalidateRect (handle, null, true);
+ }
+ }
+ }
+ }
+ }
+}
+
+@Override
+void setBoundsInPixels (int x, int y, int width, int height, int flags, boolean defer) {
+ /*
+ * Bug in Windows. If the table column widths are adjusted
+ * in WM_SIZE or WM_POSITIONCHANGED using LVM_SETCOLUMNWIDTH
+ * blank lines may be inserted at the top of the table. A
+ * call to LVM_GETTOPINDEX will return a negative number (this
+ * is an impossible result). Once the blank lines appear,
+ * there seems to be no way to get rid of them, other than
+ * destroying and recreating the table. The fix is to send
+ * the resize notification after the size has been changed in
+ * the operating system.
+ *
+ * NOTE: This does not fix the case when the user is resizing
+ * columns dynamically. There is no fix for this case at this
+ * time.
+ */
+ setDeferResize (true);
+ super.setBoundsInPixels (x, y, width, height, flags, false);
+ setDeferResize (false);
+}
+
+/**
+ * Sets the order that the items in the receiver should
+ * be displayed in to the given argument which is described
+ * in terms of the zero-relative ordering of when the items
+ * were added.
+ *
+ * @param order the new order to display the items
+ *
+ * @exception SWTException
+ *
+ * @exception IllegalArgumentException
+ *
+ *
+ * @see Table#getColumnOrder()
+ * @see TableColumn#getMoveable()
+ * @see TableColumn#setMoveable(boolean)
+ * @see SWT#Move
+ *
+ * @since 3.1
+ */
+public void setColumnOrder (int [] order) {
+ checkWidget ();
+ if (order == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (columnCount == 0) {
+ if (order.length != 0) error (SWT.ERROR_INVALID_ARGUMENT);
+ return;
+ }
+ if (order.length != columnCount) error (SWT.ERROR_INVALID_ARGUMENT);
+ int [] oldOrder = new int [columnCount];
+ OS.SendMessage (handle, OS.LVM_GETCOLUMNORDERARRAY, columnCount, oldOrder);
+ boolean reorder = false;
+ boolean [] seen = new boolean [columnCount];
+ for (int i=0; i
+ * Note: This operation is a HINT and is not supported on all platforms. If + * the native header has a 3D look and feel (e.g. Windows 7), this method + * will cause the header to look FLAT irrespective of the state of the table style. + *
+ * @param color the new color (or null) + * + * @exception IllegalArgumentExceptiontrue
,
+ * and marks it invisible otherwise.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, marking + * it visible may not actually cause it to be displayed. + *
+ * + * @param show the new visibility state + * + * @exception SWTExceptiontrue
,
+ * and marks it invisible otherwise. Note that some platforms draw grid lines
+ * while others may draw alternating row colors.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, marking + * it visible may not actually cause it to be displayed. + *
+ * + * @param show the new visibility state + * + * @exception SWTException+ * Indices that are out of range and duplicate indices are ignored. + * If the receiver is single-select and multiple indices are specified, + * then all indices are ignored. + *
+ * + * @param indices the indices of the items to select + * + * @exception IllegalArgumentException+ * If the item is not in the receiver, then it is ignored. + *
+ * + * @param item the item to select + * + * @exception IllegalArgumentException+ * Items that are not in the receiver are ignored. + * If the receiver is single-select and multiple items are specified, + * then all items are ignored. + *
+ * + * @param items the array of items + * + * @exception IllegalArgumentException+ * Indices that are out of range are ignored and no items will be selected + * if start is greater than end. + * If the receiver is single-select and there is more than one item in the + * given range, then all indices are ignored. + *
+ * + * @param start the start index of the items to select + * @param end the end index of the items to select + * + * @exception SWTExceptionnull
+ *
+ * @exception IllegalArgumentException UP
, DOWN
or NONE
.
+ *
+ * @param direction the direction of the sort indicator
+ *
+ * @exception SWTException + * Note: Only one of the styles LEFT, RIGHT and CENTER may be specified. + *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Table, TableItem, TableColumn snippets + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class TableColumn extends Item { + Table parent; + boolean resizable, moveable; + String toolTipText; + int id; + +/** + * Constructs a new instance of this class given its parent + * (which must be aTable
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
Table
), a style value
+ * describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * Note that due to a restriction on some platforms, the first column + * is always left aligned. + *
+ * @param parent a composite control which will be the parent of the new instance (cannot be null) + * @param style the style of control to construct + * @param index the zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentExceptionControlListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException SelectionListener
+ * interface.
+ *
+ * widgetSelected
is called when the column header is selected.
+ * widgetDefaultSelected
is not called.
+ *
LEFT
, RIGHT
or CENTER
.
+ *
+ * @return the alignment
+ *
+ * @exception SWTException Table
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException LEFT
, RIGHT
+ * or CENTER
.
+ * + * Note that due to a restriction on some platforms, the first column + * is always left aligned. + *
+ * @param alignment the new alignment + * + * @exception SWTException+ * The mnemonic indicator (character '&') is not displayed in a tool tip. + * To display a single '&' in the tool tip, the character '&' can be + * escaped by doubling it in the string. + *
+ *+ * NOTE: This operation is a hint and behavior is platform specific, on Windows + * for CJK-style mnemonics of the form " (&C)" at the end of the tooltip text + * are not shown in tooltip. + *
+ * + * @param string the new tool tip text (or null) + * + * @exception SWTException+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Table, TableItem, TableColumn snippets + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class TableItem extends Item { + Table parent; + String [] strings; + Image [] images; + Font font; + Font [] cellFont; + boolean checked, grayed, cached; + int imageIndent, background = -1, foreground = -1; + int [] cellBackground, cellForeground; + +/** + * Constructs a new instance of this class given its parent + * (which must be aTable
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
Table
), a style value
+ * describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
true
if the receiver is checked,
+ * and false otherwise. When the parent does not have
+ * the CHECK
style, return false.
+ *
+ * @return the checked state of the checkbox
+ *
+ * @exception SWTException true
if the receiver is grayed,
+ * and false otherwise. When the parent does not have
+ * the CHECK
style, return false.
+ *
+ * @return the grayed state of the checkbox
+ *
+ * @exception SWTException Table
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException + * Note: If control characters like '\n', '\t' etc. are used + * in the string, then the behavior is platform dependent. + *
+ * @param strings the array of new strings + * + * @exception IllegalArgumentExceptionTaskItem
for the given Shell
or the TaskItem
+ * for the application if the Shell
parameter is null
.
+ * If the requested item is not supported by the platform it returns null
.
+ *
+ * @param shell the shell for which the task item is requested, or null to request the application item
+ * @return the task item for the given shell or the application
+ *
+ * @exception SWTException TaskItem
s which are the items
+ * in the receiver.
+ * + * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + *
+ * + * @return the items in the receiver + * + * @exception SWTExceptionTray
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
TaskBar
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException + * This feature might not be available for the receiver on all + * platforms. The application code can check if it is supported + * by calling the respective get method. When the feature is not + * available, the get method will always return the NULL.
+ * + *
+ * For better cross platform support, the application code should
+ * set this feature on the TaskItem
for application.
+ * On Windows, this feature will only work on RCP applications.
+ * The menu should be fully created before this method is called. + * Dynamic changes to the menu after the method is called will not be reflected + * in the native menu.
+ * + * @param menu the new pop up menu + * + * @exception IllegalArgumentException+ * This feature might not be available for the receiver on all + * platforms. The application code can check if it is supported + * by calling the respective get method. When the feature is not + * available, the get method will always return the NULL.
+ * + *
+ * For better cross platform support, the application code should
+ * first try to set this feature on the TaskItem
for the
+ * main shell then on the TaskItem
for the application.
+ * This feature might not be available for the receiver on all + * platforms. The application code can check if it is supported + * by calling the respective get method. When the feature is not + * available, the get method will always return an empty string.
+ * + *
+ * For better cross platform support, the application code should
+ * first try to set this feature on the TaskItem
for the
+ * main shell then on the TaskItem
for the application.
SWT#DEFAULT
.
+ *
+ * + * This feature might not be available for the receiver on all + * platforms. The application code can check if it is supported + * by calling the respective get method. When the feature is not + * available, the get method will always return zero.
+ * + *
+ * For better cross platform support, the application code should
+ * first try to set this feature on the TaskItem
for the
+ * main shell then on the TaskItem
for the application.
SWT#NORMAL
, SWT#PAUSED
,
+ * SWT#ERROR
is set with setProgress()
. SWT#DEFAULT
indicates that no progress should be shown.
+ *
+ *
+ * This feature might not be available for the receiver on all
+ * platforms. The application code can check if it is supported
+ * by calling the respective get method. When the feature is not
+ * available, the get method will always return SWT#DEFAULT
.
+ * For better cross platform support, the application code should
+ * first try to set this feature on the TaskItem
for the
+ * main shell then on the TaskItem
for the application.
+ * Note: Only one of the styles MULTI and SINGLE may be specified, + * and only one of the styles LEFT, CENTER, and RIGHT may be specified. + *
+ *+ * Note: The styles ICON_CANCEL and ICON_SEARCH are hints used in combination with SEARCH. + * When the platform supports the hint, the text control shows these icons. When an icon + * is selected, a default selection event is sent with the detail field set to one of + * ICON_CANCEL or ICON_SEARCH. Normally, application code does not need to check the + * detail. In the case of ICON_CANCEL, the text is cleared before the default selection + * event is sent causing the application to search for an empty string. + *
+ *+ * Note: Some text actions such as Undo are not natively supported on all platforms. + *
+ *+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Text snippets + * @see SWT Example: ControlExample + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class Text extends Scrollable { + int tabs, oldStart, oldEnd; + boolean doubleClick, ignoreModify, ignoreVerify, ignoreCharacter, allowPasswordChar; + String message; + int[] segments; + int clearSegmentsCount = 0; + long hwndSearch, hwndCancel, hwndActive; + + static final char LTR_MARK = '\u200e'; + static final char RTL_MARK = '\u200f'; + + /* Custom icons defined in swt.rc */ + static final int IDI_SEARCH = 101; + static final int IDI_CANCEL = 102; + + /** + * The maximum number of characters that can be entered + * into a text widget. + *+ * Note that this value is platform dependent, based upon + * the native widget implementation. + *
+ */ + public static final int LIMIT; + + /** + * The delimiter used by multi-line text widgets. When text + * is queried and from the widget, it will be delimited using + * this delimiter. + */ + public static final String DELIMITER; + + /* + * This code is intentionally commented. + */ +// static final char PASSWORD; + + /* + * These values can be different on different platforms. + * Therefore they are not initialized in the declaration + * to stop the compiler from inlining. + */ + static { + LIMIT = 0x7FFFFFFF; + DELIMITER = "\r\n"; + } + + static final long EditProc; + static final TCHAR EditClass = new TCHAR (0, "EDIT", true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, EditClass, lpWndClass); + EditProc = lpWndClass.lpfnWndProc; + /* + * This code is intentionally commented. + */ +// long hwndText = OS.CreateWindowEx (0, +// EditClass, +// null, +// OS.WS_OVERLAPPED | OS.ES_PASSWORD, +// 0, 0, 0, 0, +// 0, +// 0, +// OS.GetModuleHandle (null), +// null); +// char echo = (char) OS.SendMessage (hwndText, OS.EM_GETPASSWORDCHAR, 0, 0); +// OS.DestroyWindow (hwndText); +// PASSWORD = echo != 0 ? echo : '*'; + } + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
ModifyListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException
+ * A SegmentEvent
is sent whenever text content is being modified or
+ * a segment listener is added or removed. You can
+ * customize the appearance of text by indicating certain characters to be inserted
+ * at certain text offsets. This may be used for bidi purposes, e.g. when
+ * adjacent segments of right-to-left text should not be reordered relative to
+ * each other.
+ * E.g., multiple Java string literals in a right-to-left language
+ * should generally remain in logical order to each other, that is, the
+ * way they are stored.
+ *
+ * Warning: This API is currently only implemented on Windows and GTK.
+ * SegmentEvent
s won't be sent on Cocoa.
+ *
SelectionListener
+ * interface.
+ *
+ * widgetSelected
is not called for texts.
+ * widgetDefaultSelected
is typically called when ENTER is pressed in a single-line text,
+ * or when ENTER is pressed in a search text. If the receiver has the SWT.SEARCH | SWT.ICON_CANCEL
style
+ * and the user cancels the search, the event object detail field contains the value SWT.ICON_CANCEL
.
+ * Likewise, if the receiver has the SWT.ICON_SEARCH
style and the icon search is selected, the
+ * event object detail field contains the value SWT.ICON_SEARCH
.
+ *
VerifyListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException + * The new text is appended to the text at + * the end of the widget. + *
+ * + * @param string the string to be appended + * + * @exception IllegalArgumentException+ * The current selection is copied to the clipboard. + *
+ * + * @exception SWTException+ * The current selection is first copied to the + * clipboard and then deleted from the widget. + *
+ * + * @exception SWTException+ * The line number of the caret is returned. + *
+ * + * @return the line number + * + * @exception SWTException+ * Indexing is zero based. + *
+ * + * @return the position of the caret + * + * @exception SWTException+ * The double click flag enables or disables the + * default action of the text widget when the user + * double clicks. + *
+ * + * @return whether or not double click is enabled + * + * @exception SWTException+ * The echo character is the character that is + * displayed when the user enters text or the + * text is changed by the programmer. + *
+ * + * @return the echo character + * + * @exception SWTExceptionSWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
+ *
+ * @return the orientation style
+ *
+ * @exception SWTException
+ * Typically this is used in conjunction with SWT.SEARCH
.
+ *
+ * Indexing is zero based. + *
+ * + * @return the position of the caret + * + * @exception SWTExceptionPoint
whose x coordinate is the
+ * character position representing the start of the selected
+ * text, and whose y coordinate is the character position
+ * representing the end of the selection. An "empty" selection
+ * is indicated by the x and y coordinates having the same value.
+ * + * Indexing is zero based. The range of a selection is from + * 0..N where N is the number of characters in the widget. + *
+ * + * @return a point representing the selection start and end + * + * @exception SWTException+ * Tab stop spacing is specified in terms of the + * space (' ') character. The width of a single + * tab stop is the pixel width of the spaces. + *
+ * + * @return the number of tab characters + * + * @exception SWTException+ * The text for a text widget is the characters in the widget, or + * an empty string if this has never been set. + *
+ * + * @return the widget text + * + * @exception SWTException+ * The text for a text widget is the characters in the widget, or + * a zero-length array if this has never been set. + *
+ *+ * Note: Use this API to prevent the text from being written into a String + * object whose lifecycle is outside of your control. This can help protect + * the text, for example, when the widget is used as a password field. + * However, the text can't be protected if an {@link SWT#Segments} or + * {@link SWT#Verify} listener has been added to the widget. + *
+ * + * @return a character array that contains the widget's text + * + * @exception SWTException+ * Indexing is zero based. The range of + * a selection is from 0..N-1 where N is + * the number of characters in the widget. + *
+ * + * @param start the start of the range + * @param end the end of the range + * @return the range of text + * + * @exception SWTException
+ * If this has not been changed by setTextLimit()
,
+ * it will be the constant Text.LIMIT
.
+ *
+ * This index can change when lines are scrolled or new lines are added or removed. + *
+ * + * @return the index of the top line + * + * @exception SWTException+ * The top point is the SWT logical point position of the line + * that is currently at the top of the widget. On + * some platforms, a text widget can be scrolled by + * points instead of lines so that a partial line + * is displayed at the top of the widget. + *
+ * The top SWT logical point changes when the widget is scrolled. + * The top SWT logical point does not include the widget trimming. + *
+ * + * @return the SWT logical point position of the top line + * + * @exception SWTException+ * The old selection is replaced with the new text. + *
+ * + * @param string the string + * + * @exception IllegalArgumentExceptionnull
+ * The selected text is deleted from the widget + * and new text inserted from the clipboard. + *
+ * + * @exception SWTException+ * The double click flag enables or disables the + * default action of the text widget when the user + * double clicks. + *
+ * Note: This operation is a hint and is not supported on + * platforms that do not have this concept. + *
+ * + * @param doubleClick the new double click flag + * + * @exception SWTException+ * The echo character is the character that is + * displayed when the user enters text or the + * text is changed by the programmer. Setting + * the echo character to '\0' clears the echo + * character and redraws the original text. + * If for any reason the echo character is invalid, + * or if the platform does not allow modification + * of the echo character, the default echo character + * for the platform is used. + *
+ * + * @param echo the new echo character + * + * @exception SWTException
+ * Typically this is used in conjunction with SWT.SEARCH
.
+ *
SWT.LEFT_TO_RIGHT
or SWT.RIGHT_TO_LEFT
.
+ * + * Note: This operation is a hint and is not supported on + * platforms that do not have this concept. + *
+ * + * @param orientation new orientation style + * + * @exception SWTException+ * Indexing is zero based. The range of + * a selection is from 0..N where N is + * the number of characters in the widget. + *
+ * Text selections are specified in terms of + * caret positions. In a text widget that + * contains N characters, there are N+1 caret + * positions, ranging from 0..N. This differs + * from other functions that address character + * position such as getText () that use the + * regular array indexing rules. + *
+ * + * @param start new caret position + * + * @exception SWTException+ * Indexing is zero based. The range of + * a selection is from 0..N where N is + * the number of characters in the widget. + *
+ * Text selections are specified in terms of + * caret positions. In a text widget that + * contains N characters, there are N+1 caret + * positions, ranging from 0..N. This differs + * from other functions that address character + * position such as getText () that use the + * usual array indexing rules. + *
+ * + * @param start the start of the range + * @param end the end of the range + * + * @exception SWTException+ * Indexing is zero based. The range of + * a selection is from 0..N where N is + * the number of characters in the widget. + *
+ * Text selections are specified in terms of + * caret positions. In a text widget that + * contains N characters, there are N+1 caret + * positions, ranging from 0..N. This differs + * from other functions that address character + * position such as getText () that use the + * usual array indexing rules. + *
+ * + * @param selection the point + * + * @exception IllegalArgumentException+ * Tab stop spacing is specified in terms of the + * space (' ') character. The width of a single + * tab stop is the pixel width of the spaces. + *
+ * + * @param tabs the number of tabs + * + * @exception SWTException+ * Note: If control characters like '\n', '\t' etc. are used + * in the string, then the behavior is platform dependent. + *
+ * @param string the new text + * + * @exception IllegalArgumentExceptionSWT.SINGLE
and the argument contains multiple lines of text
+ * then the result of this operation is undefined and may vary between platforms.
+ * + * Note: Use this API to prevent the text from being written into a String + * object whose lifecycle is outside of your control. This can help protect + * the text, for example, when the widget is used as a password field. + * However, the text can't be protected if an {@link SWT#Segments} or + * {@link SWT#Verify} listener has been added to the widget. + *
+ * + * @param text a character array that contains the new text + * + * @exception IllegalArgumentException+ * Instead of trying to set the text limit to zero, consider + * creating a read-only text widget. + *
+ * To reset this value to the default, use setTextLimit(Text.LIMIT)
.
+ * Specifying a limit value larger than Text.LIMIT
sets the
+ * receiver's limit to Text.LIMIT
.
+ *
+ * If the selection is already showing + * in the receiver, this method simply returns. Otherwise, + * lines are scrolled until the selection is visible. + *
+ * + * @exception SWTException
+ * The item children that may be added to instances of this class
+ * must be of type ToolItem
.
+ *
+ * Note that although this class is a subclass of Composite
,
+ * it does not make sense to add Control
children to it,
+ * or set a layout on it.
+ *
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. + *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see ToolBar, ToolItem snippets + * @see SWT Example: ControlExample + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class ToolBar extends Composite { + int lastFocusId, lastArrowId, lastHotId; + ToolItem [] items; + ToolItem [] tabItemList; + boolean ignoreResize, ignoreMouse; + ImageList imageList, disabledImageList, hotImageList; + static final long ToolBarProc; + static final TCHAR ToolBarClass = new TCHAR (0, OS.TOOLBARCLASSNAME, true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, ToolBarClass, lpWndClass); + ToolBarProc = lpWndClass.lpfnWndProc; + } + + /* + * From the Windows SDK for TB_SETBUTTONSIZE: + * + * "If an application does not explicitly + * set the button size, the size defaults + * to 24 by 22 pixels". + */ + static final int DEFAULT_WIDTH = 24; + static final int DEFAULT_HEIGHT = 22; + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
ToolItem
s which are the items
+ * in the receiver.
+ * + * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + *
+ * + * @return the items in the receiver + * + * @exception SWTException+ * Note: Only one of the styles CHECK, PUSH, RADIO, SEPARATOR and DROP_DOWN + * may be specified. + *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see ToolBar, ToolItem snippets + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class ToolItem extends Item { + ToolBar parent; + Control control; + String toolTipText; + Image disabledImage, hotImage; + Image disabledImage2; + int id; + short cx; + +/** + * Constructs a new instance of this class given its parent + * (which must be aToolBar
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
ToolBar
), a style value
+ * describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
SelectionListener
+ * interface.
+ *
+ * When widgetSelected
is called when the mouse is over the arrow portion of a drop-down tool,
+ * the event object detail field contains the value SWT.ARROW
.
+ * widgetDefaultSelected
is not called.
+ *
+ * When the SWT.RADIO
style bit is set, the widgetSelected
method is
+ * also called when the receiver loses selection because another item in the same radio group
+ * was selected by the user. During widgetSelected
the application can use
+ * getSelection()
to determine the current selected state of the receiver.
+ *
SEPARATOR
.
+ *
+ * @return the control
+ *
+ * @exception SWTException + * The disabled image is displayed when the receiver is disabled. + *
+ * + * @return the receiver's disabled image + * + * @exception SWTExceptiontrue
if the receiver is enabled, and
+ * false
otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException + * The hot image is displayed when the mouse enters the receiver. + *
+ * + * @return the receiver's hot image + * + * @exception SWTExceptionToolBar
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException true
if the receiver is selected,
+ * and false otherwise.
+ *
+ * When the receiver is of type CHECK
or RADIO
,
+ * it is selected when it is checked (which some platforms draw as a
+ * pushed in button). If the receiver is of any other type, this method
+ * returns false.
+ *
true
if the receiver is enabled and all
+ * of the receiver's ancestors are enabled, and false
+ * otherwise. A disabled control is typically not selectable from the
+ * user interface and draws with an inactive or "grayed" look.
+ *
+ * @return the receiver's enabled state
+ *
+ * @exception SWTException SEPARATOR
.
+ *
+ * @param control the new control
+ *
+ * @exception IllegalArgumentException true
,
+ * and disables it otherwise.
+ * + * A disabled control is typically + * not selectable from the user interface and draws with an + * inactive or "grayed" look. + *
+ * + * @param enabled the new enabled state + * + * @exception SWTException+ * The disabled image is displayed when the receiver is disabled. + *
+ * + * @param image the disabled image to display on the receiver (may be null) + * + * @exception IllegalArgumentException+ * The hot image is displayed when the mouse enters the receiver. + *
+ * + * @param image the hot image to display on the receiver (may be null) + * + * @exception IllegalArgumentException
+ * When the receiver is of type CHECK
or RADIO
,
+ * it is selected when it is checked (which some platforms draw as a
+ * pushed in button).
+ *
+ * Mnemonics are indicated by an '&' that causes the next + * character to be the mnemonic. When the user presses a + * key sequence that matches the mnemonic, a selection + * event occurs. On most platforms, the mnemonic appears + * underlined but may be emphasised in a platform specific + * manner. The mnemonic indicator character '&' can be + * escaped by doubling it in the string, causing a single + * '&' to be displayed. + *
+ * Note: If control characters like '\n', '\t' etc. are used + * in the string, then the behavior is platform dependent. + *
+ * + * @param string the new text + * + * @exception IllegalArgumentException+ * The mnemonic indicator (character '&') is not displayed in a tool tip. + * To display a single '&' in the tool tip, the character '&' can be + * escaped by doubling it in the string. + *
+ *+ * NOTE: This operation is a hint and behavior is platform specific, on Windows + * for CJK-style mnemonics of the form " (&C)" at the end of the tooltip text + * are not shown in tooltip. + *
+ * + * @param string the new tool tip text (or null) + * + * @exception SWTExceptionSEPARATOR
ToolItems.
+ *
+ * @param width the new width. If the new value is SWT.DEFAULT
,
+ * the width is a fixed-width area whose amount is determined by the platform.
+ * If the new value is 0 a vertical or horizontal line will be drawn, depending
+ * on the setting of the corresponding style bit (SWT.VERTICAL
or
+ * SWT.HORIZONTAL
). If the new value is SWT.SEPARATOR_FILL
+ * a variable-width space is inserted that acts as a spring between the two adjoining
+ * items which will push them out to the extent of the containing ToolBar.
+ *
+ *
+ * @exception SWTException + * Note: Only one of the styles ICON_ERROR, ICON_INFORMATION, + * and ICON_WARNING may be specified. + *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Tool Tips snippets + * @see SWT Example: ControlExample + * @see Sample code and further information + * + * @since 3.2 + * @noextend This class is not intended to be subclassed by clients. + */ +public class ToolTip extends Widget { + Shell parent; + TrayItem item; + String text = "", message = ""; + int id, x, y; + boolean autoHide = true, hasLocation, visible; + static final int TIMER_ID = 100; + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
SelectionListener
+ * interface.
+ *
+ * widgetSelected
is called when the receiver is selected.
+ * widgetDefaultSelected
is not called.
+ *
true
if the receiver is automatically
+ * hidden by the platform, and false
otherwise.
+ *
+ * @return the receiver's auto hide state
+ *
+ * @exception SWTException Shell
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException true
if the receiver is visible, and
+ * false
otherwise.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, this method + * may still indicate that it is considered visible even though + * it may not actually be showing. + *
+ * + * @return the receiver's visibility state + * + * @exception SWTExceptiontrue
if the receiver is visible and all
+ * of the receiver's ancestors are visible and false
+ * otherwise.
+ *
+ * @return the receiver's visibility state
+ *
+ * @exception SWTException true
,
+ * and remain visible when false
.
+ *
+ * @param autoHide the auto hide state
+ *
+ * @exception SWTException + * Note that this is different from most widgets where the + * location of the widget is relative to the parent. + *
+ * + * @param x the new x coordinate for the receiver + * @param y the new y coordinate for the receiver + * + * @exception SWTException+ * Note that this is different from most widgets where the + * location of the widget is relative to the parent. + *
+ * Note that the platform window manager ultimately has control + * over the location of tooltips. + *
+ * + * @param location the new location for the receiver + * + * @exception IllegalArgumentExceptiontrue
,
+ * and marks it invisible otherwise.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, marking + * it visible may not actually cause it to be displayed. + *
+ * + * @param visible the new visibility state + * + * @exception SWTExceptiontouches
field of an Event or TouchEvent.
+ *
+ * @see org.eclipse.swt.events.TouchEvent
+ * @see Sample code and further information
+ *
+ * @since 3.7
+ */
+public final class Touch {
+
+ /**
+ * The unique identity of the touch. Use this value to track changes to a touch
+ * during the touch's life. Two touches may have the same identity even if they
+ * come from different sources.
+ */
+ public long id;
+
+ /**
+ * The object representing the input source that generated the touch.
+ */
+ public TouchSource source;
+
+ /**
+ * The state of this touch at the time it was generated. If this field is 0
+ * then the finger is still touching the device but has not moved
+ * since the last TouchEvent
was generated.
+ *
+ * @see org.eclipse.swt.SWT#TOUCHSTATE_DOWN
+ * @see org.eclipse.swt.SWT#TOUCHSTATE_MOVE
+ * @see org.eclipse.swt.SWT#TOUCHSTATE_UP
+ */
+ public int state;
+
+ /**
+ * A flag indicating that the touch is the first touch from a previous
+ * state of no touch points. Once designated as such, the touch remains
+ * the primary touch until all fingers are removed from the device.
+ */
+ public boolean primary;
+
+ /**
+ * The x location of the touch in TouchSource coordinates.
+ */
+ public int x;
+
+ /**
+ * The y location of the touch in TouchSource coordinates.
+ */
+ public int y;
+
+/**
+ * Constructs a new touch state from the given inputs.
+ *
+ * @param identity Identity of the touch
+ * @param source Object representing the device that generated the touch
+ * @param state One of the state constants representing the state of this touch
+ * @param primary Whether or not the touch is the primary touch
+ * @param x X location of the touch in screen coordinates
+ * @param y Y location of the touch in screen coordinates
+ */
+Touch (long identity, TouchSource source, int state, boolean primary, int x, int y) {
+ this.id = identity;
+ this.source = source;
+ this.state = state;
+ this.primary = primary;
+ this.x = x;
+ this.y = y;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString() {
+ return "Touch {id=" + id
+ + " source=" + source
+ + " state=" + state
+ + " primary=" + primary
+ + " x=" + x
+ + " y=" + y
+ + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TouchSource.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TouchSource.java
new file mode 100644
index 000000000..d74cf171c
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TouchSource.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Instances of this class represent sources of touch input that generate Touch
objects.
+ * They also provide information about the input source, which is important for interpreting the
+ * information in the Touch
object.
+ * + * Instances of this class can be marked as direct or indirect: + *
true
for direct or false
for indirect.
+ *
+ * @return true
if the input source is direct, or false
otherwise
+ */
+public boolean isDirect () {
+ return direct;
+}
+
+/**
+ * Returns the bounding rectangle of the device. For a direct source, this corresponds to the bounds of
+ * the display device in pixels. For an indirect source, this contains the size of the device in points.
+ *
+ * Note that the x and y values may not necessarily be 0 if the TouchSource is a direct source.
+ *
+ * @return the bounding rectangle of the input source
+ */
+public Rectangle getBounds () {
+ return new Rectangle (bounds.x, bounds.y, bounds.width, bounds.height);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+@Override
+public String toString () {
+ return "TouchSource {handle=" + handle + " direct=" + direct + " bounds=" + bounds + "}";
+}
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Tracker.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Tracker.java
new file mode 100644
index 000000000..ba256fea1
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Tracker.java
@@ -0,0 +1,1246 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2013 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class implement rubber banding rectangles that are
+ * drawn onto a parent Composite
or Display
.
+ * These rectangles can be specified to respond to mouse and key events
+ * by either moving or resizing themselves accordingly. Trackers are
+ * typically used to represent window geometries in a lightweight manner.
+ *
+ *
+ * Note: Rectangle move behavior is assumed unless RESIZE is specified. + *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Tracker snippets + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class Tracker extends Widget { + Control parent; + boolean tracking, cancelled, stippled; + Rectangle [] rectangles = new Rectangle [0], proportions = rectangles; + Rectangle bounds; + long resizeCursor; + Cursor clientCursor; + int cursorOrientation = SWT.NONE; + boolean inEvent = false; + boolean drawn; + long hwndTransparent, hwndOpaque, oldTransparentProc, oldOpaqueProc; + int oldX, oldY; + + /* + * The following values mirror step sizes on Windows + */ + final static int STEPSIZE_SMALL = 1; + final static int STEPSIZE_LARGE = 9; + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * Note: Currently, null can be passed in for the display argument. + * This has the effect of creating the tracker on the currently active + * display if there is one. If there is no current display, the + * tracker is created on a "default" display. Passing in null as + * the display argument is not considered to be good coding style, + * and may not be supported in a future release of SWT. + *
+ * + * @param display the display to create the tracker on + * @param style the style of control to construct + * + * @exception SWTExceptionControlListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException KeyListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException true
if the rectangles are drawn with a stippled line, false
otherwise.
+ *
+ * @return the stippled effect of the rectangles
+ *
+ * @exception SWTException true
if the user did not cancel the Tracker, false
otherwise
+ *
+ * @exception SWTException Cursor
of the Tracker. If this cursor is null
+ * then the cursor reverts to the default.
+ *
+ * @param newCursor the new Cursor
to display
+ *
+ * @exception SWTException true
if rectangle should appear stippled
+ *
+ * @exception SWTException + * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Display#getSystemTray + * @see Tray, TrayItem snippets + * @see Sample code and further information + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + */ +public class Tray extends Widget { + int itemCount; + TrayItem [] items = new TrayItem [4]; + +Tray (Display display, int style) { + this.display = display; + reskinWidget (); +} + +void createItem (TrayItem item, int index) { + if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE); + if (itemCount == items.length) { + TrayItem [] newItems = new TrayItem [items.length + 4]; + System.arraycopy (items, 0, newItems, 0, items.length); + items = newItems; + } + System.arraycopy (items, index, items, index + 1, itemCount++ - index); + items [index] = item; +} + +void destroyItem (TrayItem item) { + int index = 0; + while (index < itemCount) { + if (items [index] == item) break; + index++; + } + if (index == itemCount) return; + System.arraycopy (items, index + 1, items, index, --itemCount - index); + items [itemCount] = null; +} + +/** + * Returns the item at the given, zero-relative index in the + * receiver. Throws an exception if the index is out of range. + * + * @param index the index of the item to return + * @return the item at the given index + * + * @exception IllegalArgumentExceptionTrayItem
s which are the items
+ * in the receiver.
+ * + * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + *
+ * + * @return the items in the receiver + * + * @exception SWTException+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Tray, TrayItem snippets + * @see Sample code and further information + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + */ +public class TrayItem extends Item { + Tray parent; + int id; + Image image2, highlightImage; + ToolTip toolTip; + String toolTipText; + boolean visible = true; + +/** + * Constructs a new instance of this class given its parent + * (which must be aTray
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
SelectionListener
+ * interface.
+ *
+ * widgetSelected
is called when the receiver is selected
+ * widgetDefaultSelected
is called when the receiver is double-clicked
+ *
MenuDetectListener
interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException Tray
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException true
if the receiver is visible and
+ * false
otherwise.
+ *
+ * @return the receiver's visibility
+ *
+ * @exception SWTException + * The mnemonic indicator (character '&') is not displayed in a tool tip. + * To display a single '&' in the tool tip, the character '&' can be + * escaped by doubling it in the string. + *
+ *+ * NOTE: This operation is a hint and behavior is platform specific, on Windows + * for CJK-style mnemonics of the form " (&C)" at the end of the tooltip text + * are not shown in tooltip. + *
+ * + * @param string the new tool tip text (or null) + * + * @exception SWTExceptiontrue
,
+ * and makes it invisible otherwise.
+ *
+ * @param visible the new visibility state
+ *
+ * @exception SWTException
+ * The item children that may be added to instances of this class
+ * must be of type TreeItem
.
+ *
+ * Style VIRTUAL
is used to create a Tree
whose
+ * TreeItem
s are to be populated by the client on an on-demand basis
+ * instead of up-front. This can provide significant performance improvements for
+ * trees that are very large or for which TreeItem
population is
+ * expensive (for example, retrieving values from an external source).
+ *
+ * Here is an example of using a Tree
with style VIRTUAL
:
+ * final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.BORDER);
+ * tree.setItemCount(20);
+ * tree.addListener(SWT.SetData, new Listener() {
+ * public void handleEvent(Event event) {
+ * TreeItem item = (TreeItem)event.item;
+ * TreeItem parentItem = item.getParentItem();
+ * String text = null;
+ * if (parentItem == null) {
+ * text = "node " + tree.indexOf(item);
+ * } else {
+ * text = parentItem.getText() + " - " + parentItem.indexOf(item);
+ * }
+ * item.setText(text);
+ * System.out.println(text);
+ * item.setItemCount(10);
+ * }
+ * });
+ *
+ *
+ * Note that although this class is a subclass of Composite
,
+ * it does not normally make sense to add Control
children to
+ * it, or set a layout on it, unless implementing something like a cell
+ * editor.
+ *
+ * Note: Only one of the styles SINGLE and MULTI may be specified. + *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Tree, TreeItem, TreeColumn snippets + * @see SWT Example: ControlExample + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class Tree extends Composite { + TreeItem [] items; + TreeColumn [] columns; + int columnCount; + ImageList imageList, headerImageList; + TreeItem currentItem; + TreeColumn sortColumn; + RECT focusRect; + long hwndParent, hwndHeader, hAnchor, hInsert, hSelect; + int lastID; + long hFirstIndexOf, hLastIndexOf; + int lastIndexOf, itemCount, sortDirection; + boolean dragStarted, gestureCompleted, insertAfter, shrink, ignoreShrink; + boolean ignoreSelect, ignoreExpand, ignoreDeselect, ignoreResize; + boolean lockSelection, oldSelected, newSelected, ignoreColumnMove; + boolean linesVisible, customDraw, painted, ignoreItemHeight; + boolean ignoreCustomDraw, ignoreDrawForeground, ignoreDrawBackground, ignoreDrawFocus; + boolean ignoreDrawSelection, ignoreDrawHot, ignoreFullSelection, explorerTheme; + boolean createdAsRTL; + boolean headerItemDragging; + int scrollWidth, selectionForeground; + long headerToolTipHandle, itemToolTipHandle; + long lastTimerID = -1; + int lastTimerCount; + int headerBackground = -1; + int headerForeground = -1; + static final boolean ENABLE_TVS_EX_FADEINOUTEXPANDOS = System.getProperty("org.eclipse.swt.internal.win32.enableFadeInOutExpandos") != null; + static final int TIMER_MAX_COUNT = 8; + static final int INSET = 3; + static final int GRID_WIDTH = 1; + static final int SORT_WIDTH = 10; + static final int HEADER_MARGIN = 12; + static final int HEADER_EXTRA = 3; + static final int INCREMENT = 5; + static final int EXPLORER_EXTRA = 2; + static final int DRAG_IMAGE_SIZE = 301; + static final long TreeProc; + static final TCHAR TreeClass = new TCHAR (0, OS.WC_TREEVIEW, true); + static final long HeaderProc; + static final TCHAR HeaderClass = new TCHAR (0, OS.WC_HEADER, true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, TreeClass, lpWndClass); + TreeProc = lpWndClass.lpfnWndProc; + OS.GetClassInfo (0, HeaderClass, lpWndClass); + HeaderProc = lpWndClass.lpfnWndProc; + } + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
SelectionListener
+ * interface.
+ *
+ * When widgetSelected
is called, the item field of the event object is valid.
+ * If the receiver has the SWT.CHECK
style and the check selection changes,
+ * the event object detail field contains the value SWT.CHECK
.
+ * widgetDefaultSelected
is typically called when an item is double-clicked.
+ * The item field of the event object is valid for default selection, but the detail field is not used.
+ *
TreeListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException SWT.VIRTUAL
style,
+ * these attributes are requested again as needed.
+ *
+ * @param index the index of the item to clear
+ * @param all true
if all child items of the indexed item should be
+ * cleared recursively, and false
otherwise
+ *
+ * @exception IllegalArgumentException SWT.VIRTUAL
style, these
+ * attributes are requested again as needed.
+ *
+ * @param all true
if all child items should be cleared
+ * recursively, and false
otherwise
+ *
+ * @exception SWTException true
if the receiver's header is visible,
+ * and false
otherwise.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, this method + * may still indicate that it is considered visible even though + * it may not actually be showing. + *
+ * + * @return the receiver's header's visibility state + * + * @exception SWTExceptionTreeColumn
s were created by the programmer,
+ * this method will throw ERROR_INVALID_RANGE
despite
+ * the fact that a single column of data may be visible in the tree.
+ * This occurs when the programmer uses the tree like a list, adding
+ * items but never creating a column.
+ *
+ * @param index the index of the column to return
+ * @return the column at the given index
+ *
+ * @exception IllegalArgumentException TreeColumn
s were created by the programmer,
+ * this value is zero, despite the fact that visually, one column
+ * of items may be visible. This occurs when the programmer uses
+ * the tree like a list, adding items but never creating a column.
+ *
+ * @return the number of columns
+ *
+ * @exception SWTException + * Specifically, the indices of the returned array represent + * the current visual order of the items, and the contents + * of the array represent the creation order of the items. + *
+ * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + *
+ * + * @return the current visual order of the receiver's items + * + * @exception SWTExceptionTreeColumn
s which are the
+ * columns in the receiver. Columns are returned in the order
+ * that they were created. If no TreeColumn
s were
+ * created by the programmer, the array is empty, despite the fact
+ * that visually, one column of items may be visible. This occurs
+ * when the programmer uses the tree like a list, adding items but
+ * never creating a column.
+ * + * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + *
+ * + * @return the items in the receiver + * + * @exception SWTException+ * The item that is returned represents an item that could be selected by the user. + * For example, if selection only occurs in items in the first column, then null is + * returned if the point is outside of the item. + * Note that the SWT.FULL_SELECTION style hint, which specifies the selection policy, + * determines the extent of the selection. + *
+ * + * @param point the point used to locate the item + * @return the item at the given point, or null if the point is not in a selectable item + * + * @exception IllegalArgumentException+ * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + *
+ * + * @return the items + * + * @exception SWTExceptiontrue
if the receiver's lines are visible,
+ * and false
otherwise. Note that some platforms draw
+ * grid lines while others may draw alternating row colors.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, this method + * may still indicate that it is considered visible even though + * it may not actually be showing. + *
+ * + * @return the visibility state of the lines + * + * @exception SWTExceptionTreeItem
or null when the receiver is a
+ * root.
+ *
+ * @return the receiver's parent item
+ *
+ * @exception SWTException TreeItem
s that are currently
+ * selected in the receiver. The order of the items is unspecified.
+ * An empty array indicates that no items are selected.
+ * + * Note: This is not the actual structure used by the receiver + * to maintain its selection, so modifying the array will + * not affect the receiver. + *
+ * @return an array representing the selection + * + * @exception SWTExceptionUP
, DOWN
+ * or NONE
.
+ *
+ * @return the sort direction
+ *
+ * @exception SWTException true
,
+ * and marks it invisible otherwise. Note that some platforms draw
+ * grid lines while others may draw alternating row colors.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, marking + * it visible may not actually cause it to be displayed. + *
+ * + * @param show the new visibility state + * + * @exception SWTException+ * If the receiver is single-select, do nothing. + *
+ * + * @exception SWTException+ * Note: This operation is a HINT and is not supported on all platforms. If + * the native header has a 3D look and feel (e.g. Windows 7), this method + * will cause the header to look FLAT irrespective of the state of the tree style. + *
+ * @param color the new color (or null) + * + * @exception IllegalArgumentExceptiontrue
,
+ * and marks it invisible otherwise.
+ * + * If one of the receiver's ancestors is not visible or some + * other condition makes the receiver not visible, marking + * it visible may not actually cause it to be displayed. + *
+ * + * @param show the new visibility state + * + * @exception SWTException+ * Items that are not in the receiver are ignored. + * If the receiver is single-select and multiple items are specified, + * then all items are ignored. + *
+ * + * @param items the array of items + * + * @exception IllegalArgumentExceptionUP
, DOWN
or NONE
.
+ *
+ * @param direction the direction of the sort indicator
+ *
+ * @exception SWTException + * Note: Only one of the styles LEFT, RIGHT and CENTER may be specified. + *
+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Tree, TreeItem, TreeColumn snippets + * @see Sample code and further information + * + * @since 3.1 + * @noextend This class is not intended to be subclassed by clients. + */ +public class TreeColumn extends Item { + Tree parent; + boolean resizable, moveable; + String toolTipText; + int id; + +/** + * Constructs a new instance of this class given its parent + * (which must be aTree
) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
Tree
), a style value
+ * describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
+ * Note that due to a restriction on some platforms, the first column + * is always left aligned. + *
+ * @param parent a composite control which will be the parent of the new instance (cannot be null) + * @param style the style of control to construct + * @param index the zero-relative index to store the receiver in its parent + * + * @exception IllegalArgumentExceptionControlListener
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException SelectionListener
+ * interface.
+ *
+ * widgetSelected
is called when the column header is selected.
+ * widgetDefaultSelected
is not called.
+ *
LEFT
, RIGHT
or CENTER
.
+ *
+ * @return the alignment
+ *
+ * @exception SWTException Tree
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException LEFT
, RIGHT
+ * or CENTER
.
+ * + * Note that due to a restriction on some platforms, the first column + * is always left aligned. + *
+ * @param alignment the new alignment + * + * @exception SWTException+ * The mnemonic indicator (character '&') is not displayed in a tool tip. + * To display a single '&' in the tool tip, the character '&' can be + * escaped by doubling it in the string. + *
+ *+ * NOTE: This operation is a hint and behavior is platform specific, on Windows + * for CJK-style mnemonics of the form " (&C)" at the end of the tooltip text + * are not shown in tooltip. + *
+ * + * @param string the new tool tip text (or null) + * + * @exception SWTException+ * IMPORTANT: This class is not intended to be subclassed. + *
+ * + * @see Tree, TreeItem, TreeColumn snippets + * @see Sample code and further information + * @noextend This class is not intended to be subclassed by clients. + */ +public class TreeItem extends Item { + /** + * the handle to the OS resource + * (Warning: This field is platform dependent) + *+ * IMPORTANT: This field is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms and should never be accessed from application code. + *
+ * + * @noreference This field is not intended to be referenced by clients. + */ + public long handle; + Tree parent; + String [] strings; + Image [] images; + Font font; + Font [] cellFont; + boolean cached; + int background = -1, foreground = -1; + int [] cellBackground, cellForeground; + +/** + * ConstructsTreeItem
and inserts it into Tree
.
+ * Item is inserted as last direct child of the tree.
+ * + * For bulk insert scenarios, see TreeItem#TreeItem(Tree,int,int) + * + * @param parent a tree control which will be the parent of the new instance (cannot be null) + * @param style no styles are currently supported, pass SWT.NONE + * + * @exception IllegalArgumentException
TreeItem
and inserts it into Tree
.
+ * Item is inserted as index
direct child of the tree.
+ * + * The fastest way to insert many items is: + *
TreeItem
and inserts it into Tree
.
+ * Item is inserted as last direct child of the specified TreeItem
.
+ * + * For bulk insert scenarios, see TreeItem#TreeItem(TreeItem,int,int) + * + * @param parentItem a tree control which will be the parent of the new instance (cannot be null) + * @param style no styles are currently supported, pass SWT.NONE + * + * @exception IllegalArgumentException
TreeItem
and inserts it into Tree
.
+ * Item is inserted as index
direct child of the specified TreeItem
.
+ * + * The fastest way to insert many items is: + *
SWT.VIRTUAL
style,
+ * these attributes are requested again as needed.
+ *
+ * @param index the index of the item to clear
+ * @param all true
if all child items of the indexed item should be
+ * cleared recursively, and false
otherwise
+ *
+ * @exception IllegalArgumentException SWT.VIRTUAL
style, these
+ * attributes are requested again as needed.
+ *
+ * @param all true
if all child items should be cleared
+ * recursively, and false
otherwise
+ *
+ * @exception SWTException true
if the receiver is checked,
+ * and false otherwise. When the parent does not have
+ * the CHECK
style, return false.
+ *
+ * @return the checked state
+ *
+ * @exception SWTException true
if the receiver is expanded,
+ * and false otherwise.
+ * + * + * @return the expanded state + * + * @exception SWTException
true
if the receiver is grayed,
+ * and false otherwise. When the parent does not have
+ * the CHECK
style, return false.
+ *
+ * @return the grayed state of the checkbox
+ *
+ * @exception SWTException TreeItem
s which
+ * are the direct item children of the receiver.
+ * + * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + *
+ * + * @return the receiver's items + * + * @exception SWTExceptionTree
.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException TreeItem
or null when the receiver is a
+ * root.
+ *
+ * @return the receiver's parent item
+ *
+ * @exception SWTException + * + * @param checked the new checked state + * + * @exception SWTException
+ * + * @param expanded the new expanded state + * + * @exception SWTException
+ * Note: If control characters like '\n', '\t' etc. are used + * in the string, then the behavior is platform dependent. + *
+ * @param strings the array of new strings + * + * @exception IllegalArgumentException+ * IMPORTANT: This class is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It should never be + * referenced from application code. + *
+ * + * @see Listener + * @see Sample code and further information + */ +public class TypedListener implements Listener { + + /** + * The receiver's event listener + */ + protected SWTEventListener eventListener; + +/** + * Constructs a new instance of this class for the given event listener. + *+ * IMPORTANT: This method is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It should never be + * referenced from application code. + *
+ * + * @param listener the event listener to store in the receiver + * + * @noreference This method is not intended to be referenced by clients. + */ +public TypedListener (SWTEventListener listener) { + eventListener = listener; +} + +/** + * Returns the receiver's event listener. + *+ * IMPORTANT: This method is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It should never be + * referenced from application code. + *
+ * + * @return the receiver's event listener + * + * @noreference This method is not intended to be referenced by clients. + */ +public SWTEventListener getEventListener () { + return eventListener; +} + +/** + * Handles the given event. + *+ * IMPORTANT: This method is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It should never be + * referenced from application code. + *
+ * @param e the event to handle + * + * @noreference This method is not intended to be referenced by clients. + */ +@Override +public void handleEvent (Event e) { + switch (e.type) { + case SWT.Activate: { + ((ShellListener) eventListener).shellActivated(new ShellEvent(e)); + break; + } + case SWT.Arm: { + ((ArmListener) eventListener).widgetArmed (new ArmEvent (e)); + break; + } + case SWT.Close: { + /* Fields set by Decorations */ + ShellEvent event = new ShellEvent (e); + ((ShellListener) eventListener).shellClosed(event); + e.doit = event.doit; + break; + } + case SWT.Collapse: { + if (eventListener instanceof TreeListener) { + ((TreeListener) eventListener).treeCollapsed(new TreeEvent(e)); + } else { + ((ExpandListener) eventListener).itemCollapsed(new ExpandEvent(e)); + } + break; + } + case SWT.Deactivate: { + ((ShellListener) eventListener).shellDeactivated(new ShellEvent(e)); + break; + } + case SWT.Deiconify: { + ((ShellListener) eventListener).shellDeiconified(new ShellEvent(e)); + break; + } + case SWT.DefaultSelection: { + ((SelectionListener)eventListener).widgetDefaultSelected(new SelectionEvent(e)); + break; + } + case SWT.Dispose: { + ((DisposeListener) eventListener).widgetDisposed(new DisposeEvent(e)); + break; + } + case SWT.DragDetect: { + ((DragDetectListener) eventListener).dragDetected(new DragDetectEvent(e)); + break; + } + case SWT.Expand: { + if (eventListener instanceof TreeListener) { + ((TreeListener) eventListener).treeExpanded(new TreeEvent(e)); + } else { + ((ExpandListener) eventListener).itemExpanded(new ExpandEvent(e)); + } + break; + } + case SWT.FocusIn: { + ((FocusListener) eventListener).focusGained(new FocusEvent(e)); + break; + } + case SWT.FocusOut: { + ((FocusListener) eventListener).focusLost(new FocusEvent(e)); + break; + } + case SWT.Gesture: { + GestureEvent event = new GestureEvent(e); + ((GestureListener)eventListener).gesture(event); + e.doit = event.doit; + break; + } + case SWT.Help: { + ((HelpListener) eventListener).helpRequested (new HelpEvent (e)); + break; + } + case SWT.Hide: { + ((MenuListener) eventListener).menuHidden(new MenuEvent(e)); + break; + } + case SWT.Iconify: { + ((ShellListener) eventListener).shellIconified(new ShellEvent(e)); + break; + } + case SWT.KeyDown: { + /* Fields set by Control */ + KeyEvent event = new KeyEvent(e); + ((KeyListener) eventListener).keyPressed(event); + e.doit = event.doit; + break; + } + case SWT.KeyUp: { + /* Fields set by Control */ + KeyEvent event = new KeyEvent(e); + ((KeyListener) eventListener).keyReleased(event); + e.doit = event.doit; + break; + } + case SWT.Modify: { + ((ModifyListener) eventListener).modifyText(new ModifyEvent(e)); + break; + } + case SWT.MenuDetect: { + MenuDetectEvent event = new MenuDetectEvent(e); + ((MenuDetectListener) eventListener).menuDetected(event); + e.x = event.x; + e.y = event.y; + e.doit = event.doit; + e.detail = event.detail; + break; + } + case SWT.MouseDown: { + ((MouseListener) eventListener).mouseDown(new MouseEvent(e)); + break; + } + case SWT.MouseDoubleClick: { + ((MouseListener) eventListener).mouseDoubleClick(new MouseEvent(e)); + break; + } + case SWT.MouseEnter: { + ((MouseTrackListener) eventListener).mouseEnter (new MouseEvent (e)); + break; + } + case SWT.MouseExit: { + ((MouseTrackListener) eventListener).mouseExit (new MouseEvent (e)); + break; + } + case SWT.MouseHover: { + ((MouseTrackListener) eventListener).mouseHover (new MouseEvent (e)); + break; + } + case SWT.MouseMove: { + ((MouseMoveListener) eventListener).mouseMove(new MouseEvent(e)); + return; + } + case SWT.MouseWheel: { + ((MouseWheelListener) eventListener).mouseScrolled(new MouseEvent(e)); + return; + } + case SWT.MouseUp: { + ((MouseListener) eventListener).mouseUp(new MouseEvent(e)); + break; + } + case SWT.Move: { + ((ControlListener) eventListener).controlMoved(new ControlEvent(e)); + break; + } + case SWT.Paint: { + /* Fields set by Control */ + PaintEvent event = new PaintEvent (e); + ((PaintListener) eventListener).paintControl (event); + e.gc = event.gc; + break; + } + case SWT.Resize: { + ((ControlListener) eventListener).controlResized(new ControlEvent(e)); + break; + } + case SWT.Segments: { + SegmentEvent event = new SegmentEvent(e); + ((SegmentListener) eventListener).getSegments(event); + e.segments = event.segments; + e.segmentsChars = event.segmentsChars; + break; + } + case SWT.Selection: { + /* Fields set by Sash */ + SelectionEvent event = new SelectionEvent (e); + ((SelectionListener) eventListener).widgetSelected (event); + e.x = event.x; + e.y = event.y; + e.doit = event.doit; + break; + } + case SWT.Show: { + ((MenuListener) eventListener).menuShown(new MenuEvent(e)); + break; + } + case SWT.Touch: { + ((TouchListener)eventListener).touch(new TouchEvent(e)); + break; + } + case SWT.Traverse: { + /* Fields set by Control */ + TraverseEvent event = new TraverseEvent (e); + ((TraverseListener) eventListener).keyTraversed (event); + e.detail = event.detail; + e.doit = event.doit; + break; + } + case SWT.Verify: { + /* Fields set by Text, RichText */ + VerifyEvent event = new VerifyEvent (e); + ((VerifyListener) eventListener).verifyText (event); + e.text = event.text; + e.doit = event.doit; + break; + } + } +} + +} diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Widget.java new file mode 100644 index 000000000..ad1f53844 --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Widget.java @@ -0,0 +1,2455 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Pierre-Yves B., pyvesdev@gmail.com - Bug 219750: [styled text] Typing ~~ inserts é~~ + *******************************************************************************/ +package org.eclipse.swt.widgets; + + +import org.eclipse.swt.*; +import org.eclipse.swt.events.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; + +/** + * This class is the abstract superclass of all user interface objects. + * Widgets are created, disposed and issue notification to listeners + * when events occur which affect them. + *+ * IMPORTANT: This class is intended to be subclassed only + * within the SWT implementation. However, it has not been marked + * final to allow those outside of the SWT development team to implement + * patched versions of the class in order to get around specific + * limitations in advance of when those limitations can be addressed + * by the team. Any class built using subclassing to access the internals + * of this class will likely fail to compile or run between releases and + * may be strongly platform specific. Subclassing should not be attempted + * without an intimate and detailed understanding of the workings of the + * hierarchy. No support is provided for user-written classes which are + * implemented as subclasses of this class. + *
+ * + * @see #checkSubclass + * @see Sample code and further information + */ +public abstract class Widget { + int style, state; + Display display; + EventTable eventTable; + Object data; + + /* Global state flags */ + static final int DISPOSED = 1<<0; + static final int CANVAS = 1<<1; + static final int KEYED_DATA = 1<<2; + static final int DISABLED = 1<<3; + static final int HIDDEN = 1<<4; + + /* A layout was requested on this widget */ + static final int LAYOUT_NEEDED = 1<<5; + + /* The preferred size of a child has changed */ + static final int LAYOUT_CHANGED = 1<<6; + + /* A layout was requested in this widget hierarchy */ + static final int LAYOUT_CHILD = 1<<7; + + /* Background flags */ + static final int THEME_BACKGROUND = 1<<8; + static final int DRAW_BACKGROUND = 1<<9; + static final int PARENT_BACKGROUND = 1<<10; + + /* Dispose and release flags */ + static final int RELEASED = 1<<11; + static final int DISPOSE_SENT = 1<<12; + + /* More global widget state flags */ + static final int TRACK_MOUSE = 1<<13; + static final int FOREIGN_HANDLE = 1<<14; + static final int DRAG_DETECT = 1<<15; + + /* Move and resize state flags */ + static final int MOVE_OCCURRED = 1<<16; + static final int MOVE_DEFERRED = 1<<17; + static final int RESIZE_OCCURRED = 1<<18; + static final int RESIZE_DEFERRED = 1<<19; + + /* Ignore WM_CHANGEUISTATE */ + static final int IGNORE_WM_CHANGEUISTATE = 1<<20; + + /* Notify of the opportunity to skin this widget */ + static final int SKIN_NEEDED = 1<<21; + + /* Bidi "auto" text direction */ + static final int HAS_AUTO_DIRECTION = 1<<22; + + /* Default size for widgets */ + static final int DEFAULT_WIDTH = 64; + static final int DEFAULT_HEIGHT = 64; + + /* Bidi UCC to enforce text direction */ + static final char LRE = '\u202a'; + static final char RLE = '\u202b'; + + /* Bidi flag and for auto text direction */ + static final int AUTO_TEXT_DIRECTION = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; + + /* Initialize the Common Controls DLL */ + static { + OS.InitCommonControls (); + } + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Widget () { +} + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + *
+ * The style value is either one of the style constants defined in
+ * class SWT
which is applicable to instances of this
+ * class, or must be built by bitwise OR'ing together
+ * (that is, using the int
"|" operator) two or more
+ * of those SWT
style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ *
handleEvent()
message. The event
+ * type is one of the event constants defined in class SWT
.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should be notified when the event occurs
+ *
+ * @exception IllegalArgumentException widgetDisposed()
message.
+ *
+ * @param listener the listener which should be notified when the receiver is disposed
+ *
+ * @exception IllegalArgumentException
+ * The SWT class library is intended to be subclassed
+ * only at specific, controlled points (most notably,
+ * Composite
and Canvas
when
+ * implementing new widgets). This method enforces this
+ * rule unless it is overridden.
+ *
+ * IMPORTANT: By providing an implementation of this + * method that allows a subclass of a class which does not + * normally allow subclassing to be created, the implementer + * agrees to be fully responsible for the fact that any such + * subclass will likely fail between SWT releases and will be + * strongly platform specific. No support is provided for + * user-written classes which are implemented in this fashion. + *
+ * The ability to subclass outside of the allowed SWT classes + * is intended purely to enable those not on the SWT development + * team to implement patches in order to get around specific + * limitations in advance of when those limitations can be + * addressed by the team. Subclassing should not be attempted + * without an intimate and detailed understanding of the hierarchy. + *
+ * + * @exception SWTExceptionSWTException
if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method should be called by
+ * widget implementors to enforce the standard SWT invariants.
+ *
+ * Currently, it is an error to invoke any method (other than
+ * isDisposed()
) on a widget that has had its
+ * dispose()
method called. It is also an error
+ * to call widget methods from any thread that is different
+ * from the thread that created the widget.
+ *
+ * In future releases of SWT, there may be more or fewer error + * checks and exceptions may be thrown for different reasons. + *
+ * + * @exception SWTException
+ * When a widget is destroyed in the operating system, its
+ * descendants are also destroyed by the operating system.
+ * This means that it is only necessary to call destroyWidget
+ * on the root of the widget tree.
+ *
+ * This method is called after releaseWidget()
.
+ *
+ * See also releaseChild()
, releaseWidget()
+ * and releaseHandle()
.
+ *
true
when sent the message isDisposed()
.
+ * Any internal connections between the widgets in the tree will
+ * have been removed to facilitate garbage collection.
+ * This method does nothing if the widget is already disposed.
+ *
+ * NOTE: This method is not called recursively on the descendants
+ * of the receiver. This means that, widget implementers can not
+ * detect when a widget is being disposed of by re-implementing
+ * this method, but should instead listen for the Dispose
+ * event.
+ *
SWTError.error
to handle the error.
+ *
+ * @param code the descriptive error code
+ *
+ * @see SWT#error(int)
+ */
+void error (int code) {
+ SWT.error(code);
+}
+
+boolean filters (int eventType) {
+ return display.filters (eventType);
+}
+
+Widget findItem (long id) {
+ return null;
+}
+
+char [] fixMnemonic (String string) {
+ return fixMnemonic (string, false, false);
+}
+
+char [] fixMnemonic (String string, boolean spaces) {
+ return fixMnemonic (string, spaces, false);
+}
+
+char [] fixMnemonic (String string, boolean spaces, boolean removeAppended) {
+ // fixMnemonic must return a null-terminated array
+ char [] buffer = new char [string.length () + 1];
+ string.getChars (0, string.length (), buffer, 0);
+ int i = 0, j = 0;
+ while (i < buffer.length) {
+ if (buffer [i] == '&') {
+ if (i + 1 < buffer.length && buffer [i + 1] == '&') {
+ buffer [j++] = spaces ? ' ' : buffer [i];
+ i++;
+ }
+ i++;
+ } else if (buffer [i] == '(' && removeAppended && i + 4 == string.length () && buffer [i + 1] == '&' && buffer [i + 3] == ')') {
+ if (spaces) buffer [j++] = ' ';
+ i += 4;
+ } else {
+ buffer [j++] = buffer [i++];
+ }
+ }
+ while (j < buffer.length) buffer [j++] = 0;
+ return buffer;
+}
+
+/**
+ * Returns the application defined widget data associated
+ * with the receiver, or null if it has not been set. The
+ * widget data is a single, unnamed field that is
+ * stored with every widget.
+ * + * Applications may put arbitrary objects in this field. If + * the object stored in the widget data needs to be notified + * when the widget is disposed of, it is the application's + * responsibility to hook the Dispose event on the widget and + * do so. + *
+ * + * @return the widget data + * + * @exception SWTException+ * Applications may have associated arbitrary objects with the + * receiver in this fashion. If the objects stored in the + * properties need to be notified when the widget is disposed + * of, it is the application's responsibility to hook the + * Dispose event on the widget and do so. + *
+ * + * @param key the name of the property + * @return the value of the property or null if it has not been set + * + * @exception IllegalArgumentException
+ * A widget's display is either provided when it is created
+ * (for example, top level Shell
s) or is the
+ * same as its parent's display.
+ *
SWT
.
+ *
+ * @param eventType the type of event to listen for
+ * @return an array of listeners that will be notified when the event occurs
+ *
+ * @exception SWTException toString
to provide a
+ * more meaningful description of the widget.
+ *
+ * @return the contents string for the widget
+ *
+ * @see #toString
+ */
+String getNameText () {
+ return ""; //$NON-NLS-1$
+}
+
+/**
+ * Returns the receiver's style information.
+ *
+ * Note that the value which is returned by this method may
+ * not match the value which was provided to the constructor
+ * when the receiver was created. This can occur when the underlying
+ * operating system does not support a particular combination of
+ * requested styles. For example, if the platform widget used to
+ * implement a particular SWT widget always has scroll bars, the
+ * result of calling this method would always have the
+ * SWT.H_SCROLL
and SWT.V_SCROLL
bits set.
+ *
true
if the specified eventType is
+ * hooked, and false
otherwise. Implementations
+ * of SWT can avoid creating objects and sending events
+ * when an event happens in the operating system but
+ * there are no listeners hooked for the event.
+ *
+ * @param eventType the event to be checked
+ *
+ * @return true
when the eventType is hooked and false
otherwise
+ *
+ * @see #isListening
+ */
+boolean hooks (int eventType) {
+ if (eventTable == null) return false;
+ return eventTable.hooks (eventType);
+}
+
+/**
+ * Returns true
if the widget has auto text direction,
+ * and false
otherwise.
+ *
+ * @return true
when the widget has auto direction and false
otherwise
+ *
+ * @see SWT#AUTO_TEXT_DIRECTION
+ *
+ * @since 3.105
+ */
+public boolean isAutoDirection () {
+ return (state & HAS_AUTO_DIRECTION) != 0;
+}
+
+/**
+ * Returns true
if the widget has been disposed,
+ * and false
otherwise.
+ * + * This method gets the dispose state for the widget. + * When a widget has been disposed, it is an error to + * invoke any other method (except {@link #dispose()}) using the widget. + *
+ * + * @returntrue
when the widget is disposed and false
otherwise
+ */
+public boolean isDisposed () {
+ return (state & DISPOSED) != 0;
+}
+
+/**
+ * Returns true
if there are any listeners
+ * for the specified event type associated with the receiver,
+ * and false
otherwise. The event type is one of
+ * the event constants defined in class SWT
.
+ *
+ * @param eventType the type of event
+ * @return true if the event is hooked
+ *
+ * @exception SWTException true
when subclassing is
+ * allowed and false
otherwise
+ *
+ * @return true
when subclassing is allowed and false
otherwise
+ */
+boolean isValidSubclass () {
+ return Display.isValidClass (getClass ());
+}
+
+/*
+ * Returns true
when the current thread is
+ * the thread that created the widget and false
+ * otherwise.
+ *
+ * @return true
when the current thread is the thread that created the widget and false
otherwise
+ */
+boolean isValidThread () {
+ return getDisplay ().isValidThread ();
+}
+
+void mapEvent (long hwnd, Event event) {
+}
+
+GC new_GC (GCData data) {
+ return null;
+}
+
+/**
+ * Notifies all of the receiver's listeners for events
+ * of the given type that one such event has occurred by
+ * invoking their handleEvent()
method. The
+ * event type is one of the event constants defined in class
+ * SWT
.
+ *
+ * @param eventType the type of event which has occurred
+ * @param event the event data
+ *
+ * @exception SWTException
+ * Typically, a widget with children will broadcast this
+ * message to all children so that they too can release their
+ * resources. The releaseHandle
method is used
+ * as part of this broadcast to zero the handle fields of the
+ * children without calling destroyWidget
. In
+ * this scenario, the children are actually destroyed later,
+ * when the operating system destroys the widget tree.
+ *
+ * This method is called after releaseWidget
+ * or from destroyWidget
when a widget is being
+ * destroyed to ensure that the widget is marked as destroyed
+ * in case the act of destroying the widget in the operating
+ * system causes application code to run in callback that
+ * could access the widget.
+ *
+ * When a widget is destroyed, it may be necessary to remove + * it from an internal data structure of the parent. When + * a widget has no handle, it may also be necessary for the + * parent to hide the widget or otherwise indicate that the + * widget has been disposed. For example, disposing a menu + * bar requires that the menu bar first be released from the + * shell when the menu bar is active. + *
+ * + * @see #dispose + * @see #releaseChildren + * @see #releaseWidget + * @see #releaseHandle + */ +void releaseParent () { +} + +/* + * Releases any internal resources back to the operating + * system and clears all fields except the widget handle. + *
+ * When a widget is destroyed, resources that were acquired
+ * on behalf of the programmer need to be returned to the
+ * operating system. For example, if the widget made a
+ * copy of an icon, supplied by the programmer, this copy
+ * would be freed in releaseWidget
. Also,
+ * to assist the garbage collector and minimize the amount
+ * of memory that is not reclaimed when the programmer keeps
+ * a reference to a disposed widget, all fields except the
+ * handle are zero'd. The handle is needed by destroyWidget
.
+ *
SWT
.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException + * IMPORTANT: This method is not part of the SWT + * public API. It is marked public only so that it can be shared + * within the packages provided by SWT. It should never be + * referenced from application code. + *
+ * + * @param eventType the type of event to listen for + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException
+ * The skin event is sent to the receiver's display when appropriate (usually before the next event
+ * is handled). Widgets are automatically marked for skinning upon creation as well as when its skin
+ * id or class changes. The skin id and/or class can be changed by calling {@link Display#setData(String, Object)}
+ * with the keys {@link SWT#SKIN_ID} and/or {@link SWT#SKIN_CLASS}. Once the skin event is sent to a widget, it
+ * will not be sent again unless reskin(int)
is called on the widget or on an ancestor
+ * while specifying the SWT.ALL
flag.
+ *
+ * The parameter flags
may be either:
+ *
+ * Applications may put arbitrary objects in this field. If + * the object stored in the widget data needs to be notified + * when the widget is disposed of, it is the application's + * responsibility to hook the Dispose event on the widget and + * do so. + *
+ * + * @param data the widget data + * + * @exception SWTException+ * Applications may associate arbitrary objects with the + * receiver in this fashion. If the objects stored in the + * properties need to be notified when the widget is disposed + * of, it is the application's responsibility to hook the + * Dispose event on the widget and do so. + *
+ * + * @param key the name of the property + * @param value the new value for the property + * + * @exception IllegalArgumentExceptionEvent
).
+
+
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/swt-awt-win32-4930r7.dll b/bundles/org.eclipse.swt.win32.win32.x86_64/swt-awt-win32-4930r7.dll
new file mode 100644
index 000000000..5c9a056d8
Binary files /dev/null and b/bundles/org.eclipse.swt.win32.win32.x86_64/swt-awt-win32-4930r7.dll differ
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/swt-gdip-win32-4930r7.dll b/bundles/org.eclipse.swt.win32.win32.x86_64/swt-gdip-win32-4930r7.dll
new file mode 100644
index 000000000..936173be4
Binary files /dev/null and b/bundles/org.eclipse.swt.win32.win32.x86_64/swt-gdip-win32-4930r7.dll differ
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/swt-wgl-win32-4930r7.dll b/bundles/org.eclipse.swt.win32.win32.x86_64/swt-wgl-win32-4930r7.dll
new file mode 100644
index 000000000..7cbd991e7
Binary files /dev/null and b/bundles/org.eclipse.swt.win32.win32.x86_64/swt-wgl-win32-4930r7.dll differ
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/swt-win32-4930r7.dll b/bundles/org.eclipse.swt.win32.win32.x86_64/swt-win32-4930r7.dll
new file mode 100644
index 000000000..bafb979bd
Binary files /dev/null and b/bundles/org.eclipse.swt.win32.win32.x86_64/swt-win32-4930r7.dll differ
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/version.txt b/bundles/org.eclipse.swt.win32.win32.x86_64/version.txt
new file mode 100644
index 000000000..ea7eb3ba3
--- /dev/null
+++ b/bundles/org.eclipse.swt.win32.win32.x86_64/version.txt
@@ -0,0 +1 @@
+version 4.924
\ No newline at end of file
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 59e88c12b..45d1286fe 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -248,6 +248,7 @@