Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT')
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/TextLayout.java4
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java3
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java71
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Table.java83
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tree.java10
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeItem.java12
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java16
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/library/make_common.mak8
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java11
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/SWTMessages.properties7
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/WidgetSpy.java154
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/layout/BorderData.java120
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/layout/BorderLayout.java420
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/version.txt2
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java23
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/GDBus.java4
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Button.java8
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java23
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java70
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java99
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolItem.java52
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java104
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeItem.java12
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java50
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java117
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java269
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java4
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/ImageList.java10
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java91
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java21
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java48
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableColumn.java110
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java16
34 files changed, 1543 insertions, 510 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/TextLayout.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/TextLayout.java
index 2d004432bc..23c3df501b 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/TextLayout.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/TextLayout.java
@@ -248,7 +248,7 @@ void computeRuns() {
if (style.strikeout) {
attrStr.addAttribute(OS.NSStrikethroughStyleAttributeName, NSNumber.numberWithInt(OS.NSUnderlineStyleSingle), range);
Color strikeColor = style.strikeoutColor;
- if (strikeColor != null) {
+ if (strikeColor != null && !strikeColor.isDisposed()) {
NSColor color = NSColor.colorWithDeviceRed(strikeColor.handle[0], strikeColor.handle[1], strikeColor.handle[2], 1);
attrStr.addAttribute(OS.NSStrikethroughColorAttributeName, color, range);
}
@@ -277,7 +277,7 @@ void computeRuns() {
if (underlineStyle != 0) {
attrStr.addAttribute(OS.NSUnderlineStyleAttributeName, NSNumber.numberWithInt(underlineStyle), range);
Color underlineColor = style.underlineColor;
- if (underlineColor != null) {
+ if (underlineColor != null && !underlineColor.isDisposed()) {
NSColor color = NSColor.colorWithDeviceRed(underlineColor.handle[0], underlineColor.handle[1], underlineColor.handle[2], 1);
attrStr.addAttribute(OS.NSUnderlineColorAttributeName, color, range);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java
index 02cc5bdf67..370c88d76c 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java
@@ -173,7 +173,8 @@ NSSize cellSizeForBounds (long id, long sel, NSRect cellFrame) {
NSAttributedString attribStr = createString(text, null, foreground, style, true, true, true);
NSRect rect = attribStr.boundingRectWithSize(wrapSize, OS.NSStringDrawingUsesLineFragmentOrigin);
attribStr.release();
- double trimHeight = size.height - titleRect.height;
+ // Avoid trim height to be set to a negative value
+ double trimHeight = Math.max(size.height - titleRect.height, 0);
size.height = rect.height;
if (image != null && ((style & (SWT.CHECK|SWT.RADIO)) !=0)) {
NSSize imageSize = image.handle.size();
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java
index 7f2b241843..d2ef22338b 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java
@@ -860,8 +860,9 @@ static private void configureSystemOptions () {
* macOS 11 always enables it regardless of sdk. The option is force
* enabled here in case SWT runs with java/launcher linked with older sdk.
*/
- if (!OS.isBigSurOrLater ())
+ if (!OS.isBigSurOrLater ()) {
configureSystemOption ("NSViewAllowsRootLayerBacking", true);
+ }
/*
* Starting with macOS 11, layer backing is always enabled. That's fine.
@@ -874,8 +875,36 @@ static private void configureSystemOptions () {
* things a lot slower. The workaround is to disable the "automatic" image
* format.
*/
- if (OS.isBigSurOrLater ())
+ if (OS.isBigSurOrLater ()) {
configureSystemOption ("NSViewUsesAutomaticLayerBackingStores", false);
+ }
+
+ /*
+ * Bug 578171: There is new code in macOS 12 that remembers which
+ * Shell was active before menu popup was shown and tries to
+ * re-activate after menu popup is closed. Unfortunately there is a
+ * bug in this code: if window list changes, it activates a wrong
+ * Shell.
+ *
+ * This is a bug on its own, but worse yet, this causes a JVM crash
+ * because activating a new Shell causes menu bar to reset its
+ * internal data, which is unexpected to the macOS's menu tracking
+ * loop.
+ *
+ * Both bugs are bugs of macOS itself. The workaround is to disable
+ * the new macOS 12 behavior.
+ *
+ * The condition should be for (macOS >= 12), but it's not possible
+ * to reliably distinguish 11 from 12, see comment for OS.VERSION.
+ * That's fine: older macOS don't know this setting and will not
+ * check for it anyway.
+ */
+ if (OS.isBigSurOrLater ()) {
+ // The name of the option is misleading. What it really means
+ // is whether '-[NSMenuWindowManagerWindow _setVisible:]' shall
+ // save/restore current key window or not.
+ configureSystemOption ("NSMenuWindowManagerWindowShouldSetVisible", true);
+ }
}
/**
@@ -1028,13 +1057,13 @@ void createMainMenu () {
appleMenu.initWithTitle(emptyStr);
OS.objc_msgSend(application.id, OS.sel_registerName("setAppleMenu:"), appleMenu.id);
- title = NSString.stringWith(SWT.getMessage("About") + " " + appName);
+ title = NSString.stringWith(SWT.getMessage("SWT_About") + " " + appName);
menuItem = appleMenu.addItemWithTitle(title, OS.sel_orderFrontStandardAboutPanel_, emptyStr);
menuItem.setTarget(applicationDelegate);
appleMenu.addItem(NSMenuItem.separatorItem());
- title = NSString.stringWith(SWT.getMessage("Preferences..."));
+ title = NSString.stringWith(SWT.getMessage("SWT_Preferences"));
menuItem = appleMenu.addItemWithTitle(title, 0, NSString.stringWith(","));
/*
@@ -1045,7 +1074,7 @@ void createMainMenu () {
appleMenu.addItem(NSMenuItem.separatorItem());
- title = NSString.stringWith(SWT.getMessage("Services"));
+ title = NSString.stringWith(SWT.getMessage("SWT_Services"));
menuItem = appleMenu.addItemWithTitle(title, 0, emptyStr);
NSMenu servicesMenu = (NSMenu)new NSMenu().alloc();
servicesMenu.initWithTitle(emptyStr);
@@ -1055,22 +1084,22 @@ void createMainMenu () {
appleMenu.addItem(NSMenuItem.separatorItem());
- title = NSString.stringWith(SWT.getMessage("Hide") + " " + appName);
+ title = NSString.stringWith(SWT.getMessage("SWT_Hide") + " " + appName);
menuItem = appleMenu.addItemWithTitle(title, OS.sel_hide_, NSString.stringWith("h"));
menuItem.setTarget(applicationDelegate);
- title = NSString.stringWith(SWT.getMessage("Hide Others"));
+ title = NSString.stringWith(SWT.getMessage("SWT_HideOthers"));
menuItem = appleMenu.addItemWithTitle(title, OS.sel_hideOtherApplications_, NSString.stringWith("h"));
menuItem.setKeyEquivalentModifierMask(OS.NSCommandKeyMask | OS.NSAlternateKeyMask);
menuItem.setTarget(applicationDelegate);
- title = NSString.stringWith(SWT.getMessage("Show All"));
+ title = NSString.stringWith(SWT.getMessage("SWT_ShowAll"));
menuItem = appleMenu.addItemWithTitle(title, OS.sel_unhideAllApplications_, emptyStr);
menuItem.setTarget(applicationDelegate);
appleMenu.addItem(NSMenuItem.separatorItem());
- title = NSString.stringWith(SWT.getMessage("Quit") + " " + appName);
+ title = NSString.stringWith(SWT.getMessage("SWT_Quit") + " " + appName);
menuItem = appleMenu.addItemWithTitle(title, OS.sel_applicationShouldTerminate_, NSString.stringWith("q"));
menuItem.setTarget(applicationDelegate);
@@ -5654,28 +5683,24 @@ void applicationWillFinishLaunching (long id, long sel, long notification) {
/* To find the nib look for each of these paths, in order, until one is found:
* /System/Library/..../Resources/<display name>.lproj/DefaultApp.nib
* /System/Library/..../Resources/<language>.lproj/DefaultApp.nib
- * /System/Library/..../Resources/<user's default language>.lproj/DefaultApp.nib
- * /System/Library/..../Resources/English.lproj/DefaultApp.nib.
- * /System/Library/..../Resources/en.lproj/DefaultApp.nib.
+ * /System/Library/..../Resources/Base.lproj/DefaultApp.nib
+ *
+ * If nib file is not found, use the fallback method createMainMenu() to create menu with localized strings.
*/
NSString path;
NSDictionary dict = NSDictionary.dictionaryWithObject(applicationDelegate, NSString.stringWith("NSOwner"));
- NSBundle bundle = NSBundle.bundleWithIdentifier(NSString.stringWith("com.apple.JavaVM"));
+ NSBundle bundle = NSBundle.bundleWithPath(NSString.stringWith("/System/Library/Frameworks/JavaVM.framework/"));
if (bundle != null) {
path = bundle.pathForResource(NSString.stringWith("DefaultApp"), NSString.stringWith("nib"), null, languageDisplayName);
if (path == null) path = bundle.pathForResource(NSString.stringWith("DefaultApp"), NSString.stringWith("nib"), null, NSString.stringWith(languageISOValue));
- if (path == null) path = bundle.pathForResource(NSString.stringWith("DefaultApp"), NSString.stringWith("nib"));
- if (!loaded) loaded = path != null && NSBundle.loadNibFile(path, dict, 0);
- if (!loaded) {
- path = bundle.pathForResource(NSString.stringWith("DefaultApp"), NSString.stringWith("nib"), null, NSString.stringWith("English"));
- if (path == null) path = bundle.pathForResource(NSString.stringWith("DefaultApp"), NSString.stringWith("nib"), null, NSString.stringWith("en"));
- loaded = path != null && NSBundle.loadNibFile(path, dict, 0);
+ if (path == null && languageISOValue.equals("en")) {
+ path = bundle.pathForResource(NSString.stringWith("DefaultApp"), NSString.stringWith("nib"));
}
+ if (!loaded) loaded = path != null && NSBundle.loadNibFile(path, dict, 0);
}
- if (!loaded) {
- path = NSString.stringWith(System.getProperty("java.home") + "/../Resources/English.lproj/DefaultApp.nib");
- loaded = path != null && NSBundle.loadNibFile(path, dict, 0);
- }
+ /*
+ * Create the main menu ourselves if Default.nib was not loaded or was not found for the specific language
+ */
if (!loaded) {
createMainMenu();
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Table.java
index 965fb9d96e..c49f1354fe 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Table.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Table.java
@@ -3636,39 +3636,66 @@ boolean tableView_writeRowsWithIndexes_toPasteboard(long id, long sel, long arg0
return sendMouseEvent(NSApplication.sharedApplication().currentEvent(), SWT.DragDetect, true);
}
+void handleClickSelected() {
+ /*
+ * When there are multiple selected items and one of them is clicked
+ * without modifiers, macOS supports two cases:
+ * 1) For single click, all other items are deselected
+ * 2) For double-click, selection stays as is, allowing to create
+ * double-click event with multiple items.
+ * In order to distinguish between the two, macOS delays (1) by
+ * [NSEvent doubleClickInterval] in order to see if it's case (2).
+ * This causes SWT.Selection to occur after SWT.MouseUp.
+ *
+ * Bug 289483: For consistent cross-platform behavior, we want
+ * SWT.Selection to occur before SWT.MouseUp. The workaround is to
+ * implement (1) in SWT code and ignore the delayed selection event.
+ */
+
+ int clickedRow = selectedRowIndex;
+ selectedRowIndex = -1;
+
+ if (clickedRow == -1) return;
+ if (dragDetected) return;
+
+ // Deselect all items except the clicked one
+ NSTableView widget = (NSTableView)view;
+ NSIndexSet selectedRows = widget.selectedRowIndexes ();
+ int count = (int)selectedRows.count();
+ long [] indexBuffer = new long [count];
+ selectedRows.getIndexes(indexBuffer, count, 0);
+ for (int i = 0; i < count; i++) {
+ if (indexBuffer[i] == clickedRow) continue;
+ ignoreSelect = true;
+ widget.deselectRow (indexBuffer[i]);
+ ignoreSelect = false;
+ }
+
+ // Bug 456602: It's possible that item is removed between mouse
+ // down (where 'selectedRowIndex' was cached) and mouse up (current
+ // code). In such case, all other items are still deselected, because
+ // 1) without workaround, selection should have happened in mouse down,
+ // where item still existed
+ // 2) clicking empty space deselects all items on macOS
+ // If item is deleted, then pending selection is canceled by macOS, so
+ // there's no need to ignore the next selection event.
+ if (clickedRow >= itemCount) return;
+
+ // Emulate SWT.Selection
+ Event event = new Event ();
+ event.item = _getItem(clickedRow);
+ sendSelectionEvent (SWT.Selection, event, false);
+
+ // Ignore real SWT.Selection that will arrive later
+ ignoreSelect = true;
+}
+
@Override
boolean sendMouseEvent(NSEvent nsEvent, int type, boolean send) {
if (type == SWT.DragDetect) {
dragDetected = true;
} else if (type == SWT.MouseUp) {
- /*
- * This code path handles the case of an unmodified click on an already-selected row.
- * To keep the order of events correct, deselect the other selected items and send the
- * selection event before MouseUp is sent. Ignore the next selection event.
- */
- if (selectedRowIndex != -1) {
- if (dragDetected) {
- selectedRowIndex = -1;
- } else {
- NSTableView widget = (NSTableView)view;
- NSIndexSet selectedRows = widget.selectedRowIndexes ();
- int count = (int)selectedRows.count();
- long [] indexBuffer = new long [count];
- selectedRows.getIndexes(indexBuffer, count, 0);
- for (int i = 0; i < count; i++) {
- if (indexBuffer[i] == selectedRowIndex) continue;
- ignoreSelect = true;
- widget.deselectRow (indexBuffer[i]);
- ignoreSelect = false;
- }
-
- Event event = new Event ();
- event.item = _getItem ((int)selectedRowIndex);
- selectedRowIndex = -1;
- sendSelectionEvent (SWT.Selection, event, false);
- ignoreSelect = true;
- }
- }
+ handleClickSelected();
dragDetected = false;
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tree.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tree.java
index da9954aa6a..1c2de57fa6 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tree.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tree.java
@@ -2805,11 +2805,7 @@ boolean sendMouseEvent(NSEvent nsEvent, int type, boolean send) {
if (type == SWT.DragDetect) {
dragDetected = true;
} else if (type == SWT.MouseUp) {
- /*
- * This code path handles the case of an unmodified click on an already-selected row.
- * To keep the order of events correct, deselect the other selected items and send the
- * selection event before MouseUp is sent. Ignore the next selection event.
- */
+ // See code comment in Table.handleClickSelected()
if (selectedRowIndex != -1) {
if (dragDetected) {
selectedRowIndex = -1;
@@ -2828,6 +2824,8 @@ boolean sendMouseEvent(NSEvent nsEvent, int type, boolean send) {
Event event = new Event ();
id itemID = widget.itemAtRow (selectedRowIndex);
+ // (itemID = null) means that item was removed after
+ // 'selectedRowIndex' was cached
if (itemID != null) {
Widget item = display.getWidget (itemID.id);
if (item != null && item instanceof TreeItem) {
@@ -3074,7 +3072,7 @@ public void setHeaderVisible (boolean show) {
/**
* Sets the number of root-level items contained in the receiver.
* <p>
- * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(org.eclipse.swt.widgets.Tree,int,int)}
+ * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(Tree,int,int)}
* and {@link TreeItem#setItemCount}
*
* @param count the number of items
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeItem.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeItem.java
index 1fdf19e060..529082d051 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeItem.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TreeItem.java
@@ -67,8 +67,8 @@ public class TreeItem extends Item {
* Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
* Item is inserted as last direct child of the tree.
* <p>
- * The fastest way to insert many items is documented in {@link org.eclipse.swt.widgets.TreeItem#TreeItem(Tree,int,int)}
- * and {@link org.eclipse.swt.widgets.TreeItem#setItemCount}
+ * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(Tree,int,int)}
+ * and {@link TreeItem#setItemCount}
*
* @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
@@ -126,8 +126,8 @@ public TreeItem (Tree parent, int style, int index) {
* Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
* Item is inserted as last direct child of the specified <code>TreeItem</code>.
* <p>
- * The fastest way to insert many items is documented in {@link org.eclipse.swt.widgets.TreeItem#TreeItem(Tree,int,int)}
- * and {@link org.eclipse.swt.widgets.TreeItem#setItemCount}
+ * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(Tree,int,int)}
+ * and {@link TreeItem#setItemCount}
*
* @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
@@ -152,8 +152,8 @@ public TreeItem (TreeItem parentItem, int style) {
* Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
* Item is inserted as <code>index</code> direct child of the specified <code>TreeItem</code>.
* <p>
- * The fastest way to insert many items is documented in {@link org.eclipse.swt.widgets.TreeItem#TreeItem(Tree,int,int)}
- * and {@link org.eclipse.swt.widgets.TreeItem#setItemCount}
+ * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(Tree,int,int)}
+ * and {@link TreeItem#setItemCount}
*
* @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
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java
index d9f38fd976..d20f9ca7c4 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java
@@ -105,7 +105,7 @@ public abstract class Widget {
static final int DEFAULT_HEIGHT = 64;
Widget () {
- /* Do nothing */
+ notifyCreationTracker();
}
/**
@@ -143,6 +143,7 @@ public Widget (Widget parent, int style) {
this.style = style;
display = parent.display;
reskinWidget ();
+ notifyCreationTracker();
}
long accessibleHandle() {
@@ -1376,6 +1377,7 @@ void release (boolean destroy) {
}
}
}
+ notifyDisposalTracker();
}
void releaseChildren (boolean destroy) {
@@ -2190,4 +2192,16 @@ boolean writeSelectionToPasteboard(long id, long sel, long pasteboard, long type
return false;
}
+void notifyCreationTracker() {
+ if (WidgetSpy.isEnabled) {
+ WidgetSpy.getInstance().widgetCreated(this);
+ }
+}
+
+void notifyDisposalTracker() {
+ if (WidgetSpy.isEnabled) {
+ WidgetSpy.getInstance().widgetDisposed(this);
+ }
+}
+
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/library/make_common.mak b/bundles/org.eclipse.swt/Eclipse SWT/common/library/make_common.mak
index a2a919082b..429f0e5b6b 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/library/make_common.mak
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/library/make_common.mak
@@ -1,5 +1,5 @@
#*******************************************************************************
-# Copyright (c) 2000, 2021 IBM Corporation and others.
+# Copyright (c) 2000, 2022 IBM Corporation and others.
#
# This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
@@ -13,7 +13,7 @@
#*******************************************************************************
maj_ver=4
-min_ver=950
-rev=3
-comma_ver=4,950,3,0
+min_ver=952
+rev=6
+comma_ver=4,952,6,0
cef_ver=3071 \ No newline at end of file
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java
index 5dadc75cac..97837153a1 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java
@@ -2275,6 +2275,7 @@ public class SWT {
* <p><b>Used By:</b></p>
* <ul>
* <li><code>FormAttachment</code> in a <code>FormLayout</code></li>
+ * <li><code>BoderData</code> in a <code>BoderLayout</code></li>
* </ul>
*/
public static final int TOP = UP;
@@ -2299,6 +2300,7 @@ public class SWT {
* <ul>
* <li><code>FormAttachment</code> in a <code>FormLayout</code></li>
* <li><code>TabFolder</code></li>
+ * <li><code>BoderData</code> in a <code>BoderLayout</code></li>
* </ul>
*/
public static final int BOTTOM = DOWN;
@@ -2329,6 +2331,10 @@ public class SWT {
* This constant can also be used to representing the left keyboard
* location during a key event.
* </p>
+ * <p><b>Used By:</b></p>
+ * <ul>
+ * <li><code>BoderData</code> in a <code>BoderLayout</code></li>
+ * </ul>
*/
public static final int LEFT = LEAD;
@@ -2358,6 +2364,10 @@ public class SWT {
* This constant can also be used to representing the right keyboard
* location during a key event.
* </p>
+ * <p><b>Used By:</b></p>
+ * <ul>
+ * <li><code>BoderData</code> in a <code>BoderLayout</code></li>
+ * </ul>
*/
public static final int RIGHT = TRAIL;
@@ -2369,6 +2379,7 @@ public class SWT {
* <li><code>Label</code></li>
* <li><code>TableColumn</code></li>
* <li><code>FormAttachment</code> in a <code>FormLayout</code></li>
+ * <li><code>BoderData</code> in a <code>BoderLayout</code></li>
* </ul>
*/
public static final int CENTER = 1 << 24;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/SWTMessages.properties b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/SWTMessages.properties
index da86f4f1e8..1c9a2c67aa 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/SWTMessages.properties
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/SWTMessages.properties
@@ -126,3 +126,10 @@ SWT_ValidTo=Valid To
SWT_ValidFromTo=Valid from: {0} to: {1}
SWT_Subject=Subject
SWT_SerialNumber=Serial Number
+SWT_About=About
+SWT_Preferences=Preferences...
+SWT_Services=Services
+SWT_Hide=Hide
+SWT_HideOthers=Hide Others
+SWT_ShowAll=Show All
+SWT_Quit=Quit
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/WidgetSpy.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/WidgetSpy.java
new file mode 100644
index 0000000000..0acb6c3479
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/WidgetSpy.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Simeon Andreev 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:
+ * Simeon Andreev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.internal;
+
+import java.util.*;
+import java.util.List;
+
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Helper class to allow widget creation and disposal monitoring
+ */
+public class WidgetSpy {
+
+ /**
+ * Flag to prevent {@link Widget} from entering this class during debugging,
+ * if tracking of creation and disposal is not enabled.
+ */
+ public static boolean isEnabled;
+
+ private static final WidgetSpy instance = new WidgetSpy();
+
+ private WidgetTracker widgetTracker;
+
+ private WidgetSpy() {
+ // singleton
+ }
+
+ public static WidgetSpy getInstance() {
+ return instance;
+ }
+
+ /**
+ * Enables tracking of {@link Widget} object creation and disposal.
+ *
+ * WARNING: the tracker will be called from the UI thread. Do not block
+ * it and do not throw any exceptions.
+ *
+ * @param tracker notified when a widget is created or disposed. Use
+ * {@code null} to disable tracking. The tracker will be
+ * notified of widgets created and disposed after setting the tracker.
+ */
+ public void setWidgetTracker(WidgetTracker tracker) {
+ isEnabled = tracker != null;
+ widgetTracker = tracker;
+ }
+
+ public void widgetCreated(Widget widget) {
+ if (widgetTracker != null) {
+ widgetTracker.widgetCreated(widget);
+ }
+ }
+
+ public void widgetDisposed(Widget widget) {
+ if (widgetTracker != null) {
+ widgetTracker.widgetDisposed(widget);
+ }
+ }
+
+ /**
+ * Custom callback to register widget creation / disposal
+ */
+ public static interface WidgetTracker {
+ default void widgetCreated(Widget widget) {}
+
+ default void widgetDisposed(Widget widget) {}
+ }
+
+ /**
+ * Default implementation simply collects all created and not disposed widgets
+ */
+ public static class NonDisposedWidgetTracker implements WidgetTracker {
+
+ private final Map<Widget, Error> nonDisposedWidgets = new LinkedHashMap<>();
+ private final Set<Class<? extends Widget> > trackedTypes = new HashSet<>();
+
+ @Override
+ public void widgetCreated(Widget widget) {
+ boolean isTracked = isTracked(widget);
+ if (isTracked) {
+ Error creationException = new Error("Created widget of type: " + widget.getClass().getSimpleName());
+ nonDisposedWidgets.put(widget, creationException);
+ }
+ }
+
+ @Override
+ public void widgetDisposed(Widget widget) {
+ boolean isTracked = isTracked(widget);
+ if (isTracked) {
+ nonDisposedWidgets.remove(widget);
+ }
+ }
+
+ public Map<Widget, Error> getNonDisposedWidgets() {
+ return Collections.unmodifiableMap(nonDisposedWidgets);
+ }
+
+ public void startTracking() {
+ clearNonDisposedWidgets();
+ WidgetSpy.getInstance().setWidgetTracker(this);
+ }
+
+ private void clearNonDisposedWidgets() {
+ nonDisposedWidgets.clear();
+ }
+
+ public void stopTracking() {
+ WidgetSpy.getInstance().setWidgetTracker(null);
+ }
+
+ public void setTrackingEnabled(boolean enabled) {
+ if (enabled) {
+ startTracking();
+ } else {
+ stopTracking();
+ }
+ }
+
+ public void setTrackedTypes(List<Class<? extends Widget>> types) {
+ trackedTypes.clear();
+ trackedTypes.addAll(types);
+ }
+
+ private boolean isTracked(Widget widget) {
+ boolean isTrackingAllTypes = trackedTypes.isEmpty();
+ if (isTrackingAllTypes) {
+ return true;
+ }
+ if (widget != null) {
+ Class<? extends Widget> widgetType = widget.getClass();
+ if (trackedTypes.contains(widgetType)) {
+ return true;
+ }
+ for (Class<? extends Widget> filteredType : trackedTypes) {
+ if (filteredType.isAssignableFrom(widgetType)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/layout/BorderData.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/layout/BorderData.java
new file mode 100644
index 0000000000..bd4dfcb663
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/layout/BorderData.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Christoph Läubrich 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:
+ * Christoph Läubrich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.layout;
+
+import static org.eclipse.swt.SWT.*;
+
+import java.util.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Controls the several aspects of a {@link BorderLayout}.
+ *
+ * @since 3.119
+ */
+public final class BorderData {
+
+ private final Map<Control, Point> cachedSize = new IdentityHashMap<>(1);
+
+ public int hHint = SWT.DEFAULT;
+ public int wHint = SWT.DEFAULT;
+ public int region = SWT.CENTER;
+
+ /**
+ * creates a {@link BorderData} with default options
+ */
+ public BorderData() {
+ }
+
+ /**
+ * creates a {@link BorderData} initialized with the given region, valid values
+ * are {@link SWT#TOP}, {@link SWT#CENTER}, {@link SWT#LEFT}, {@link SWT#RIGHT},
+ * {@link SWT#BOTTOM}
+ *
+ * @param region the region valid values are {@link SWT#TOP},
+ * {@link SWT#CENTER}, {@link SWT#LEFT}, {@link SWT#RIGHT},
+ * {@link SWT#BOTTOM}
+ */
+ public BorderData(int region) {
+ this.region = region;
+ }
+
+ /**
+ * creates a {@link BorderData} initialized with the given region and width and
+ * height hints
+ *
+ * @param region the region valid values are {@link SWT#TOP},
+ * {@link SWT#CENTER}, {@link SWT#LEFT}, {@link SWT#RIGHT},
+ * {@link SWT#BOTTOM}
+ * @param widthHint the default hint for the width
+ * @param heightHint he default hint for the height
+ */
+ public BorderData(int region, int widthHint, int heightHint) {
+ this.region = region;
+ this.wHint = widthHint;
+ this.hHint = heightHint;
+ }
+
+ Point getSize(Control control) {
+ return cachedSize.computeIfAbsent(control, c -> c.computeSize(wHint, hHint, true));
+ }
+
+ void flushCache(Control control) {
+ cachedSize.remove(control);
+ }
+
+ @Override
+ public String toString() {
+ return "BorderData [region=" + getRegionString(region) + ", hHint=" + hHint + ", wHint=" + wHint + "]";
+ }
+
+ static String getRegionString(int region) {
+ switch (region) {
+ case SWT.TOP:
+ return "SWT.TOP";
+ case SWT.RIGHT:
+ return "SWT.RIGHT";
+ case SWT.BOTTOM:
+ return "SWT.BOTTOM";
+ case SWT.LEFT:
+ return "SWT.LEFT";
+ case SWT.CENTER:
+ return "SWT.CENTER";
+ default:
+ return "SWT.NONE";
+ }
+ }
+
+ /**
+ *
+ * @return the region of this BorderData or {@link SWT#NONE} if it is out of
+ * range
+ */
+ int getRegion() {
+ switch (region) {
+ case TOP:
+ case BOTTOM:
+ case CENTER:
+ case RIGHT:
+ case LEFT:
+ return region;
+ case SWT.NONE:
+ default:
+ return SWT.NONE;
+ }
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/layout/BorderLayout.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/layout/BorderLayout.java
new file mode 100644
index 0000000000..4f6b176971
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/layout/BorderLayout.java
@@ -0,0 +1,420 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Christoph Läubrich 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:
+ * Christoph Läubrich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.layout;
+
+import static org.eclipse.swt.SWT.*;
+
+import java.util.*;
+import java.util.AbstractMap.*;
+import java.util.List;
+import java.util.Map.*;
+import java.util.function.*;
+import java.util.stream.*;
+import java.util.stream.IntStream.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * {@link BorderLayout} places controls in five regions
+ *
+ * <pre>
+ * +--------------------------------+
+ * | NORTH / TOP |
+ * +---+------------------------+---+
+ * | | | |
+ * | W | | E |
+ * | E | | A |
+ * | S | | S |
+ * | T | | T |
+ * | / | | / |
+ * | L | CENTER | R |
+ * | E | | I |
+ * | F | | G |
+ * | T | | H |
+ * | | | T |
+ * | | | |
+ * +---+------------------------+---+
+ * | SOUTH / BOTTOM |
+ * +--------------------------------+
+ * </pre>
+ *
+ * The controls at the NORTH/SOUTH borders get their preferred heights, the
+ * controls at the EAST/WEST get their preferred widths and the center region
+ * grow/shrink according to the remaining space. If more than one control is
+ * placed inside a region the controls are equally distributed across their axis
+ * where the grow (CENTER controlled by the {@link BorderLayout#type} value)
+ *
+ * @since 3.119
+ */
+public class BorderLayout extends Layout {
+
+ private static final ToIntFunction<Point> WIDTH = p -> p.x;
+ private static final ToIntFunction<Point> HEIGHT = p -> p.y;
+
+ /**
+ * type specifies how controls will be positioned within the center region.
+ *
+ * The default value is {@link SWT#HORIZONTAL}.
+ *
+ * Possible values are:
+ * <ul>
+ * <li>{@link SWT#HORIZONTAL}: Position the controls horizontally from left to
+ * right</li>
+ * <li>{@link SWT#VERTICAL}: Position the controls vertically from top to
+ * bottom</li>
+ * </ul>
+ */
+ 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.
+ *
+ */
+ 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;
+ /**
+ * spacing specifies the number of points between the edge of one region and its
+ * neighboring regions.
+ *
+ * The default value is 0.
+ *
+ */
+ public int spacing = 0;
+ /**
+ * controlSpacing specifies the number of points between the edge of one control
+ * and its neighboring control inside a region.
+ *
+ * The default value is 0.
+ *
+ */
+ public int controlSpacing = 0;
+ /**
+ * If the width of the {@link SWT#LEFT} and {@link SWT#RIGHT} region exceeds the
+ * available space this factor is used to distribute the size to the controls,
+ * valid values range between [0 ... 1]
+ *
+ * The default value is 0.5 (equal distribution of available space)
+ */
+ public double widthDistributionFactor = 0.5;
+ /**
+ * If the height of the {@link SWT#TOP} and {@link SWT#BOTTOM} region exceeds the
+ * available space this factor is used to distribute the size to the controls,
+ * valid values range between [0 ... 1]
+ *
+ * The default value is 0.5 (equal distribution of available space)
+ *
+ */
+ public double heightDistributionFactor = 0.5;
+
+ @Override
+ protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
+ if (hHint > SWT.DEFAULT && wHint > SWT.DEFAULT) {
+ return new Point(wHint, hHint);
+ }
+ Stream<Entry<Control, BorderData>> children = Arrays.stream(composite.getChildren())//
+ .map(control-> borderDataControl(control, flushCache));
+ Map<Integer, List<Entry<Control, BorderData>>> regionMap = children
+ .collect(Collectors.groupingBy(BorderLayout::region));
+ int width;
+ if (wHint <= SWT.DEFAULT) {
+ Builder widthBuilder = IntStream.builder();
+ int northWidth = getTotal(WIDTH, TOP, regionMap);
+ int southWidth = getTotal(WIDTH, BOTTOM, regionMap);
+ int centerWidth;
+ if (type == SWT.HORIZONTAL) {
+ centerWidth = getTotal(WIDTH, CENTER, regionMap);
+ } else {
+ centerWidth = getMax(WIDTH, CENTER, regionMap);
+ }
+ int westWidth = getMax(WIDTH, LEFT, regionMap);
+ int eastWidth = getMax(WIDTH, RIGHT, regionMap);
+ int middleWidth = westWidth + centerWidth + eastWidth;
+ if (centerWidth > 0) {
+ if (westWidth > 0) {
+ middleWidth += spacing;
+ }
+ if (eastWidth > 0) {
+ middleWidth += spacing;
+ }
+ } else if (westWidth > 0 && eastWidth > 0) {
+ middleWidth += spacing;
+ }
+ widthBuilder.add(middleWidth);
+ widthBuilder.add(northWidth);
+ widthBuilder.add(southWidth);
+ width = widthBuilder.build().max().orElse(0) + 2 * marginWidth;
+ } else {
+ width = wHint;
+ }
+ int height;
+ if (hHint <= SWT.DEFAULT) {
+ Builder heightBuilder = IntStream.builder();
+ int northHeight = getMax(HEIGHT, TOP, regionMap);
+ int southHeight = getMax(HEIGHT, BOTTOM, regionMap);
+ int westHeight = getTotal(HEIGHT, LEFT, regionMap);
+ int eastHeight = getTotal(HEIGHT, RIGHT, regionMap);
+ int centerHeight;
+ if (type == SWT.HORIZONTAL) {
+ centerHeight = getMax(HEIGHT, CENTER, regionMap);
+ } else {
+ centerHeight = getTotal(HEIGHT, CENTER, regionMap);
+ }
+ if (centerHeight > 0) {
+ if (northHeight > 0) {
+ centerHeight += spacing;
+ }
+ if (southHeight > 0) {
+ centerHeight += spacing;
+ }
+ }
+ if (westHeight > 0) {
+ if (northHeight > 0) {
+ westHeight += spacing;
+ }
+ if (southHeight > 0) {
+ westHeight += spacing;
+ }
+ }
+ if (eastHeight > 0) {
+ if (northHeight > 0) {
+ eastHeight += spacing;
+ }
+ if (southHeight > 0) {
+ eastHeight += spacing;
+ }
+ }
+ int sum = northHeight + southHeight;
+ heightBuilder.add(westHeight + sum);
+ heightBuilder.add(centerHeight + sum);
+ heightBuilder.add(eastHeight + sum);
+ height = heightBuilder.build().max().orElse(0) + 2 * marginHeight;
+ } else {
+ height = hHint;
+ }
+ return new Point(width, height);
+ }
+
+ /**
+ * Calculates the total W/H according to the extractor
+ *
+ * @param extractor either {@link #WIDTH} or {@link #HEIGHT}
+ * @param region the region to compute
+ * @param regionMap the map of regions
+ * @return the total W/H including the {@link #controlSpacing}
+ */
+ private int getTotal(ToIntFunction<Point> extractor, int region,
+ Map<Integer, List<Entry<Control, BorderData>>> regionMap) {
+ List<Entry<Control, BorderData>> list = regionMap.getOrDefault(region, Collections.emptyList());
+ if (list.isEmpty()) {
+ return 0;
+ }
+ return list.stream().mapToInt(entry -> extractor.applyAsInt(entry.getValue().getSize(entry.getKey()))).sum()
+ + ((list.size() - 1) * controlSpacing);
+ }
+
+ private static int getMax(ToIntFunction<Point> extractor, int region,
+ Map<Integer, List<Entry<Control, BorderData>>> regionMap) {
+ List<Entry<Control, BorderData>> list = regionMap.getOrDefault(region, Collections.emptyList());
+ return getMax(extractor, list);
+ }
+
+ private static int getMax(ToIntFunction<Point> extractor, List<Entry<Control, BorderData>> list) {
+ return list.stream().mapToInt(entry -> extractor.applyAsInt(entry.getValue().getSize(entry.getKey()))).max()
+ .orElse(0);
+ }
+
+ @Override
+ protected void layout(Composite composite, boolean flushCache) {
+ Rectangle clientArea = composite.getClientArea();
+ int clientX = clientArea.x + marginWidth;
+ int clientY = clientArea.y + marginHeight;
+ int clientWidth = clientArea.width - 2 * marginWidth;
+ int clientHeight = clientArea.height - 2 * marginHeight;
+ Stream<Entry<Control, BorderData>> children = Arrays.stream(composite.getChildren())//
+ .map(control-> borderDataControl(control, flushCache));
+ Map<Integer, List<Entry<Control, BorderData>>> regionMap = children
+ .collect(Collectors.groupingBy(BorderLayout::region));
+ regionMap.getOrDefault(SWT.NONE, Collections.emptyList())
+ .forEach(entry -> entry.getKey().setBounds(clientX, clientY, 0, 0));
+ List<Entry<Control, BorderData>> northList = regionMap.getOrDefault(TOP, Collections.emptyList());
+ List<Entry<Control, BorderData>> southList = regionMap.getOrDefault(BOTTOM, Collections.emptyList());
+ List<Entry<Control, BorderData>> westList = regionMap.getOrDefault(LEFT, Collections.emptyList());
+ List<Entry<Control, BorderData>> eastList = regionMap.getOrDefault(RIGHT, Collections.emptyList());
+ List<Entry<Control, BorderData>> centerList = regionMap.getOrDefault(CENTER, Collections.emptyList());
+ int northControlCount = northList.size();
+ int northControlHeight = getMax(HEIGHT, northList);
+ int southControlCount = southList.size();
+ int southControlHeight = getMax(HEIGHT, southList);
+ if (northControlHeight + southControlHeight > clientHeight) {
+ int distributionSize = (int) (clientHeight * heightDistributionFactor);
+ if (northControlHeight > distributionSize) {
+ northControlHeight = distributionSize;
+ }
+ southControlHeight = clientHeight - northControlHeight;
+ }
+ int centerControlHeight = clientHeight - northControlHeight - southControlHeight;
+ int westControlCount = westList.size();
+ int westControlWidth = getMax(WIDTH, westList);
+ int eastControlCount = eastList.size();
+ int eastControlWidth = getMax(WIDTH, eastList);
+ if (westControlWidth + eastControlWidth > clientWidth) {
+ int distributionSize = (int) (clientWidth * widthDistributionFactor);
+ if (westControlWidth > distributionSize) {
+ westControlWidth = distributionSize;
+ }
+ eastControlWidth = clientWidth - westControlWidth;
+ }
+ int centerControlWidth = clientWidth - westControlWidth - eastControlWidth;
+ int centerControlCount = centerList.size();
+ // Full width and preferred height for NORTH and SOUTH if possible
+ if (northControlCount > 0) {
+ int controlWidth = (clientWidth - (northControlCount - 1) * controlSpacing) / northControlCount;
+ int x = clientX;
+ int y = clientY;
+ for (Entry<Control, BorderData> entry : northList) {
+ entry.getKey().setBounds(x, y, controlWidth, northControlHeight);
+ x += controlWidth + controlSpacing;
+ }
+ }
+ if (southControlCount > 0) {
+ int controlWidth = (clientWidth - (southControlCount - 1) * controlSpacing) / southControlCount;
+ int x = clientX;
+ int y = clientY + centerControlHeight + northControlHeight;
+ for (Entry<Control, BorderData> entry : southList) {
+ entry.getKey().setBounds(x, y, controlWidth, southControlHeight);
+ x += controlWidth + controlSpacing;
+ }
+ }
+ // remaining height for WEST and EAST, preferred width for WEST and EAST if
+ // possible ...
+ if (westControlCount > 0) {
+ int x = clientX;
+ int y = clientY + northControlHeight;
+ int h = clientHeight - northControlHeight - southControlHeight;
+ if (northControlCount > 0) {
+ y += spacing;
+ h -= spacing;
+ }
+ if (southControlCount > 0) {
+ h -= spacing;
+ }
+ int controlHeight = (h - (westControlCount - 1) * controlSpacing) / westControlCount;
+ for (Entry<Control, BorderData> entry : westList) {
+ entry.getKey().setBounds(x, y, westControlWidth, controlHeight);
+ y += controlHeight + controlSpacing;
+ }
+ }
+ if (eastControlCount > 0) {
+ int x = clientX + centerControlWidth + westControlWidth;
+ int y = clientY + northControlHeight;
+ int h = clientHeight - northControlHeight - southControlHeight;
+ if (northControlCount > 0) {
+ y += spacing;
+ h -= spacing;
+ }
+ if (southControlCount > 0) {
+ h -= spacing;
+ }
+ int controlHeight = (h - (eastControlCount - 1) * controlSpacing) / eastControlCount;
+ for (Entry<Control, BorderData> entry : eastList) {
+ entry.getKey().setBounds(x, y, eastControlWidth, controlHeight);
+ y += controlHeight + controlSpacing;
+ }
+ }
+ // remaining height and width for CENTER
+ if (centerControlCount > 0) {
+ int x = clientX + westControlWidth;
+ int y = clientY + northControlHeight;
+ int h = centerControlHeight;
+ int w = centerControlWidth;
+ if (westControlCount > 0) {
+ x += spacing;
+ w -= spacing;
+ }
+ if (eastControlCount > 0) {
+ w -= spacing;
+ }
+ if (northControlCount > 0) {
+ y += spacing;
+ h -= spacing;
+ }
+ if (southControlCount > 0) {
+ h -= spacing;
+ }
+ int controlHeight;
+ int controlWidth;
+ if (type == SWT.HORIZONTAL) {
+ controlHeight = h;
+ controlWidth = (w - (centerControlCount - 1) * controlSpacing) / centerControlCount;
+ } else {
+ controlWidth = w;
+ controlHeight = (h - (centerControlCount - 1) * controlSpacing) / centerControlCount;
+ }
+ for (Entry<Control, BorderData> entry : centerList) {
+ entry.getKey().setBounds(x, y, controlWidth, controlHeight);
+ if (type == SWT.HORIZONTAL) {
+ x += controlWidth + controlSpacing;
+ } else {
+ y += controlHeight + controlSpacing;
+ }
+ }
+ }
+ }
+
+ private static <C extends Control> Entry<C, BorderData> borderDataControl(C control, boolean flushCache) {
+ Object layoutData = control.getLayoutData();
+ if (layoutData instanceof BorderData) {
+ BorderData borderData = (BorderData) layoutData;
+ if (flushCache) {
+ borderData.flushCache(control);
+ }
+ return new SimpleEntry<>(control, borderData);
+ } else {
+ return new SimpleEntry<>(control, null);
+ }
+ }
+
+ private static int region(Entry<Control, BorderData> entry) {
+ BorderData borderData = entry.getValue();
+ if (borderData == null) {
+ //we assume all controls without explicit data to be placed in the center area
+ return SWT.CENTER;
+ }
+ return borderData.getRegion();
+ }
+
+ @Override
+ public String toString() {
+ return "BorderLayout [" //
+ + "type=" + ((type == SWT.HORIZONTAL) ? "SWT.HORIZONTAL" : "SWT.VERTICAL") //
+ + ", marginWidth=" + marginWidth //
+ + ", marginHeight=" + marginHeight //
+ + ", spacing=" + spacing //
+ + ", controlSpacing=" + controlSpacing //
+ + ", widthDistributionFactor=" + widthDistributionFactor//
+ + ", heightDistributionFactor=" + heightDistributionFactor //
+ + "]";
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/version.txt b/bundles/org.eclipse.swt/Eclipse SWT/common/version.txt
index f423d893b9..ccc5290de9 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/version.txt
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/version.txt
@@ -1 +1 @@
-version 4.950 \ No newline at end of file
+version 4.952 \ No newline at end of file
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java
index ec5d50b551..7a0f7aee60 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java
@@ -17,11 +17,13 @@ package org.eclipse.swt.graphics;
import java.io.*;
import java.util.*;
+import java.util.List;
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.gtk.*;
import org.eclipse.swt.internal.image.*;
+import org.eclipse.swt.widgets.*;
/**
* Instances of this class are used to load images from,
@@ -176,16 +178,12 @@ boolean isInterlacedPNG(byte [] imageAsByteArray) {
}
ImageData [] getImageDataArrayFromStream(InputStream stream) {
- byte[] buffer = new byte[2048];
long loader = GDK.gdk_pixbuf_loader_new();
- int length;
List<ImageData> imgDataList = new ArrayList<>();
try {
// 1) Load InputStream into byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- while ((length = stream.read(buffer)) > -1) {
- baos.write(buffer, 0, length);
- }
+ stream.transferTo(baos);
baos.flush();
byte[] data_buffer = baos.toByteArray();
if (data_buffer.length == 0) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); // empty stream
@@ -193,7 +191,20 @@ ImageData [] getImageDataArrayFromStream(InputStream stream) {
// 2) Copy byte array to C memory, write to GdkPixbufLoader
long buffer_ptr = OS.g_malloc(data_buffer.length);
C.memmove(buffer_ptr, data_buffer, data_buffer.length);
- GDK.gdk_pixbuf_loader_write(loader, buffer_ptr, data_buffer.length, null);
+ long [] error = new long [1];
+ GDK.gdk_pixbuf_loader_write(loader, buffer_ptr, data_buffer.length, error);
+ if(error[0] != 0) {
+ /* Bug 576484
+ * It is safe just to assume if this fails it is most likely an IO error
+ * since unsupported format is checked before, and invalid image right after.
+ * Still, check if it belongs to the G_FILE_ERROR domain and IO error code
+ */
+ if(OS.g_error_matches(error[0], OS.g_file_error_quark(), OS.G_FILE_ERROR_IO)){
+ SWT.error(SWT.ERROR_IO, null, Display.extractFreeGError(error[0]));
+ } else {
+ OS.g_error_free(error[0]);
+ }
+ }
GDK.gdk_pixbuf_loader_close(loader, null);
// 3) Get GdkPixbufAnimation from loader
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/GDBus.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/GDBus.java
index 8bda62b217..78def99d4a 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/GDBus.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/GDBus.java
@@ -335,7 +335,7 @@ public class GDBus {
*
* @param gVariant a pointer to the native GVariant
*/
- private static Object[] convertGVariantToJava(long gVariant) {
+ public static Object[] convertGVariantToJava(long gVariant) {
Object retVal = convertGVariantToJavaHelper(gVariant);
if (retVal instanceof Object[]) {
return (Object[]) retVal;
@@ -405,7 +405,7 @@ public class GDBus {
*
* @return pointer GVariant *
*/
- private static long convertJavaToGVariant(Object javaObject) throws SWTException {
+ public static long convertJavaToGVariant(Object javaObject) throws SWTException {
if (javaObject == null) {
return 0;
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Button.java
index 07609de651..10a2f92441 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Button.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Button.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2020 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -304,7 +304,7 @@ void createHandle (int index) {
switch (style & bits) {
case SWT.ARROW:
- byte arrowType [] = GTK.GTK_NAMED_ICON_GO_UP;
+ byte[] arrowType = GTK.GTK_NAMED_ICON_GO_UP;
if ((style & SWT.UP) != 0) arrowType = GTK.GTK_NAMED_ICON_GO_UP;
if ((style & SWT.DOWN) != 0) arrowType = GTK.GTK_NAMED_ICON_GO_DOWN;
if ((style & SWT.LEFT) != 0) arrowType = GTK.GTK_NAMED_ICON_GO_PREVIOUS;
@@ -844,7 +844,7 @@ void _setAlignment (int alignment) {
style &= ~(SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
style |= alignment & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
boolean isRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
- byte arrowType [] = GTK.GTK_NAMED_ICON_GO_UP;
+ byte[] arrowType = GTK.GTK_NAMED_ICON_GO_UP;
switch (alignment) {
case SWT.UP: arrowType = GTK.GTK_NAMED_ICON_GO_UP; break;
case SWT.DOWN: arrowType = GTK.GTK_NAMED_ICON_GO_DOWN; break;
@@ -1187,7 +1187,7 @@ void setOrientation (boolean create) {
if (labelHandle != 0) GTK.gtk_widget_set_direction (labelHandle, dir);
if (imageHandle != 0) GTK.gtk_widget_set_direction (imageHandle, dir);
if (arrowHandle != 0) {
- byte arrowType [] = (style & SWT.RIGHT_TO_LEFT) != 0 ? GTK.GTK_NAMED_ICON_GO_NEXT : GTK.GTK_NAMED_ICON_GO_PREVIOUS;
+ byte[] arrowType = (style & SWT.RIGHT_TO_LEFT) != 0 ? GTK.GTK_NAMED_ICON_GO_NEXT : GTK.GTK_NAMED_ICON_GO_PREVIOUS;
switch (style & (SWT.LEFT | SWT.RIGHT)) {
case SWT.LEFT: GTK3.gtk_image_set_from_icon_name (arrowHandle, arrowType, GTK.GTK_ICON_SIZE_MENU); break;
case SWT.RIGHT: GTK3.gtk_image_set_from_icon_name (arrowHandle, arrowType, GTK.GTK_ICON_SIZE_MENU); break;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
index ffdbf489ac..d3bb60ab59 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
@@ -57,6 +57,8 @@ public abstract class Control extends Widget implements Drawable {
static final boolean DISABLE_EMOJI = Boolean.getBoolean("SWT_GTK_INPUT_HINT_NO_EMOJI");
long fixedHandle;
+ long firstFixedHandle = 0;
+ long keyController;
long redrawWindow, enableWindow, provider;
int drawCount, backgroundAlpha = 255;
long dragGesture, zoomGesture, rotateGesture, panGesture;
@@ -432,7 +434,7 @@ void hookEvents () {
private void hookKeyboardAndFocusSignals(long focusHandle) {
if (GTK.GTK4) {
- long keyController = GTK4.gtk_event_controller_key_new();
+ keyController = GTK4.gtk_event_controller_key_new();
GTK4.gtk_widget_add_controller(focusHandle, keyController);
GTK.gtk_event_controller_set_propagation_phase(keyController, GTK.GTK_PHASE_CAPTURE);
OS.g_signal_connect(keyController, OS.key_pressed, display.keyPressReleaseProc, KEY_PRESSED);
@@ -3926,6 +3928,25 @@ void gtk4_focus_enter_event(long controller, long event) {
}
@Override
+void gtk4_focus_window_event(long handle, long event) {
+ super.gtk4_focus_window_event(handle, event);
+
+ if(firstFixedHandle == 0) {
+ long child = handle;
+ //3rd child of shell will be SWTFixed
+ for(int i = 0; i<3; i++) {
+ child = GTK4.gtk_widget_get_first_child(child);
+ }
+ firstFixedHandle = child != 0 ? child:0;
+ }
+
+ if(firstFixedHandle !=0 && GTK.gtk_widget_has_focus(firstFixedHandle)) {
+ if(event == SWT.FocusIn)sendFocusEvent(SWT.FocusIn);
+ else sendFocusEvent(SWT.FocusOut);
+ }
+}
+
+@Override
long gtk_focus_out_event (long widget, long event) {
// widget could be disposed at this point
if (handle != 0) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
index 4dfc47fb1f..4eaa9e6cff 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
@@ -132,13 +132,13 @@ public class Display extends Device {
Callback eventCallback;
long eventProc, windowProc2, windowProc3, windowProc4, windowProc5, windowProc6;
long changeValueProc;
- long snapshotDrawProc, keyPressReleaseProc, focusProc, enterMotionProc, leaveProc,
+ long snapshotDrawProc, keyPressReleaseProc, focusProc, windowActiveProc, enterMotionProc, leaveProc,
scrollProc, resizeProc, activateProc, gesturePressReleaseProc;
long notifyProc;
long computeSizeProc;
Callback windowCallback2, windowCallback3, windowCallback4, windowCallback5, windowCallback6;
Callback changeValue;
- Callback snapshotDraw, keyPressReleaseCallback, focusCallback, enterMotionCallback, computeSizeCallback,
+ Callback snapshotDraw, keyPressReleaseCallback, focusCallback, windowActiveCallback, enterMotionCallback, computeSizeCallback,
scrollCallback, leaveCallback, resizeCallback, activateCallback, gesturePressReleaseCallback;
Callback notifyCallback;
EventTable eventTable, filterTable;
@@ -222,19 +222,6 @@ public class Display extends Device {
SessionManagerListener sessionManagerListener;
Runnable [] disposeList;
- /*
- * DBus objects to be freed upong Display release. Only public for use in
- * other areas of SWT (i.e. WebKit). See bug 540060.
- */
- /** @noreference */
- public java.util.List<Long> dBusServers = new ArrayList<>();
- /** @noreference */
- public java.util.List<Long> dBusAuthObservers = new ArrayList<>();
- /** @noreference */
- public java.util.List<Long> dBusGUIDS = new ArrayList<>();
- /** @noreference */
- public java.util.List<Long> dBusConnections = new ArrayList<>();
-
/* Deferred Layout list */
Composite[] layoutDeferred;
int layoutDeferredCount;
@@ -3573,6 +3560,9 @@ void initializeCallbacks () {
focusCallback = new Callback(this, "focusProc", void.class, new Type[] {long.class, long.class}); //$NON-NLS-1$
focusProc = focusCallback.getAddress();
+ windowActiveCallback = new Callback(this, "windowActiveProc", void.class, new Type[] {long.class, long.class}); //$NON-NLS-1$
+ windowActiveProc = windowActiveCallback.getAddress();
+
enterMotionCallback = new Callback(this, "enterMotionProc", void.class, new Type[] {
long.class, double.class, double.class, long.class}); //$NON-NLS-1$
enterMotionProc = enterMotionCallback.getAddress ();
@@ -3850,44 +3840,6 @@ void initializeSessionManager() {
}
/**
- * Some parts of SWT (like WebKit) use GDBus for IPC. Some of these objects
- * cannot be disposed of in their own classes due to design challenges.
- * In these instances we release them along with this Display. This ensures
- * no Browser will be using them at disposal time.
- */
-void releaseDBusServices() {
- releaseSessionManager();
- for (long connection : dBusConnections) {
- if (OS.g_dbus_connection_is_closed(connection)) continue;
- long [] error = new long [1];
- boolean closed = OS.g_dbus_connection_close_sync(connection, 0, error);
- if (error[0] != 0) {
- String msg = extractFreeGError(error[0]);
- System.err.println("SWT Display: error closing connection: " + msg);
- }
- if (closed) {
- // Free this as we added a reference to it
- OS.g_object_unref(connection);
- }
- }
- for (long server : dBusServers) {
- OS.g_dbus_server_stop(server);
- OS.g_object_unref(server);
- }
- for (long authObserver : dBusAuthObservers) {
- OS.g_object_unref(authObserver);
- }
- for (long guid : dBusGUIDS) {
- OS.g_free(guid);
- }
- dBusConnections.clear();
- dBusServers.clear();
- dBusAuthObservers.clear();
- dBusGUIDS.clear();
- dBusServers = dBusAuthObservers = dBusGUIDS = dBusConnections = null;
-}
-
-/**
* Helper method to extract GError messages. Only call if the pointer is valid (i.e. non-zero).
*
* @param errorPtr pointer to the GError
@@ -4670,7 +4622,6 @@ protected void release () {
synchronizer.releaseSynchronizer ();
synchronizer = null;
- releaseDBusServices ();
releaseSessionManager ();
releaseDisplay ();
super.release ();
@@ -4701,6 +4652,10 @@ void releaseDisplay () {
focusCallback = null;
focusProc = 0;
+ windowActiveCallback.dispose();
+ windowActiveCallback = null;
+ windowActiveProc = 0;
+
enterMotionCallback.dispose();
enterMotionCallback = null;
enterMotionProc = 0;
@@ -6130,13 +6085,18 @@ boolean scrollProc(long controller, double dx, double dy, long user_data) {
return false;
}
-void focusProc(long controller, long user_data) {
+void focusProc(long controller, long user_data) {;
long handle = GTK.gtk_event_controller_get_widget(controller);
Widget widget = getWidget(handle);
if (widget != null) widget.focusProc(controller, user_data);
}
+void windowActiveProc(long handle, long user_data) {;
+ Widget widget = getWidget(handle);
+ if (widget != null) widget.windowActiveProc(handle, user_data);
+}
+
boolean keyPressReleaseProc(long controller, int keyval, int keycode, int state, long user_data) {
long handle = GTK.gtk_event_controller_get_widget(controller);
Widget widget = getWidget(handle);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
index 23db4e2023..224734ad0e 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
@@ -947,6 +947,7 @@ void hookEvents () {
}
if (GTK.GTK4) {
OS.g_signal_connect_closure (shellHandle, OS.close_request, display.getClosure (CLOSE_REQUEST), false);
+ OS.g_signal_connect(shellHandle, OS.notify_is_active, display.windowActiveProc, FOCUS_IN);
long keyController = GTK4.gtk_event_controller_key_new();
GTK4.gtk_widget_add_controller(shellHandle, keyController);
GTK.gtk_event_controller_set_propagation_phase(keyController, GTK.GTK_PHASE_TARGET);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
index 1e0ec9eca1..cc67a0eef6 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
@@ -2961,6 +2961,32 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
}
}
}
+
+ GdkRectangle rendererRect = new GdkRectangle ();
+ GdkRectangle columnRect = new GdkRectangle ();
+ int y_offset;
+ {
+ /*
+ * SWT creates multiple renderers (kind of sub-columns) per column.
+ * For example: one for checkbox, one for image, one for text.
+ * 'background_area' argument in this function is area of currently
+ * painted renderer. However, for SWT.EraseItem and SWT.PaintItem,
+ * SWT wants entire column's area along with the event. There's api
+ * 'gtk_tree_view_get_background_area()' but it calculates item's
+ * rect in control, which will have wrong Y if item is rendered
+ * separately (for example, for drag image).
+ * The workaround is to take X range from api and Y range from argument.
+ */
+ OS.memmove (rendererRect, background_area, GdkRectangle.sizeof);
+
+ long path = GTK.gtk_tree_model_get_path (modelHandle, iter);
+ GTK.gtk_tree_view_get_background_area (handle, path, columnHandle, columnRect);
+ GTK.gtk_tree_path_free (path);
+
+ y_offset = columnRect.y - rendererRect.y;
+ columnRect.y -= y_offset;
+ }
+
if (item != null) {
if (GTK.GTK_IS_CELL_RENDERER_TOGGLE (cell) || (columnIndex != 0 || (style & SWT.CHECK) == 0)) {
drawFlags = (int)flags;
@@ -2980,10 +3006,7 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
if ((flags & GTK.GTK_CELL_RENDERER_FOCUSED) != 0) drawState |= SWT.FOCUSED;
}
- GdkRectangle rect = new GdkRectangle ();
- long path = GTK.gtk_tree_model_get_path (modelHandle, iter);
- GTK.gtk_tree_view_get_background_area (handle, path, columnHandle, rect);
- GTK.gtk_tree_path_free (path);
+ Rectangle rect = columnRect.toRectangle ();
if ((drawState & SWT.SELECTED) == 0) {
if ((state & PARENT_BACKGROUND) != 0 || backgroundImage != null) {
Control control = findBackgroundControl ();
@@ -3029,23 +3052,36 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
if (cr != 0) {
GdkRectangle r = new GdkRectangle();
GDK.gdk_cairo_get_clip_rectangle(cr, r);
- Rectangle rect2 = DPIUtil.autoScaleDown(new Rectangle(rect.x, r.y, r.width, r.height));
+ Rectangle rect2 = DPIUtil.autoScaleDown(rect);
// Caveat: rect2 is necessary because GC#setClipping(Rectangle) got broken by bug 446075
gc.setClipping(rect2.x, rect2.y, rect2.width, rect2.height);
} else {
- Rectangle rect2 = DPIUtil.autoScaleDown(new Rectangle(rect.x, rect.y, rect.width, rect.height));
+ Rectangle rect2 = DPIUtil.autoScaleDown(rect);
// Caveat: rect2 is necessary because GC#setClipping(Rectangle) got broken by bug 446075
gc.setClipping(rect2.x, rect2.y, rect2.width, rect2.height);
}
+
+ // SWT.PaintItem/SWT.EraseItem often expect that event.y matches
+ // what 'event.item.getBounds()' returns. The workaround is to
+ // adjust coordinate system temporarily.
Event event = new Event ();
- event.item = item;
- event.index = columnIndex;
- event.gc = gc;
- event.detail = drawState;
- Rectangle eventRect = new Rectangle (rect.x, rect.y, rect.width, rect.height);
- event.setBounds (DPIUtil.autoScaleDown (eventRect));
- sendEvent (SWT.EraseItem, event);
+ try {
+ Rectangle eventRect = new Rectangle (rect.x, rect.y, rect.width, rect.height);
+
+ eventRect.y += y_offset;
+ Cairo.cairo_translate (cr, 0, -y_offset);
+
+ event.item = item;
+ event.index = columnIndex;
+ event.gc = gc;
+ event.detail = drawState;
+ event.setBounds (DPIUtil.autoScaleDown (eventRect));
+ sendEvent (SWT.EraseItem, event);
+ } finally {
+ Cairo.cairo_translate (cr, 0, y_offset);
+ }
+
drawForegroundRGBA = null;
drawState = event.doit ? event.detail : 0;
drawFlags &= ~(GTK.GTK_CELL_RENDERER_FOCUSED | GTK.GTK_CELL_RENDERER_SELECTED);
@@ -3074,9 +3110,7 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
if ((drawState & SWT.BACKGROUND) != 0 && (drawState & SWT.SELECTED) == 0) {
GC gc = getGC(cr);
gc.setBackground (item.getBackground (columnIndex));
- GdkRectangle rect = new GdkRectangle ();
- OS.memmove (rect, background_area, GdkRectangle.sizeof);
- gc.fillRectangle(DPIUtil.autoScaleDown(new Rectangle(rect.x, rect.y, rect.width, rect.height)));
+ gc.fillRectangle (DPIUtil.autoScaleDown (rendererRect.toRectangle ()));
gc.dispose ();
}
if ((drawState & SWT.FOREGROUND) != 0 || GTK.GTK_IS_CELL_RENDERER_TOGGLE (cell)) {
@@ -3102,10 +3136,7 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
if (GTK.GTK_IS_CELL_RENDERER_TEXT (cell)) {
if (hooks (SWT.PaintItem)) {
if (wasSelected) drawState |= SWT.SELECTED;
- GdkRectangle rect = new GdkRectangle ();
- long path = GTK.gtk_tree_model_get_path (modelHandle, iter);
- GTK.gtk_tree_view_get_background_area (handle, path, columnHandle, rect);
- GTK.gtk_tree_path_free (path);
+ Rectangle rect = columnRect.toRectangle ();
ignoreSize = true;
int [] contentX = new int [1], contentWidth = new int [1];
gtk_cell_renderer_get_preferred_size (cell, handle, contentWidth, null);
@@ -3149,18 +3180,30 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
gc.setFont (item.getFont (columnIndex));
if ((style & SWT.MIRRORED) != 0) rect.x = getClientWidth () - rect.width - rect.x;
- Rectangle rect2 = DPIUtil.autoScaleDown(new Rectangle(rect.x, rect.y, rect.width, rect.height));
+ Rectangle rect2 = DPIUtil.autoScaleDown(rect);
// Caveat: rect2 is necessary because GC#setClipping(Rectangle) got broken by bug 446075
gc.setClipping(rect2.x, rect2.y, rect2.width, rect2.height);
+ // SWT.PaintItem/SWT.EraseItem often expect that event.y matches
+ // what 'event.item.getBounds()' returns. The workaround is to
+ // adjust coordinate system temporarily.
Event event = new Event ();
- event.item = item;
- event.index = columnIndex;
- event.gc = gc;
- Rectangle eventRect = new Rectangle (rect.x + contentX [0], rect.y, contentWidth [0], rect.height);
- event.setBounds (DPIUtil.autoScaleDown (eventRect));
- event.detail = drawState;
- sendEvent (SWT.PaintItem, event);
+ try {
+ Rectangle eventRect = new Rectangle (rect.x + contentX [0], rect.y, contentWidth [0], rect.height);
+
+ eventRect.y += y_offset;
+ Cairo.cairo_translate (cr, 0, -y_offset);
+
+ event.item = item;
+ event.index = columnIndex;
+ event.gc = gc;
+ event.detail = drawState;
+ event.setBounds (DPIUtil.autoScaleDown (eventRect));
+ sendEvent (SWT.PaintItem, event);
+ } finally {
+ Cairo.cairo_translate (cr, 0, y_offset);
+ }
+
gc.dispose();
}
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolItem.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolItem.java
index 723b591b09..bdf0b5fa2a 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolItem.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolItem.java
@@ -59,6 +59,15 @@ public class ToolItem extends Item {
boolean mapHooked;
boolean enabled = true;
+ /**
+ * The image that is currently used by the tool item.
+ * Either the image set by client code via {@link #setImage(Image)}
+ * or {@link #setDisabledImage(Image)}, depending on button state.
+ * Or if the button is disabled but no disabled image is specified,
+ * a grayed out version of the "normal" image.
+ */
+ Image currentImage;
+
/**
* Constructs a new instance of this class given its parent
* (which must be a <code>ToolBar</code>) and a style value
@@ -657,6 +666,7 @@ long gtk_create_menu_proxy (long widget) {
return 1;
}
+ Image image = currentImage;
if (image != null) {
ImageList imageList = parent.imageList;
if (imageList != null) {
@@ -1261,6 +1271,7 @@ private void disposeDefault() {
void _setImage (Image image) {
if ((style & SWT.SEPARATOR) != 0) return;
+ currentImage = image;
if (image != null) {
ImageList imageList = parent.imageList;
if (imageList == null) imageList = parent.imageList = new ImageList ();
@@ -1293,15 +1304,7 @@ void _setImage (Image image) {
* required to reset the proxy menu. Otherwise, the
* old menuItem appears in the overflow menu.
*/
- if ((style & SWT.DROP_DOWN) != 0) {
- if (GTK.GTK4) {
- /* TODO: GTK4 have to implement our own overflow menu */
- } else {
- proxyMenuItem = 0;
- proxyMenuItem = GTK3.gtk_tool_item_retrieve_proxy_menu_item (handle);
- OS.g_signal_connect(proxyMenuItem, OS.activate, ToolBar.menuItemSelectedFunc.getAddress(), handle);
- }
- }
+ recreateMenuProxy();
parent.relayout ();
}
@@ -1411,15 +1414,7 @@ public void setText (String string) {
* required to reset the proxy menu. Otherwise, the
* old menuItem appears in the overflow menu.
*/
- if ((style & SWT.DROP_DOWN) != 0) {
- if (GTK.GTK4) {
- /* TODO: GTK4 have to implement our own overflow menu */
- } else {
- proxyMenuItem = 0;
- proxyMenuItem = GTK3.gtk_tool_item_retrieve_proxy_menu_item (handle);
- OS.g_signal_connect(proxyMenuItem, OS.activate, ToolBar.menuItemSelectedFunc.getAddress(), handle);
- }
- }
+ recreateMenuProxy();
parent.relayout ();
}
@@ -1474,15 +1469,7 @@ public void setToolTipText(String string) {
* Otherwise, the old menuItem appears in the overflow
* menu as a blank item.
*/
- if ((style & SWT.DROP_DOWN) != 0) {
- if (GTK.GTK4) {
- /* TODO: GTK4 have to implement our own overflow menu */
- } else {
- proxyMenuItem = 0;
- proxyMenuItem = GTK3.gtk_tool_item_retrieve_proxy_menu_item (handle);
- OS.g_signal_connect(proxyMenuItem, OS.activate, ToolBar.menuItemSelectedFunc.getAddress(), handle);
- }
- }
+ recreateMenuProxy();
}
/**
@@ -1570,4 +1557,15 @@ long dpiChanged(long object, long arg0) {
return 0;
}
+
+private void recreateMenuProxy() {
+ if ((style & SWT.DROP_DOWN) != 0 || proxyMenuItem != 0) {
+ if (GTK.GTK4) {
+ /* TODO: GTK4 have to implement our own overflow menu */
+ } else {
+ proxyMenuItem = 0;
+ proxyMenuItem = GTK3.gtk_tool_item_retrieve_proxy_menu_item (handle);
+ }
+ }
+}
} \ No newline at end of file
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
index 77e6bdfd26..cab5bf8567 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
@@ -3168,6 +3168,32 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
}
}
}
+
+ GdkRectangle rendererRect = new GdkRectangle ();
+ GdkRectangle columnRect = new GdkRectangle ();
+ int y_offset;
+ {
+ /*
+ * SWT creates multiple renderers (kind of sub-columns) per column.
+ * For example: one for checkbox, one for image, one for text.
+ * 'background_area' argument in this function is area of currently
+ * painted renderer. However, for SWT.EraseItem and SWT.PaintItem,
+ * SWT wants entire column's area along with the event. There's api
+ * 'gtk_tree_view_get_background_area()' but it calculates item's
+ * rect in control, which will have wrong Y if item is rendered
+ * separately (for example, for drag image).
+ * The workaround is to take X range from api and Y range from argument.
+ */
+ OS.memmove (rendererRect, background_area, GdkRectangle.sizeof);
+
+ long path = GTK.gtk_tree_model_get_path (modelHandle, iter);
+ GTK.gtk_tree_view_get_background_area (handle, path, columnHandle, columnRect);
+ GTK.gtk_tree_path_free (path);
+
+ y_offset = columnRect.y - rendererRect.y;
+ columnRect.y -= y_offset;
+ }
+
if (item != null) {
if (GTK.GTK_IS_CELL_RENDERER_TOGGLE (cell) || ( columnIndex != 0 || (style & SWT.CHECK) == 0)) {
drawFlags = (int)flags;
@@ -3187,10 +3213,7 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
if ((flags & GTK.GTK_CELL_RENDERER_FOCUSED) != 0) drawState |= SWT.FOCUSED;
}
- GdkRectangle rect = new GdkRectangle ();
- long path = GTK.gtk_tree_model_get_path (modelHandle, iter);
- GTK.gtk_tree_view_get_background_area (handle, path, columnHandle, rect);
- GTK.gtk_tree_path_free (path);
+ Rectangle rect = columnRect.toRectangle ();
// Use the x and width information from the Cairo context. See bug 535124.
if (cr != 0) {
GdkRectangle r2 = new GdkRectangle ();
@@ -3243,21 +3266,34 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
if (cr != 0) {
// Use the original rectangle, not the Cairo clipping for the y, width, and height values.
// See bug 535124.
- Rectangle rect2 = DPIUtil.autoScaleDown(new Rectangle(rect.x, rect.y, rect.width, rect.height));
+ Rectangle rect2 = DPIUtil.autoScaleDown(rect);
gc.setClipping(rect2.x, rect2.y, rect2.width, rect2.height);
} else {
- Rectangle rect2 = DPIUtil.autoScaleDown(new Rectangle(rect.x, rect.y, rect.width, rect.height));
+ Rectangle rect2 = DPIUtil.autoScaleDown(rect);
// Caveat: rect2 is necessary because GC#setClipping(Rectangle) got broken by bug 446075
gc.setClipping(rect2.x, rect2.y, rect2.width, rect2.height);
}
+
+ // SWT.PaintItem/SWT.EraseItem often expect that event.y matches
+ // what 'event.item.getBounds()' returns. The workaround is to
+ // adjust coordinate system temporarily.
Event event = new Event ();
- event.item = item;
- event.index = columnIndex;
- event.gc = gc;
- Rectangle eventRect = new Rectangle (rect.x, rect.y, rect.width, rect.height);
- event.setBounds (DPIUtil.autoScaleDown (eventRect));
- event.detail = drawState;
- sendEvent (SWT.EraseItem, event);
+ try {
+ Rectangle eventRect = new Rectangle (rect.x, rect.y, rect.width, rect.height);
+
+ eventRect.y += y_offset;
+ Cairo.cairo_translate (cr, 0, -y_offset);
+
+ event.item = item;
+ event.index = columnIndex;
+ event.gc = gc;
+ event.detail = drawState;
+ event.setBounds (DPIUtil.autoScaleDown (eventRect));
+ sendEvent (SWT.EraseItem, event);
+ } finally {
+ Cairo.cairo_translate (cr, 0, y_offset);
+ }
+
drawForegroundRGBA = null;
drawState = event.doit ? event.detail : 0;
drawFlags &= ~(GTK.GTK_CELL_RENDERER_FOCUSED | GTK.GTK_CELL_RENDERER_SELECTED);
@@ -3275,12 +3311,9 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
}
}
if ((drawState & SWT.BACKGROUND) != 0 && (drawState & SWT.SELECTED) == 0) {
-
GC gc = getGC(cr);
gc.setBackground (item.getBackground (columnIndex));
- GdkRectangle rect = new GdkRectangle ();
- OS.memmove (rect, background_area, GdkRectangle.sizeof);
- gc.fillRectangle(DPIUtil.autoScaleDown(new Rectangle(rect.x, rect.y, rect.width, rect.height)));
+ gc.fillRectangle (DPIUtil.autoScaleDown (rendererRect.toRectangle ()));
gc.dispose ();
}
if ((drawState & SWT.FOREGROUND) != 0 || GTK.GTK_IS_CELL_RENDERER_TOGGLE (cell)) {
@@ -3306,10 +3339,7 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
if (GTK.GTK_IS_CELL_RENDERER_TEXT (cell)) {
if (hooks (SWT.PaintItem)) {
if (wasSelected) drawState |= SWT.SELECTED;
- GdkRectangle rect = new GdkRectangle ();
- long path = GTK.gtk_tree_model_get_path (modelHandle, iter);
- GTK.gtk_tree_view_get_background_area (handle, path, columnHandle, rect);
- GTK.gtk_tree_path_free (path);
+ Rectangle rect = columnRect.toRectangle ();
ignoreSize = true;
int [] contentX = new int [1], contentWidth = new int [1];
gtk_cell_renderer_get_preferred_size (cell, handle, contentWidth, null);
@@ -3339,7 +3369,7 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
/* indent */
GdkRectangle rect3 = new GdkRectangle ();
GTK.gtk_widget_realize (handle);
- path = GTK.gtk_tree_model_get_path (modelHandle, iter);
+ long path = GTK.gtk_tree_model_get_path (modelHandle, iter);
GTK.gtk_tree_view_get_cell_area (handle, path, columnHandle, rect3);
GTK.gtk_tree_path_free (path);
contentX[0] += rect3.x;
@@ -3362,18 +3392,30 @@ void rendererRender (long cell, long cr, long snapshot, long widget, long backgr
rect.x = getClientWidth () - rect.width - rect.x;
}
- Rectangle rect2 = DPIUtil.autoScaleDown(new Rectangle(rect.x, rect.y, rect.width, rect.height));
+ Rectangle rect2 = DPIUtil.autoScaleDown(rect);
// Caveat: rect2 is necessary because GC#setClipping(Rectangle) got broken by bug 446075
gc.setClipping(rect2.x, rect2.y, rect2.width, rect2.height);
+ // SWT.PaintItem/SWT.EraseItem often expect that event.y matches
+ // what 'event.item.getBounds()' returns. The workaround is to
+ // adjust coordinate system temporarily.
Event event = new Event ();
- event.item = item;
- event.index = columnIndex;
- event.gc = gc;
- Rectangle eventRect = new Rectangle (rect.x + contentX [0], rect.y, contentWidth [0], rect.height);
- event.setBounds (DPIUtil.autoScaleDown (eventRect));
- event.detail = drawState;
- sendEvent(SWT.PaintItem, event);
+ try {
+ Rectangle eventRect = new Rectangle (rect.x + contentX [0], rect.y, contentWidth [0], rect.height);
+
+ eventRect.y += y_offset;
+ Cairo.cairo_translate (cr, 0, -y_offset);
+
+ event.item = item;
+ event.index = columnIndex;
+ event.gc = gc;
+ event.detail = drawState;
+ event.setBounds (DPIUtil.autoScaleDown (eventRect));
+ sendEvent (SWT.PaintItem, event);
+ } finally {
+ Cairo.cairo_translate (cr, 0, y_offset);
+ }
+
gc.dispose();
}
}
@@ -3500,7 +3542,7 @@ void setItemCount (long parentIter, int count) {
/**
* Sets the number of root-level items contained in the receiver.
* <p>
- * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(org.eclipse.swt.widgets.Tree,int,int)}
+ * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(Tree,int,int)}
* and {@link TreeItem#setItemCount}
*
* @param count the number of items
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeItem.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeItem.java
index c7545f6658..d4f94ac010 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeItem.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeItem.java
@@ -51,8 +51,8 @@ public class TreeItem extends Item {
* Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
* Item is inserted as last direct child of the tree.
* <p>
- * The fastest way to insert many items is documented in {@link org.eclipse.swt.widgets.TreeItem#TreeItem(Tree,int,int)}
- * and {@link org.eclipse.swt.widgets.TreeItem#setItemCount}
+ * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(Tree,int,int)}
+ * and {@link TreeItem#setItemCount}
*
* @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
@@ -110,8 +110,8 @@ public TreeItem (Tree parent, int style, int index) {
* Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
* Item is inserted as last direct child of the specified <code>TreeItem</code>.
* <p>
- * The fastest way to insert many items is documented in {@link org.eclipse.swt.widgets.TreeItem#TreeItem(Tree,int,int)}
- * and {@link org.eclipse.swt.widgets.TreeItem#setItemCount}
+ * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(Tree,int,int)}
+ * and {@link TreeItem#setItemCount}
*
* @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
@@ -136,8 +136,8 @@ public TreeItem (TreeItem parentItem, int style) {
* Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
* Item is inserted as <code>index</code> direct child of the specified <code>TreeItem</code>.
* <p>
- * The fastest way to insert many items is documented in {@link org.eclipse.swt.widgets.TreeItem#TreeItem(Tree,int,int)}
- * and {@link org.eclipse.swt.widgets.TreeItem#setItemCount}
+ * The fastest way to insert many items is documented in {@link TreeItem#TreeItem(Tree,int,int)}
+ * and {@link TreeItem#setItemCount}
*
* @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
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
index 0c301d5b1e..3aa2083ff4 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
@@ -255,7 +255,9 @@ public abstract class Widget {
/**
* Prevents uninitialized instances from being created outside the package.
*/
-Widget () {}
+Widget () {
+ notifyCreationTracker();
+}
/**
* Constructs a new instance of this class given its parent
@@ -292,6 +294,7 @@ public Widget (Widget parent, int style) {
this.style = style;
display = parent.display;
reskinWidget ();
+ notifyCreationTracker();
}
void _addListener (int eventType, Listener listener) {
@@ -793,6 +796,14 @@ void gtk4_key_release_event(long controller, int keyval, int keycode, int state,
void gtk4_focus_enter_event(long controller, long event) {}
/**
+ * @param handle the handle of the window that caused the event
+ * @param event the type of event, should be FocusIn or FocusOut
+ */
+void gtk4_focus_window_event(long handle, long event) {
+ gtk_focus_in_event (handle, event);
+}
+
+/**
* @param controller the corresponding controller responsible for capturing the event
* @param event the GdkEvent captured
*/
@@ -1345,6 +1356,7 @@ void release (boolean destroy) {
releaseHandle ();
}
}
+ notifyDisposalTracker();
}
}
@@ -1583,7 +1595,8 @@ char [] sendIMKeyEvent (int type, long event, char [] chars) {
int index = 0, count = 0, state = 0;
long ptr = 0;
if (event == 0) {
- ptr = GTK3.gtk_get_current_event ();
+ long controller = Control.getControl(this.handle).keyController;
+ ptr = GTK.GTK4 ? GTK4.gtk_event_controller_get_current_event(controller):GTK3.gtk_get_current_event ();
if (ptr != 0) {
int eventType = GDK.gdk_event_get_event_type(ptr);
eventType = Control.fixGdkEventTypeValues(eventType);
@@ -1603,9 +1616,13 @@ char [] sendIMKeyEvent (int type, long event, char [] chars) {
break;
}
} else {
- int [] buffer = new int [1];
- GTK3.gtk_get_current_event_state (buffer);
- state = buffer [0];
+ if(GTK.GTK4) {
+ state = GTK4.gtk_event_controller_get_current_event_state(controller);
+ } else {
+ int [] buffer = new int [1];
+ GTK3.gtk_get_current_event_state (buffer);
+ state = buffer [0];
+ }
}
} else {
ptr = event;
@@ -1627,13 +1644,13 @@ char [] sendIMKeyEvent (int type, long event, char [] chars) {
* the key by returning null.
*/
if (isDisposed ()) {
- if (ptr != 0 && ptr != event) gdk_event_free (ptr);
+ if (ptr != 0 && ptr != event && !GTK.GTK4) gdk_event_free (ptr);
return null;
}
if (javaEvent.doit) chars [count++] = chars [index];
index++;
}
- if (ptr != 0 && ptr != event) gdk_event_free (ptr);
+ if (ptr != 0 && ptr != event && !GTK.GTK4) gdk_event_free (ptr);
if (count == 0) return null;
if (index != count) {
char [] result = new char [count];
@@ -2295,6 +2312,12 @@ void focusProc(long controller, long user_data) {
}
}
+void windowActiveProc(long handle, long user_data) {
+ long eventType = GTK.gtk_window_is_active(handle) ? SWT.FocusIn:SWT.FocusOut;
+
+ gtk4_focus_window_event(handle, eventType);
+}
+
boolean keyPressReleaseProc(long controller, int keyval, int keycode, int state, long user_data) {
long event = GTK4.gtk_event_controller_get_current_event(controller);
@@ -2520,4 +2543,17 @@ void gtk_widget_size_allocate (long widget, GtkAllocation allocation, int baseli
GTK3.gtk_widget_size_allocate(widget, allocation);
}
}
+
+void notifyCreationTracker() {
+ if (WidgetSpy.isEnabled) {
+ WidgetSpy.getInstance().widgetCreated(this);
+ }
+}
+
+void notifyDisposalTracker() {
+ if (WidgetSpy.isEnabled) {
+ WidgetSpy.getInstance().widgetDisposed(this);
+ }
+}
+
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java
index a89ddf86f9..b79fe461f5 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java
@@ -1220,12 +1220,14 @@ void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight,
data.hNullBitmap = 0;
}
}
- if (srcImage.alpha != -1 || srcImage.alphaData != null) {
- drawBitmapAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
+ boolean isDib = bm.bmBits != 0;
+ int depth = bm.bmPlanes * bm.bmBitsPixel;
+ if (isDib && depth == 32) {
+ drawBitmapAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
} else if (srcImage.transparentPixel != -1) {
drawBitmapTransparent(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
} else {
- drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
+ drawBitmapColor(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
}
if (mustRestore) {
long hOldBitmap = OS.SelectObject(memGC.handle, srcImage.handle);
@@ -1233,35 +1235,15 @@ void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight,
}
}
-void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) {
- /* Simple cases */
- if (srcImage.alpha == 0) return;
- if (srcImage.alpha == 255) {
- drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
- return;
- }
-
+void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
boolean alphaBlendSupport = true;
boolean isPrinter = OS.GetDeviceCaps(handle, OS.TECHNOLOGY) == OS.DT_RASPRINTER;
+ int sourceAlpha = -1;
if (isPrinter) {
int caps = OS.GetDeviceCaps(handle, OS.SHADEBLENDCAPS);
if (caps != 0) {
- if (srcImage.alpha != -1) {
- alphaBlendSupport = (caps & OS.SB_CONST_ALPHA) != 0;
- } else {
- alphaBlendSupport = (caps & OS.SB_PIXEL_ALPHA) != 0;
- }
- }
- }
- if (alphaBlendSupport) {
- BLENDFUNCTION blend = new BLENDFUNCTION();
- blend.BlendOp = OS.AC_SRC_OVER;
- long srcHdc = OS.CreateCompatibleDC(handle);
- long oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
- if (srcImage.alpha != -1) {
- blend.SourceConstantAlpha = (byte)srcImage.alpha;
- OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, blend);
- } else {
+ long srcHdc = OS.CreateCompatibleDC(handle);
+ long oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
long memDib = Image.createDIB(srcWidth, srcHeight, 32);
if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
long memHdc = OS.CreateCompatibleDC(handle);
@@ -1271,34 +1253,41 @@ void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHe
OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY);
byte[] srcData = new byte[dibBM.bmWidthBytes * dibBM.bmHeight];
OS.MoveMemory(srcData, dibBM.bmBits, srcData.length);
- final int apinc = imgWidth - srcWidth;
- int ap = srcY * imgWidth + srcX, sp = 0;
- byte[] alphaData = srcImage.alphaData;
- for (int y = 0; y < srcHeight; ++y) {
- for (int x = 0; x < srcWidth; ++x) {
- int alpha = alphaData[ap++] & 0xff;
- int r = ((srcData[sp + 0] & 0xFF) * alpha) + 128;
- r = (r + (r >> 8)) >> 8;
- int g = ((srcData[sp + 1] & 0xFF) * alpha) + 128;
- g = (g + (g >> 8)) >> 8;
- int b = ((srcData[sp + 2] & 0xFF) * alpha) + 128;
- b = (b + (b >> 8)) >> 8;
- srcData[sp+0] = (byte)r;
- srcData[sp+1] = (byte)g;
- srcData[sp+2] = (byte)b;
- srcData[sp+3] = (byte)alpha;
- sp += 4;
+ int size = srcData.length;
+ sourceAlpha = srcData[3] & 0xFF;
+ for (int sp = 7; sp < size; sp += 4) {
+ int currentAlpha = srcData[sp] & 0xFF;
+ if (sourceAlpha != currentAlpha) {
+ sourceAlpha = -1;
+ break;
}
- ap += apinc;
}
- OS.MoveMemory(dibBM.bmBits, srcData, srcData.length);
- blend.SourceConstantAlpha = (byte)0xff;
- blend.AlphaFormat = OS.AC_SRC_ALPHA;
- OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, blend);
OS.SelectObject(memHdc, oldMemBitmap);
OS.DeleteDC(memHdc);
OS.DeleteObject(memDib);
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.DeleteDC(srcHdc);
+ if (sourceAlpha != -1) {
+ if (sourceAlpha == 0) return;
+ if (sourceAlpha == 255) {
+ drawBitmapColor(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
+ return;
+ }
+ alphaBlendSupport = (caps & OS.SB_CONST_ALPHA) != 0;
+ }
+ else {
+ alphaBlendSupport = (caps & OS.SB_PIXEL_ALPHA) != 0;
+ }
}
+ }
+ if (alphaBlendSupport) {
+ BLENDFUNCTION blend = new BLENDFUNCTION();
+ blend.BlendOp = OS.AC_SRC_OVER;
+ long srcHdc = OS.CreateCompatibleDC(handle);
+ long oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
+ blend.SourceConstantAlpha = (byte)sourceAlpha;
+ blend.AlphaFormat = OS.AC_SRC_ALPHA;
+ OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, srcHdc, 0, 0, srcWidth, srcHeight, blend);
OS.SelectObject(srcHdc, oldSrcBitmap);
OS.DeleteDC(srcHdc);
return;
@@ -1348,26 +1337,6 @@ void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHe
byte[] srcData = new byte[sizeInBytes];
OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
- /* Merge the alpha channel in place */
- int alpha = srcImage.alpha;
- final boolean hasAlphaChannel = (srcImage.alpha == -1);
- if (hasAlphaChannel) {
- final int apinc = imgWidth - srcWidth;
- final int spinc = dibBM.bmWidthBytes - srcWidth * 4;
- int ap = srcY * imgWidth + srcX, sp = 3;
- byte[] alphaData = srcImage.alphaData;
- for (int y = 0; y < srcHeight; ++y) {
- for (int x = 0; x < srcWidth; ++x) {
- srcData[sp] = alphaData[ap++];
- sp += 4;
- }
- ap += apinc;
- sp += spinc;
- }
- }
-
- /* Scale the foreground pixels with alpha */
- OS.MoveMemory(dibBM.bmBits, srcData, sizeInBytes);
/*
* When drawing to a printer, StretchBlt does not correctly stretch if
* the source and destination HDCs are the same. The workaround is to
@@ -1403,10 +1372,10 @@ void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHe
int dp = 0;
for (int y = 0; y < destHeight; ++y) {
for (int x = 0; x < destWidth; ++x) {
- if (hasAlphaChannel) alpha = srcData[dp + 3] & 0xff;
- destData[dp] += ((srcData[dp] & 0xff) - (destData[dp] & 0xff)) * alpha / 255;
- destData[dp + 1] += ((srcData[dp + 1] & 0xff) - (destData[dp + 1] & 0xff)) * alpha / 255;
- destData[dp + 2] += ((srcData[dp + 2] & 0xff) - (destData[dp + 2] & 0xff)) * alpha / 255;
+ int alpha = srcData[dp + 3] & 0xFF;
+ destData[dp ] += (srcData[dp ] & 0xFF) - (destData[dp ] & 0xFF) * alpha / 255;
+ destData[dp + 1] += (srcData[dp + 1] & 0xFF) - (destData[dp + 1] & 0xFF) * alpha / 255;
+ destData[dp + 2] += (srcData[dp + 2] & 0xFF) - (destData[dp + 2] & 0xFF) * alpha / 255;
dp += 4;
}
dp += dpinc;
@@ -1642,7 +1611,7 @@ void drawBitmapTransparent(Image srcImage, int srcX, int srcY, int srcWidth, int
OS.DeleteDC(srcHdc);
}
-void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) {
+void drawBitmapColor(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
long srcHdc = OS.CreateCompatibleDC(handle);
long oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
int dwRop = OS.GetROP2(handle) == OS.R2_XORPEN ? OS.SRCINVERT : OS.SRCCOPY;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
index c0766ccab7..1b38c70d27 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
@@ -112,16 +112,6 @@ public final class Image extends Resource implements Drawable {
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;
@@ -283,11 +273,6 @@ public Image(Device device, Image srcImage, int flag) {
device.internal_dispose_GC(hDC, null);
transparentPixel = srcImage.transparentPixel;
- alpha = srcImage.alpha;
- if (srcImage.alphaData != null) {
- alphaData = new byte[srcImage.alphaData.length];
- System.arraycopy(srcImage.alphaData, 0, alphaData, 0, alphaData.length);
- }
break;
case SWT.ICON:
handle = OS.CopyImage(srcImage.handle, OS.IMAGE_ICON, rect.width, rect.height, 0);
@@ -977,9 +962,12 @@ void initNative(String filename) {
long [] createGdipImage() {
switch (type) {
case SWT.BITMAP: {
- if (alpha != -1 || alphaData != null || transparentPixel != -1) {
- BITMAP bm = new BITMAP();
- OS.GetObject(handle, BITMAP.sizeof, bm);
+ BITMAP bm = new BITMAP();
+ OS.GetObject(handle, BITMAP.sizeof, bm);
+ int depth = bm.bmPlanes * bm.bmBitsPixel;
+ boolean isDib = bm.bmBits != 0;
+ boolean hasAlpha = isDib && depth == 32;
+ if (hasAlpha || transparentPixel != -1) {
int imgWidth = bm.bmWidth;
int imgHeight = bm.bmHeight;
long hDC = device.internal_new_GC(null);
@@ -993,8 +981,14 @@ long [] createGdipImage() {
OS.GetObject(memDib, BITMAP.sizeof, dibBM);
int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
OS.BitBlt(memHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY);
+ long hHeap = OS.GetProcessHeap();
+ long pixels = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, sizeInBytes);
+ if (pixels == 0) SWT.error(SWT.ERROR_NO_HANDLES);
byte red = 0, green = 0, blue = 0;
- if (transparentPixel != -1) {
+ if (hasAlpha) {
+ OS.MoveMemory(pixels, bm.bmBits, sizeInBytes);
+ }
+ else {
if (bm.bmBitsPixel <= 8) {
byte[] color = new byte[4];
OS.GetDIBColorTable(srcHdc, transparentPixel, 1, color);
@@ -1029,30 +1023,8 @@ long [] createGdipImage() {
break;
}
}
- }
- OS.SelectObject(srcHdc, oldSrcBitmap);
- OS.SelectObject(memHdc, oldMemBitmap);
- OS.DeleteObject(srcHdc);
- OS.DeleteObject(memHdc);
- byte[] srcData = new byte[sizeInBytes];
- OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
- OS.DeleteObject(memDib);
- device.internal_dispose_GC(hDC, null);
- if (alpha != -1) {
- for (int y = 0, dp = 0; y < imgHeight; ++y) {
- for (int x = 0; x < imgWidth; ++x) {
- srcData[dp + 3] = (byte)alpha;
- dp += 4;
- }
- }
- } else if (alphaData != null) {
- for (int y = 0, dp = 0, ap = 0; y < imgHeight; ++y) {
- for (int x = 0; x < imgWidth; ++x) {
- srcData[dp + 3] = alphaData[ap++];
- dp += 4;
- }
- }
- } else if (transparentPixel != -1) {
+ byte[] srcData = new byte[sizeInBytes];
+ OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
for (int y = 0, dp = 0; y < imgHeight; ++y) {
for (int x = 0; x < imgWidth; ++x) {
if (srcData[dp] == blue && srcData[dp + 1] == green && srcData[dp + 2] == red) {
@@ -1063,12 +1035,15 @@ long [] createGdipImage() {
dp += 4;
}
}
+ OS.MoveMemory(pixels, srcData, sizeInBytes);
}
- long hHeap = OS.GetProcessHeap();
- long pixels = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, srcData.length);
- if (pixels == 0) SWT.error(SWT.ERROR_NO_HANDLES);
- OS.MoveMemory(pixels, srcData, sizeInBytes);
- return new long []{Gdip.Bitmap_new(imgWidth, imgHeight, dibBM.bmWidthBytes, Gdip.PixelFormat32bppARGB, pixels), pixels};
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.SelectObject(memHdc, oldMemBitmap);
+ OS.DeleteObject(srcHdc);
+ OS.DeleteObject(memHdc);
+ OS.DeleteObject(memDib);
+ int pixelFormat = hasAlpha ? Gdip.PixelFormat32bppPARGB : Gdip.PixelFormat32bppARGB;
+ return new long []{Gdip.Bitmap_new(imgWidth, imgHeight, dibBM.bmWidthBytes, pixelFormat, pixels), pixels};
}
return new long []{Gdip.Bitmap_new(handle, 0), 0};
}
@@ -1633,10 +1608,32 @@ public ImageData getImageDataAtCurrentZoom() {
/* Construct and return the ImageData */
ImageData imageData = new ImageData(width, height, depth, palette, 4, data);
imageData.transparentPixel = this.transparentPixel;
- imageData.alpha = alpha;
- if (alpha == -1 && alphaData != null) {
- imageData.alphaData = new byte[alphaData.length];
- System.arraycopy(alphaData, 0, imageData.alphaData, 0, alphaData.length);
+ if (isDib && depth == 32) {
+ byte straightData[] = new byte[imageSize];
+ byte alphaData[] = new byte[width * height];
+ boolean validAlpha = true;
+ for (int ap = 0, dp = 0; validAlpha && ap < alphaData.length; ap++, dp += 4) {
+ int b = data[dp ] & 0xFF;
+ int g = data[dp + 1] & 0xFF;
+ int r = data[dp + 2] & 0xFF;
+ int a = data[dp + 3] & 0xFF;
+ alphaData[ap] = (byte) a;
+ validAlpha = validAlpha && b <= a && g <= a && r <= a;
+ if (a != 0) {
+ straightData[dp ] = (byte) (((b * 0xFF) + a / 2) / a);
+ straightData[dp + 1] = (byte) (((g * 0xFF) + a / 2) / a);
+ straightData[dp + 2] = (byte) (((r * 0xFF) + a / 2) / a);
+ }
+ }
+ if (validAlpha) {
+ imageData.data = straightData;
+ imageData.alphaData = alphaData;
+ }
+ else {
+ for (int dp = 3; dp < imageSize; dp += 4) {
+ data[dp] = (byte) 0xFF;
+ }
+ }
}
return imageData;
}
@@ -1684,6 +1681,7 @@ void init(int width, int height) {
int planes = OS.GetDeviceCaps(hDC, OS.PLANES);
int depth = bits * planes;
if (depth < 16) depth = 16;
+ if (depth > 24) depth = 24;
handle = createDIB(width, height, depth);
}
if (handle != 0) {
@@ -1729,6 +1727,9 @@ static long [] init(Device device, Image image, ImageData i) {
img.alphaData = i.alphaData;
i = img;
}
+
+ boolean hasAlpha = i.alpha != -1 || i.alphaData != null;
+
/*
* Windows supports 16-bit mask of (0x7C00, 0x3E0, 0x1F),
* 24-bit mask of (0xFF0000, 0xFF00, 0xFF) and 32-bit mask
@@ -1745,51 +1746,56 @@ static long [] init(Device device, Image image, ImageData i) {
int newOrder = ImageData.MSB_FIRST;
PaletteData newPalette = null;
- switch (i.depth) {
- case 8:
- /*
- * Bug 566545. Usually each color mask selects a different part of the pixel
- * value to encode the according color. In this common case it is rather trivial
- * to convert an 8-bit direct color image to the Windows supported 16-bit image.
- * However there is no enforcement for the color masks to be disjunct. For
- * example an 8-bit image where all color masks select the same 8-bit of pixel
- * value (mask = 0xFF and shift = 0 for all colors) results in a very efficient
- * 8-bit gray-scale image without the need of defining a color table.
- *
- * That's why we need to calculate the actual required depth if all colors are
- * stored non-overlapping which might require 24-bit instead of the usual
- * expected 16-bit.
- */
- int minDepth = ImageData.getChannelWidth(redMask, palette.redShift)
- + ImageData.getChannelWidth(greenMask, palette.greenShift)
- + ImageData.getChannelWidth(blueMask, palette.blueShift);
- if (minDepth <= 16) {
- newDepth = 16;
+ if (hasAlpha) {
+ newDepth = 32;
+ newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ }
+ else {
+ switch (i.depth) {
+ case 8:
+ /*
+ * Bug 566545. Usually each color mask selects a different part of the pixel
+ * value to encode the according color. In this common case it is rather trivial
+ * to convert an 8-bit direct color image to the Windows supported 16-bit image.
+ * However there is no enforcement for the color masks to be disjunct. For
+ * example an 8-bit image where all color masks select the same 8-bit of pixel
+ * value (mask = 0xFF and shift = 0 for all colors) results in a very efficient
+ * 8-bit gray-scale image without the need of defining a color table.
+ *
+ * That's why we need to calculate the actual required depth if all colors are
+ * stored non-overlapping which might require 24-bit instead of the usual
+ * expected 16-bit.
+ */
+ int minDepth = ImageData.getChannelWidth(redMask, palette.redShift)
+ + ImageData.getChannelWidth(greenMask, palette.greenShift)
+ + ImageData.getChannelWidth(blueMask, palette.blueShift);
+ if (minDepth <= 16) {
+ newDepth = 16;
+ newOrder = ImageData.LSB_FIRST;
+ newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
+ } else {
+ newDepth = 24;
+ newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
+ }
+ break;
+ case 16:
newOrder = ImageData.LSB_FIRST;
- newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
- } else {
+ 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:
newDepth = 24;
newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
- }
- 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);
+ break;
+ default:
+ SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
}
if (newPalette != null) {
ImageData img = new ImageData(i.width, i.height, newDepth, newPalette);
@@ -1808,6 +1814,73 @@ static long [] init(Device device, Image image, ImageData i) {
i = img;
}
}
+ else if (hasAlpha) {
+ int newDepth = 32;
+ PaletteData newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ int newOrder = ImageData.MSB_FIRST;
+ RGB[] rgbs = i.palette.getRGBs();
+ int length = rgbs.length;
+ byte[] srcReds = new byte[length];
+ byte[] srcGreens = new byte[length];
+ byte[] srcBlues = new byte[length];
+ for (int j = 0; j < rgbs.length; j++) {
+ RGB rgb = rgbs[j];
+ if (rgb == null) continue;
+ srcReds[j] = (byte)rgb.red;
+ srcGreens[j] = (byte)rgb.green;
+ srcBlues[j] = (byte)rgb.blue;
+ }
+ 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, srcReds, srcGreens, srcBlues,
+ 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(i.palette.getRGB(i.transparentPixel));
+ }
+ img.maskPad = i.maskPad;
+ img.maskData = i.maskData;
+ img.alpha = i.alpha;
+ img.alphaData = i.alphaData;
+ i = img;
+ }
+ if (i.alpha != -1) {
+ int alpha = i.alpha & 0xFF;
+ byte[] data = i.data;
+ for (int dp = 0; dp < i.data.length; dp += 4) {
+ /* pre-multiplied alpha */
+ int r = ((data[dp ] & 0xFF) * alpha) + 128;
+ r = (r + (r >> 8)) >> 8;
+ int g = ((data[dp + 1] & 0xFF) * alpha) + 128;
+ g = (g + (g >> 8)) >> 8;
+ int b = ((data[dp + 2] & 0xFF) * alpha) + 128;
+ b = (b + (b >> 8)) >> 8;
+ data[dp ] = (byte) b;
+ data[dp + 1] = (byte) g;
+ data[dp + 2] = (byte) r;
+ data[dp + 3] = (byte) alpha;
+ }
+ }
+ else if (i.alphaData != null) {
+ byte[] data = i.data;
+ for (int ap = 0, dp = 0; dp < i.data.length; ap++, dp += 4) {
+ /* pre-multiplied alpha */
+ int a = i.alphaData[ap] & 0xFF;
+ int r = ((data[dp ] & 0xFF) * a) + 128;
+ r = (r + (r >> 8)) >> 8;
+ int g = ((data[dp + 1] & 0xFF) * a) + 128;
+ g = (g + (g >> 8)) >> 8;
+ int b = ((data[dp + 2] & 0xFF) * a) + 128;
+ b = (b + (b >> 8)) >> 8;
+ data[dp ] = (byte) r;
+ data[dp + 1] = (byte) g;
+ data[dp + 2] = (byte) b;
+ data[dp + 3] = (byte) a;
+ }
+ }
+
/* Construct bitmap info header by hand */
RGB[] rgbs = i.palette.getRGBs();
BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
@@ -1894,14 +1967,6 @@ static long [] init(Device device, Image image, ImageData i) {
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;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java
index 4f8ae61709..1c71538df3 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java
@@ -2871,10 +2871,12 @@ StyleItem[] merge (long items, int itemCount) {
}
}
+ boolean mayNeedSplit = true;
int styleLimit = translateOffset(styles[styleIndex + 1].start);
if (styleLimit <= itemLimit) {
int runLen = styleLimit - start;
if (runLen < MAX_RUN_LENGTH) {
+ mayNeedSplit = false;
styleIndex++;
start = styleLimit;
if (start < itemLimit && 0 < start && start < end) {
@@ -2888,7 +2890,7 @@ StyleItem[] merge (long items, int itemCount) {
}
}
int runLen = itemLimit - start;
- if (runLen > MAX_RUN_LENGTH) {
+ if (mayNeedSplit && runLen > MAX_RUN_LENGTH) {
start += splitLongRun(item);
} else if (itemLimit <= styleLimit) {
itemIndex = nextItemIndex;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/ImageList.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/ImageList.java
index ff2a39ff6c..34ccb923d2 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/ImageList.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/ImageList.java
@@ -151,10 +151,16 @@ long copyWithAlpha (long hBitmap, int background, byte[] alphaData, int destWidt
/* Merge the alpha channel in place */
if (alphaData != null) {
int spinc = dibBM.bmWidthBytes - srcWidth * 4;
- int ap = 0, sp = 3;
+ int ap = 0, sp = 0;
for (int y = 0; y < srcHeight; ++y) {
for (int x = 0; x < srcWidth; ++x) {
- srcData [sp] = alphaData [ap++];
+ int a = alphaData [ap++] & 0xFF;
+ if (a != 0) {
+ srcData [sp ] = (byte)((((srcData [sp ] & 0xFF) * 0xFF) + a / 2) / a);
+ srcData [sp + 1] = (byte)((((srcData [sp + 1] & 0xFF) * 0xFF) + a / 2) / a);
+ srcData [sp + 2] = (byte)((((srcData [sp + 2] & 0xFF) * 0xFF) + a / 2) / a);
+ }
+ srcData [sp + 3] = (byte)a;
sp += 4;
}
sp += spinc;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java
index 82516a201f..592eaedc40 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java
@@ -1433,6 +1433,71 @@ LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
return super.wmNotifyChild (hdr, wParam, lParam);
}
+static int getThemeStateId(int style, boolean pressed, boolean enabled) {
+ int direction = style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
+
+ /*
+ * 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 (direction == SWT.LEFT) {
+ direction = SWT.RIGHT;
+ } else if (direction == SWT.RIGHT) {
+ direction = SWT.LEFT;
+ }
+ }
+
+ /*
+ * On Win11, scrollbars no longer show arrows by default.
+ * Arrows only show up when hot/disabled/pushed.
+ * The workaround is to use hot image in place of default.
+ */
+ boolean hot = false;
+ if (OS.WIN32_BUILD >= OS.WIN32_BUILD_WIN11_21H2) {
+ if (!pressed && enabled) {
+ hot = true;
+ }
+ }
+
+ if (hot) {
+ switch (direction) {
+ case SWT.UP: return OS.ABS_UPHOT;
+ case SWT.DOWN: return OS.ABS_DOWNHOT;
+ case SWT.LEFT: return OS.ABS_LEFTHOT;
+ case SWT.RIGHT: return OS.ABS_RIGHTHOT;
+ }
+ }
+
+ if (pressed) {
+ switch (direction) {
+ case SWT.UP: return OS.ABS_UPPRESSED;
+ case SWT.DOWN: return OS.ABS_DOWNPRESSED;
+ case SWT.LEFT: return OS.ABS_LEFTPRESSED;
+ case SWT.RIGHT: return OS.ABS_RIGHTPRESSED;
+ }
+ }
+
+ if (!enabled) {
+ switch (direction) {
+ case SWT.UP: return OS.ABS_UPDISABLED;
+ case SWT.DOWN: return OS.ABS_DOWNDISABLED;
+ case SWT.LEFT: return OS.ABS_LEFTDISABLED;
+ case SWT.RIGHT: return OS.ABS_RIGHTDISABLED;
+ }
+ }
+
+ switch (direction) {
+ case SWT.UP: return OS.ABS_UPNORMAL;
+ case SWT.DOWN: return OS.ABS_DOWNNORMAL;
+ case SWT.LEFT: return OS.ABS_LEFTNORMAL;
+ case SWT.RIGHT: return OS.ABS_RIGHTNORMAL;
+ }
+
+ // Have some sane value if all else fails
+ return OS.ABS_LEFTNORMAL;
+}
+
@Override
LRESULT wmDrawChild (long wParam, long lParam) {
if ((style & SWT.ARROW) == 0) return super.wmDrawChild (wParam, lParam);
@@ -1441,29 +1506,9 @@ LRESULT wmDrawChild (long wParam, long lParam) {
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;
+ boolean pressed = ((struct.itemState & OS.ODS_SELECTED) != 0);
+ boolean enabled = getEnabled ();
+ int iStateId = getThemeStateId(style, pressed, enabled);
OS.DrawThemeBackground (display.hScrollBarTheme (), struct.hDC, OS.SBP_ARROWBTN, iStateId, rect, null);
} else {
int uState = OS.DFCS_SCROLLLEFT;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java
index bc0f470331..5b5342b940 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java
@@ -38,6 +38,9 @@ import org.eclipse.swt.internal.win32.*;
* @noextend This class is not intended to be subclassed by clients.
*/
public class Caret extends Widget {
+ /** The Caret last updated on the OS-level */
+ private static Caret currentCaret;
+
Canvas parent;
int x, y, width, height;
boolean moved, resized;
@@ -285,6 +288,7 @@ void killFocus () {
void move () {
moved = false;
+ setCurrentCaret(this);
if (!OS.SetCaretPos (x, y)) return;
resizeIME ();
}
@@ -332,6 +336,9 @@ void releaseParent () {
@Override
void releaseWidget () {
super.releaseWidget ();
+ if (isCurrentCaret()) {
+ setCurrentCaret(null);
+ }
parent = null;
image = null;
font = null;
@@ -390,7 +397,7 @@ public void setBounds (int x, int y, int width, int 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;
+ if (samePosition && sameExtent && isCurrentCaret()) return;
this.x = x;
this.y = y;
this.width = width;
@@ -530,12 +537,20 @@ public void setLocation (int x, int y) {
}
void setLocationInPixels (int x, int y) {
- if (this.x == x && this.y == y) return;
+ if (this.x == x && this.y == y && isCurrentCaret()) return;
this.x = x; this.y = y;
moved = true;
if (isVisible && hasFocus ()) move ();
}
+private boolean isCurrentCaret() {
+ return Caret.currentCaret == this;
+}
+
+private void setCurrentCaret(Caret caret) {
+ Caret.currentCaret = caret;
+}
+
/**
* Sets the receiver's location to the point specified by
* the argument which is relative to the receiver's
@@ -572,7 +587,7 @@ public void setSize (int width, int height) {
}
void setSizeInPixels (int width, int height) {
- if (this.width == width && this.height == height) return;
+ if (this.width == width && this.height == height && isCurrentCaret()) return;
this.width = width; this.height = height;
resized = true;
if (isVisible && hasFocus ()) resize ();
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java
index 151be728f1..2e71ec17df 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java
@@ -991,39 +991,6 @@ static long create32bitDIB (Image image) {
dp += 4;
}
}
- } else if (alpha != -1) {
- for (int y = 0, dp = 0; y < imgHeight; ++y) {
- for (int x = 0; x < imgWidth; ++x) {
- int r = ((srcData[dp + 0] & 0xFF) * alpha) + 128;
- r = (r + (r >> 8)) >> 8;
- int g = ((srcData[dp + 1] & 0xFF) * alpha) + 128;
- g = (g + (g >> 8)) >> 8;
- int b = ((srcData[dp + 2] & 0xFF) * alpha) + 128;
- b = (b + (b >> 8)) >> 8;
- srcData[dp+0] = (byte)r;
- srcData[dp+1] = (byte)g;
- srcData[dp+2] = (byte)b;
- srcData[dp+3] = (byte)alpha;
- dp += 4;
- }
- }
- } else if (alphaData != null) {
- for (int y = 0, dp = 0, ap = 0; y < imgHeight; ++y) {
- for (int x = 0; x < imgWidth; ++x) {
- int a = alphaData[ap++] & 0xFF;
- int r = ((srcData[dp + 0] & 0xFF) * a) + 128;
- r = (r + (r >> 8)) >> 8;
- int g = ((srcData[dp + 1] & 0xFF) * a) + 128;
- g = (g + (g >> 8)) >> 8;
- int b = ((srcData[dp + 2] & 0xFF) * a) + 128;
- b = (b + (b >> 8)) >> 8;
- srcData[dp+0] = (byte)r;
- srcData[dp+1] = (byte)g;
- srcData[dp+2] = (byte)b;
- srcData[dp+3] = (byte)a;
- dp += 4;
- }
- }
} else if (transparentPixel != -1) {
for (int y = 0, dp = 0; y < imgHeight; ++y) {
for (int x = 0; x < imgWidth; ++x) {
@@ -1035,7 +1002,7 @@ static long create32bitDIB (Image image) {
dp += 4;
}
}
- } else {
+ } else if (alpha == -1 && alphaData == null) {
for (int y = 0, dp = 0; y < imgHeight; ++y) {
for (int x = 0; x < imgWidth; ++x) {
srcData [dp + 3] = (byte)0xFF;
@@ -1117,6 +1084,11 @@ static long create32bitDIB (long hBitmap, int alpha, byte [] alphaData, int tran
if (alpha != -1) {
for (int y = 0, dp = 0; y < imgHeight; ++y) {
for (int x = 0; x < imgWidth; ++x) {
+ if (alpha != 0) {
+ srcData [dp ] = (byte)((((srcData[dp ] & 0xFF) * 0xFF) + alpha / 2) / alpha);
+ srcData [dp + 1] = (byte)((((srcData[dp + 1] & 0xFF) * 0xFF) + alpha / 2) / alpha);
+ srcData [dp + 2] = (byte)((((srcData[dp + 2] & 0xFF) * 0xFF) + alpha / 2) / alpha);
+ }
srcData [dp + 3] = (byte)alpha;
dp += 4;
}
@@ -1124,7 +1096,13 @@ static long create32bitDIB (long hBitmap, int alpha, byte [] alphaData, int tran
} else if (alphaData != null) {
for (int y = 0, dp = 0, ap = 0; y < imgHeight; ++y) {
for (int x = 0; x < imgWidth; ++x) {
- srcData [dp + 3] = alphaData [ap++];
+ int a = alphaData [ap++] & 0xFF;
+ if (a != 0) {
+ srcData [dp ] = (byte)((((srcData[dp ] & 0xFF) * 0xFF) + a / 2) / a);
+ srcData [dp + 1] = (byte)((((srcData[dp + 1] & 0xFF) * 0xFF) + a / 2) / a);
+ srcData [dp + 2] = (byte)((((srcData[dp + 2] & 0xFF) * 0xFF) + a / 2) / a);
+ }
+ srcData [dp + 3] = (byte)a;
dp += 4;
}
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableColumn.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableColumn.java
index 823a620c74..097ab46efa 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableColumn.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/TableColumn.java
@@ -324,6 +324,75 @@ int getWidthInPixels () {
}
/**
+ * WINAPI doesn't provide any means to request column's optimal size.
+ * There is only an API to resize to optimal size. The workaround is to
+ * 1) disable redraw
+ * 2) resize to optimal
+ * 3) query new column size
+ * 4) set old column size
+ * 5) enable redraw
+ * This preserves old column size. As a consequence, no painting is
+ * needed after enabling redraw.
+ */
+private int calcAutoWidth(int index, boolean withHeader) {
+ long hwnd = parent.handle;
+
+ // WM_SETREDRAW has a side effect of forcing Control to be visible.
+ // On the other hand, if control is invisible, 'WM_SETREDRAW' is not needed.
+ int style = OS.GetWindowLong (hwnd, OS.GWL_STYLE);
+ boolean isTableVisible = ((style & OS.WS_VISIBLE) != 0);
+ boolean isTableDrawing = parent.getDrawing ();
+ boolean needsDisableRedraw = isTableVisible && isTableDrawing;
+
+ try {
+ if (needsDisableRedraw) {
+ // WM_SETREDRAW is used directly, because 'Control.setRedraw()'
+ // also repaints, which is to be avoided in this function.
+ OS.SendMessage (hwnd, OS.WM_SETREDRAW, 0, 0);
+ }
+
+ int oldWidth = (int)OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
+
+ /*
+ * Feature in Windows. When LVSCW_AUTOSIZE_USEHEADER is used
+ * with LVM_SETCOLUMNWIDTH to resize the last column, the last
+ * column is expanded to fill the client area. The fix is to
+ * resize the table to be small, set the column width and then
+ * restore the table to its original size.
+ *
+ * Note: temporarily setting LVS_EX_COLUMNSNAPPOINTS may be a
+ * less intrusive workaround.
+ */
+ RECT rect = null;
+ boolean fixWidth = index == parent.getColumnCount () - 1;
+ if (fixWidth) {
+ rect = new RECT ();
+ OS.GetWindowRect (hwnd, rect);
+ OS.UpdateWindow (hwnd);
+ int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER;
+ OS.SetWindowPos (hwnd, 0, 0, 0, 0, rect.bottom - rect.top, flags);
+ }
+
+ int resizeType = withHeader ? OS.LVSCW_AUTOSIZE_USEHEADER : OS.LVSCW_AUTOSIZE;
+ OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, resizeType);
+
+ if (fixWidth) {
+ int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOZORDER;
+ OS.SetWindowPos (hwnd, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, flags);
+ }
+
+ int newWidth = (int)OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
+ OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, oldWidth);
+
+ return newWidth;
+ } finally {
+ if (needsDisableRedraw) {
+ OS.SendMessage (hwnd, OS.WM_SETREDRAW, 1, 0);
+ }
+ }
+}
+
+/**
* 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.
@@ -381,10 +450,8 @@ public void pack () {
}
if (newFont != 0) OS.SelectObject (hDC, oldFont);
OS.ReleaseDC (hwnd, hDC);
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, columnWidth);
} else {
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, OS.LVSCW_AUTOSIZE);
- columnWidth = (int)OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
+ columnWidth = calcAutoWidth (index, false);
if (index == 0) {
/*
* Bug in Windows. When LVM_SETCOLUMNWIDTH is used with LVSCW_AUTOSIZE
@@ -412,38 +479,19 @@ public void pack () {
}
if (headerWidth > columnWidth) {
if (!hasHeaderImage) {
- /*
- * Feature in Windows. When LVSCW_AUTOSIZE_USEHEADER is used
- * with LVM_SETCOLUMNWIDTH to resize the last column, the last
- * column is expanded to fill the client area. The fix is to
- * resize the table to be small, set the column width and then
- * restore the table to its original size.
- */
- RECT rect = null;
- boolean fixWidth = index == parent.getColumnCount () - 1;
- if (fixWidth) {
- rect = new RECT ();
- OS.GetWindowRect (hwnd, rect);
- OS.UpdateWindow (hwnd);
- int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER;
- OS.SetWindowPos (hwnd, 0, 0, 0, 0, rect.bottom - rect.top, flags);
- }
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, OS.LVSCW_AUTOSIZE_USEHEADER);
- if (fixWidth) {
- int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOZORDER;
- OS.SetWindowPos (hwnd, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, flags);
- }
+ // The code has been there for years and it's no longer clear why
+ // not just use 'headerWidth' here. Maybe because SWT's size
+ // calculation is imperfect and WINAPI will do it better?
+ columnWidth = calcAutoWidth (index, true);
} else {
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, headerWidth);
- }
- } else {
- if (index == 0) {
- OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, columnWidth);
+ columnWidth = headerWidth;
}
}
+
+ OS.SendMessage (hwnd, OS.LVM_SETCOLUMNWIDTH, index, columnWidth);
+
parent.ignoreColumnResize = false;
- int newWidth = (int)OS.SendMessage (hwnd, OS.LVM_GETCOLUMNWIDTH, index, 0);
- if (oldWidth != newWidth) {
+ if (oldWidth != columnWidth) {
updateToolTip (index);
sendEvent (SWT.Resize);
if (isDisposed ()) return;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java
index 3cb9a97aaf..488cf58683 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java
@@ -125,6 +125,7 @@ public abstract class Widget {
* Prevents uninitialized instances from being created outside the package.
*/
Widget () {
+ notifyCreationTracker();
}
/**
@@ -162,6 +163,7 @@ public Widget (Widget parent, int style) {
this.style = style;
display = parent.display;
reskinWidget ();
+ notifyCreationTracker();
}
void _addListener (int eventType, Listener listener) {
@@ -829,6 +831,7 @@ void release (boolean destroy) {
releaseHandle ();
}
}
+ notifyDisposalTracker();
}
}
@@ -2487,4 +2490,17 @@ LRESULT wmXButtonUp (long hwnd, long wParam, long lParam) {
}
return result;
}
+
+void notifyCreationTracker() {
+ if (WidgetSpy.isEnabled) {
+ WidgetSpy.getInstance().widgetCreated(this);
+ }
+}
+
+void notifyDisposalTracker() {
+ if (WidgetSpy.isEnabled) {
+ WidgetSpy.getInstance().widgetDisposed(this);
+ }
+}
+
}

Back to the top