diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSProgressIndicator.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSProgressIndicator.java
index 3397ada72d7..d430ad015e9 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSProgressIndicator.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSProgressIndicator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2026 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -7,9 +7,6 @@
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.internal.cocoa;
@@ -63,6 +60,10 @@ public void setUsesThreadedAnimation(boolean usesThreadedAnimation) {
OS.objc_msgSend(this.id, OS.sel_setUsesThreadedAnimation_, usesThreadedAnimation);
}
+public void sizeToFit() {
+ OS.objc_msgSend(this.id, OS.sel_sizeToFit);
+}
+
public void startAnimation(id sender) {
OS.objc_msgSend(this.id, OS.sel_startAnimation_, sender != null ? sender.id : 0);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSWorkspace.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSWorkspace.java
index 9bfa02eae83..16d5910854f 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSWorkspace.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSWorkspace.java
@@ -7,9 +7,6 @@
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.internal.cocoa;
@@ -27,6 +24,16 @@ public NSWorkspace(id id) {
super(id);
}
+public NSURL URLForApplicationToOpenURL(NSURL url) {
+ long result = OS.objc_msgSend(this.id, OS.sel_URLForApplicationToOpenURL_, url != null ? url.id : 0);
+ return result != 0 ? new NSURL(result) : null;
+}
+
+public NSURL URLForApplicationToOpenContentType(UTType contentType) {
+ long result = OS.objc_msgSend(this.id, OS.sel_URLForApplicationToOpenContentType_, contentType != null ? contentType.id : 0);
+ return result != 0 ? new NSURL(result) : null;
+}
+
public NSString fullPathForApplication(NSString appName) {
long result = OS.objc_msgSend(this.id, OS.sel_fullPathForApplication_, appName != null ? appName.id : 0);
return result != 0 ? new NSString(result) : null;
@@ -45,16 +52,6 @@ public boolean openURL(NSURL url) {
return OS.objc_msgSend_bool(this.id, OS.sel_openURL_, url != null ? url.id : 0);
}
-public NSURL urlForApplicationToOpenURL(NSURL url) {
- long result = OS.objc_msgSend(this.id, OS.sel_URLForApplicationToOpenURL_, url != null ? url.id : 0);
- return result != 0 ? new NSURL(result) : null;
-}
-
-public NSURL urlForApplicationToOpenContentType(long contentType) {
- long result = OS.objc_msgSend(this.id, OS.sel_URLForApplicationToOpenContentType_, contentType);
- return result != 0 ? new NSURL(result) : null;
-}
-
public boolean openURLs(NSArray urls, NSString bundleIdentifier, long options, NSAppleEventDescriptor descriptor, long identifiers) {
return OS.objc_msgSend_bool(this.id, OS.sel_openURLs_withAppBundleIdentifier_options_additionalEventParamDescriptor_launchIdentifiers_, urls != null ? urls.id : 0, bundleIdentifier != null ? bundleIdentifier.id : 0, options, descriptor != null ? descriptor.id : 0, identifiers);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java
index 40c830f8464..ea852de5a13 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java
@@ -767,6 +767,7 @@ public static boolean isSystemDarkAppearance() {
public static final long class_NSWorkspace = objc_getClass("NSWorkspace");
public static final long class_SFCertificatePanel = objc_getClass("SFCertificatePanel");
public static final long class_SFCertificateTrustPanel = objc_getClass("SFCertificateTrustPanel");
+public static final long class_UTType = objc_getClass("UTType");
public static final long class_WebDataSource = objc_getClass("WebDataSource");
public static final long class_WebFrame = objc_getClass("WebFrame");
public static final long class_WebFrameView = objc_getClass("WebFrameView");
@@ -830,9 +831,9 @@ public static Selector getSelector (long value) {
public static final long sel_PMPrintSettings = Selector.sel_PMPrintSettings.value;
public static final long sel_TIFFRepresentation = Selector.sel_TIFFRepresentation.value;
public static final long sel_URL = Selector.sel_URL.value;
-public static final long sel_URLFromPasteboard_ = Selector.sel_URLFromPasteboard_.value;
-public static final long sel_URLForApplicationToOpenURL_ = Selector.sel_URLForApplicationToOpenURL_.value;
public static final long sel_URLForApplicationToOpenContentType_ = Selector.sel_URLForApplicationToOpenContentType_.value;
+public static final long sel_URLForApplicationToOpenURL_ = Selector.sel_URLForApplicationToOpenURL_.value;
+public static final long sel_URLFromPasteboard_ = Selector.sel_URLFromPasteboard_.value;
public static final long sel_URLWithString_ = Selector.sel_URLWithString_.value;
public static final long sel_UTF8String = Selector.sel_UTF8String.value;
public static final long sel_abortEditing = Selector.sel_abortEditing.value;
@@ -2143,6 +2144,9 @@ public static Selector getSelector (long value) {
/** Constants */
public static final int NSAlertFirstButtonReturn = 1000;
public static final int NSAlertSecondButtonReturn = 1001;
+public static final int NSAlertStyleCritical = 2;
+public static final int NSAlertStyleInformational = 1;
+public static final int NSAlertStyleWarning = 0;
public static final int NSAlertThirdButtonReturn = 1002;
public static final int NSAlphaFirstBitmapFormat = 1;
public static final int NSAlphaNonpremultipliedBitmapFormat = 2;
@@ -2164,7 +2168,6 @@ public static Selector getSelector (long value) {
public static final int NSBezelStylePushDisclosure = 14;
public static final int NSBezelStyleSmallSquare = 6;
public static final int NSBoldFontMask = 2;
-
public static final int NSBottomTabsBezelBorder = 2;
public static final int NSBoxCustom = 4;
public static final int NSBoxSeparator = 2;
@@ -2174,21 +2177,19 @@ public static Selector getSelector (long value) {
public static final int NSButtonTypeRadio = 4;
public static final int NSButtonTypeSwitch = 3;
public static final int NSCarriageReturnCharacter = 13;
-public static final int NSDatePickerStyleClockAndCalendar = 1;
-
public static final int NSClosePathBezierPathElement = 3;
-public static final int NSCommandKeyMask = 1048576;
+public static final int NSColorSpaceModelRGB = 1;
public static final int NSCompositingOperationClear = 0;
public static final int NSCompositingOperationCopy = 1;
public static final int NSCompositingOperationSourceAtop = 5;
public static final int NSCompositingOperationSourceOver = 2;
public static final int NSContentsCellMask = 1;
-public static final int NSControlKeyMask = 262144;
-public static final int NSCriticalAlertStyle = 2;
public static final int NSCurveToBezierPathElement = 2;
+public static final int NSDatePickerStyleClockAndCalendar = 1;
+public static final int NSDatePickerStyleTextField = 2;
+public static final int NSDatePickerStyleTextFieldAndStepper = 0;
public static final int NSDeleteCharacter = 127;
public static final long NSDeviceIndependentModifierFlagsMask = 4294901760L;
-
public static final int NSDragOperationCopy = 1;
public static final int NSDragOperationDelete = 32;
public static final long NSDragOperationEvery = -1L;
@@ -2197,6 +2198,10 @@ public static Selector getSelector (long value) {
public static final int NSDragOperationNone = 0;
public static final int NSEnterCharacter = 3;
public static final int NSEvenOddWindingRule = 1;
+public static final int NSEventModifierFlagCommand = 1048576;
+public static final int NSEventModifierFlagControl = 262144;
+public static final int NSEventModifierFlagHelp = 4194304;
+public static final int NSEventModifierFlagShift = 131072;
public static final int NSEventPhaseBegan = 1;
public static final int NSEventPhaseCancelled = 16;
public static final int NSEventPhaseEnded = 8;
@@ -2212,9 +2217,7 @@ public static Selector getSelector (long value) {
public static final int NSFocusRingTypeNone = 1;
public static final int NSFontPanelModeMaskAllEffects = 1048320;
public static final int NSFontPanelModeMaskAllModes = -1;
-
public static final int NSHelpFunctionKey = 63302;
-public static final int NSHelpKeyMask = 4194304;
public static final int NSHourMinuteDatePickerElementFlag = 12;
public static final int NSHourMinuteSecondDatePickerElementFlag = 14;
public static final int NSImageAbove = 5;
@@ -2229,7 +2232,7 @@ public static Selector getSelector (long value) {
public static final int NSImageLeft = 2;
public static final int NSImageOnly = 1;
public static final int NSImageOverlaps = 6;
-public static final int NSInformationalAlertStyle = 1;
+public static final int NSImageScaleNone = 2;
public static final int NSItalicFontMask = 1;
public static final int NSKeyDown = 10;
public static final int NSKeyUp = 11;
@@ -2246,10 +2249,13 @@ public static Selector getSelector (long value) {
public static final int NSLineBreakByWordWrapping = 0;
public static final int NSLineToBezierPathElement = 1;
public static final int NSControlSizeMini = 2;
-
+public static final int NSControlSizeRegular = 0;
+public static final int NSControlSizeSmall = 1;
+public static final int NSControlStateValueMixed = -1;
+public static final int NSControlStateValueOff = 0;
+public static final int NSControlStateValueOn = 1;
public static final int NSMiterLineJoinStyle = 0;
public static final int NSModalResponseCancel = 0;
-public static final int NSControlStateValueMixed = -1;
public static final int NSMouseEntered = 8;
public static final int NSMouseExited = 9;
public static final int NSMouseMoved = 5;
@@ -2259,9 +2265,6 @@ public static Selector getSelector (long value) {
public static final int NSNoImage = 0;
public static final int NSNoTitle = 0;
public static final int NSNonZeroWindingRule = 0;
-
-public static final int NSControlStateValueOff = 0;
-public static final int NSControlStateValueOn = 1;
public static final int NSOpenGLCPSurfaceOrder = 235;
public static final int NSOpenGLPFAAccumSize = 14;
public static final int NSOpenGLPFAAlphaSize = 11;
@@ -2280,9 +2283,6 @@ public static Selector getSelector (long value) {
public static final int NSPortraitOrientation = 0;
public static final int NSPrintPanelShowsPageSetupAccessory = 256;
public static final int NSPrintPanelShowsPrintSelection = 32;
-public static final int NSProgressIndicatorPreferredThickness = 14;
-public static final int NSColorSpaceModelRGB = 1;
-public static final int NSControlSizeRegular = 0;
public static final int NSRegularSquareBezelStyle = 2;
public static final int NSResizableWindowMask = 8;
public static final int NSRightMouseDown = 3;
@@ -2290,19 +2290,14 @@ public static Selector getSelector (long value) {
public static final int NSRightMouseUp = 4;
public static final int NSRoundLineCapStyle = 1;
public static final int NSRoundLineJoinStyle = 1;
-public static final int NSImageScaleNone = 2;
public static final int NSScrollElasticityNone = 1;
public static final int NSScrollWheel = 22;
-public static final int NSScrollerDecrementLine = 4;
public static final int NSScrollerDecrementPage = 1;
-public static final int NSScrollerIncrementLine = 5;
public static final int NSScrollerIncrementPage = 3;
public static final int NSScrollerKnob = 2;
public static final int NSScrollerKnobSlot = 6;
public static final int NSScrollerStyleLegacy = 0;
public static final int NSScrollerStyleOverlay = 1;
-public static final int NSShiftKeyMask = 131072;
-public static final int NSControlSizeSmall = 1;
public static final int NSSquareLineCapStyle = 2;
public static final int NSStatusWindowLevel = 25;
public static final int NSStringDrawingUsesLineFragmentOrigin = 1;
@@ -2322,9 +2317,6 @@ public static Selector getSelector (long value) {
public static final int NSTextAlignmentJustified = 3;
public static final int NSTextAlignmentLeft = 0;
public static final int NSTextAlignmentRight = IS_X86_64 ? 1 : 2;
-public static final int NSDatePickerStyleTextFieldAndStepper = 0;
-public static final int NSDatePickerStyleTextField = 2;
-
public static final int NSToolbarDisplayModeIconOnly = 2;
public static final long NSTouchPhaseAny = -1L;
public static final int NSTouchPhaseBegan = 1;
@@ -2336,14 +2328,12 @@ public static Selector getSelector (long value) {
public static final int NSUnderlineStyleNone = 0;
public static final int NSUnderlineStyleSingle = 1;
public static final int NSUnderlineStyleThick = 2;
-
public static final int NSViewHeightSizable = 16;
public static final int NSViewMaxXMargin = 4;
public static final int NSViewMaxYMargin = 32;
public static final int NSViewMinXMargin = 1;
public static final int NSViewMinYMargin = 8;
public static final int NSViewWidthSizable = 2;
-public static final int NSWarningAlertStyle = 0;
public static final int NSWindowAbove = 1;
public static final int NSWindowBelow = -1;
public static final int NSWindowCollectionBehaviorFullScreenAuxiliary = 256;
@@ -3183,12 +3173,6 @@ public static Selector getSelector (long value) {
* @param image cast=(CGImageRef)
*/
public static final native void CGImageRelease(long image);
-/**
- * @param url cast=(CFURLRef)
- * @param mediaBox cast=(const CGRect *)
- * @param auxiliaryInfo cast=(CFDictionaryRef)
- */
-public static final native long CGPDFContextCreateWithURL(long url, CGRect mediaBox, long auxiliaryInfo);
/**
* @param context cast=(CGContextRef)
* @param pageInfo cast=(CFDictionaryRef)
@@ -3197,11 +3181,17 @@ public static Selector getSelector (long value) {
/**
* @param context cast=(CGContextRef)
*/
-public static final native void CGPDFContextEndPage(long context);
+public static final native void CGPDFContextClose(long context);
+/**
+ * @param url cast=(CFURLRef)
+ * @param mediaBox cast=(CGRect*)
+ * @param auxiliaryInfo cast=(CFDictionaryRef)
+ */
+public static final native long CGPDFContextCreateWithURL(long url, CGRect mediaBox, long auxiliaryInfo);
/**
* @param context cast=(CGContextRef)
*/
-public static final native void CGPDFContextClose(long context);
+public static final native void CGPDFContextEndPage(long context);
/**
* @param path cast=(CGMutablePathRef)
* @param m cast=(CGAffineTransform*)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/Selector.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/Selector.java
index 589d736607e..09e0ae8c00c 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/Selector.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/Selector.java
@@ -96,9 +96,9 @@ public enum Selector {
, sel_PMPrintSettings("PMPrintSettings")
, sel_TIFFRepresentation("TIFFRepresentation")
, sel_URL("URL")
- , sel_URLFromPasteboard_("URLFromPasteboard:")
- , sel_URLForApplicationToOpenURL_("URLForApplicationToOpenURL:")
, sel_URLForApplicationToOpenContentType_("URLForApplicationToOpenContentType:")
+ , sel_URLForApplicationToOpenURL_("URLForApplicationToOpenURL:")
+ , sel_URLFromPasteboard_("URLFromPasteboard:")
, sel_URLWithString_("URLWithString:")
, sel_UTF8String("UTF8String")
, sel_abortEditing("abortEditing")
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/UTType.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/UTType.java
new file mode 100644
index 00000000000..b836c18703f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/UTType.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2026 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.swt.internal.cocoa;
+
+public class UTType extends NSObject {
+
+public UTType() {
+ super();
+}
+
+public UTType(long id) {
+ super(id);
+}
+
+public UTType(id id) {
+ super(id);
+}
+
+public static UTType typeWithFilenameExtension(NSString filenameExtension) {
+ long result = OS.objc_msgSend(OS.class_UTType, OS.sel_typeWithFilenameExtension_, filenameExtension != null ? filenameExtension.id : 0);
+ return result != 0 ? new UTType(result) : null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/common/org/eclipse/swt/internal/Library.java b/bundles/org.eclipse.swt/Eclipse SWT PI/common/org/eclipse/swt/internal/Library.java
index 62927e205b4..0b1069113f5 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/common/org/eclipse/swt/internal/Library.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/common/org/eclipse/swt/internal/Library.java
@@ -35,7 +35,7 @@ public class Library {
/**
* SWT revision number (must be >= 0)
*/
- static int REVISION = 7;
+ static int REVISION = 10;
/**
* The JAVA and SWT versions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c
index d290dcf83fb..4f41025f6c9 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c
@@ -359,6 +359,18 @@ JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1formats_1builder_1new)
}
#endif
+#ifndef NO_gdk_1content_1formats_1contain_1gtype
+JNIEXPORT jboolean JNICALL GTK4_NATIVE(gdk_1content_1formats_1contain_1gtype)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1)
+{
+ jboolean rc = 0;
+ GTK4_NATIVE_ENTER(env, that, gdk_1content_1formats_1contain_1gtype_FUNC);
+ rc = (jboolean)gdk_content_formats_contain_gtype((GdkContentFormats *)arg0, (GType)arg1);
+ GTK4_NATIVE_EXIT(env, that, gdk_1content_1formats_1contain_1gtype_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO_gdk_1content_1formats_1get_1gtypes
JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1formats_1get_1gtypes)
(JNIEnv *env, jclass that, jlong arg0, jlongArray arg1)
@@ -403,6 +415,16 @@ JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1content_1formats_1to_1string)
}
#endif
+#ifndef NO_gdk_1content_1formats_1unref
+JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1formats_1unref)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ GTK4_NATIVE_ENTER(env, that, gdk_1content_1formats_1unref_FUNC);
+ gdk_content_formats_unref((GdkContentFormats *)arg0);
+ GTK4_NATIVE_EXIT(env, that, gdk_1content_1formats_1unref_FUNC);
+}
+#endif
+
#ifndef NO_gdk_1content_1provider_1get_1value
JNIEXPORT jboolean JNICALL GTK4_NATIVE(gdk_1content_1provider_1get_1value)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlongArray arg2)
@@ -613,6 +635,66 @@ JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1content_1serializer_1set_1task_1data)
}
#endif
+#ifndef NO_gdk_1drop_1finish
+JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1drop_1finish)
+ (JNIEnv *env, jclass that, jlong arg0, jint arg1)
+{
+ GTK4_NATIVE_ENTER(env, that, gdk_1drop_1finish_FUNC);
+ gdk_drop_finish((GdkDrop *)arg0, (GdkDragAction)arg1);
+ GTK4_NATIVE_EXIT(env, that, gdk_1drop_1finish_FUNC);
+}
+#endif
+
+#ifndef NO_gdk_1drop_1get_1actions
+JNIEXPORT jint JNICALL GTK4_NATIVE(gdk_1drop_1get_1actions)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ jint rc = 0;
+ GTK4_NATIVE_ENTER(env, that, gdk_1drop_1get_1actions_FUNC);
+ rc = (jint)gdk_drop_get_actions((GdkDrop *)arg0);
+ GTK4_NATIVE_EXIT(env, that, gdk_1drop_1get_1actions_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO_gdk_1drop_1get_1formats
+JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1drop_1get_1formats)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ jlong rc = 0;
+ GTK4_NATIVE_ENTER(env, that, gdk_1drop_1get_1formats_FUNC);
+ rc = (jlong)gdk_drop_get_formats((GdkDrop *)arg0);
+ GTK4_NATIVE_EXIT(env, that, gdk_1drop_1get_1formats_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO_gdk_1drop_1read_1value_1async
+JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1drop_1read_1value_1async)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jint arg2, jlong arg3, jlong arg4, jlong arg5)
+{
+ GTK4_NATIVE_ENTER(env, that, gdk_1drop_1read_1value_1async_FUNC);
+ gdk_drop_read_value_async((GdkDrop *)arg0, (GType)arg1, arg2, (GCancellable *)arg3, (GAsyncReadyCallback)arg4, (gpointer)arg5);
+ GTK4_NATIVE_EXIT(env, that, gdk_1drop_1read_1value_1async_FUNC);
+}
+#endif
+
+#ifndef NO_gdk_1drop_1read_1value_1finish
+JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1drop_1read_1value_1finish)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlongArray arg2)
+{
+ jlong *lparg2=NULL;
+ jlong rc = 0;
+ GTK4_NATIVE_ENTER(env, that, gdk_1drop_1read_1value_1finish_FUNC);
+ if (arg2) if ((lparg2 = (*env)->GetLongArrayElements(env, arg2, NULL)) == NULL) goto fail;
+ rc = (jlong)gdk_drop_read_value_finish((GdkDrop *)arg0, (GAsyncResult *)arg1, (GError **)lparg2);
+fail:
+ if (arg2 && lparg2) (*env)->ReleaseLongArrayElements(env, arg2, lparg2, 0);
+ GTK4_NATIVE_EXIT(env, that, gdk_1drop_1read_1value_1finish_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO_gdk_1paintable_1snapshot
JNIEXPORT void JNICALL GTK4_NATIVE(gdk_1paintable_1snapshot)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1, jint arg2, jint arg3)
@@ -2577,6 +2659,16 @@ JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1tree_1view_1column_1cell_1get_1size)
}
#endif
+#ifndef NO_gtk_1tree_1view_1enable_1model_1drag_1dest
+JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1tree_1view_1enable_1model_1drag_1dest)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jint arg2)
+{
+ GTK4_NATIVE_ENTER(env, that, gtk_1tree_1view_1enable_1model_1drag_1dest_FUNC);
+ gtk_tree_view_enable_model_drag_dest((GtkTreeView *)arg0, (GdkContentFormats *)arg1, (GdkDragAction)arg2);
+ GTK4_NATIVE_EXIT(env, that, gtk_1tree_1view_1enable_1model_1drag_1dest_FUNC);
+}
+#endif
+
#ifndef NO_gtk_1widget_1action_1set_1enabled
JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1widget_1action_1set_1enabled)
(JNIEnv *env, jclass that, jlong arg0, jbyteArray arg1, jboolean arg2)
@@ -2841,6 +2933,16 @@ JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1widget_1pick)
}
#endif
+#ifndef NO_gtk_1widget_1remove_1controller
+JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1widget_1remove_1controller)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1)
+{
+ GTK4_NATIVE_ENTER(env, that, gtk_1widget_1remove_1controller_FUNC);
+ gtk_widget_remove_controller((GtkWidget *)arg0, (GtkEventController *)arg1);
+ GTK4_NATIVE_EXIT(env, that, gtk_1widget_1remove_1controller_FUNC);
+}
+#endif
+
#ifndef NO_gtk_1widget_1set_1cursor
JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1widget_1set_1cursor)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h
index 15d43724ca5..f240d03cae9 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h
@@ -47,9 +47,11 @@ typedef enum {
gdk_1content_1formats_1builder_1add_1mime_1type_FUNC,
gdk_1content_1formats_1builder_1free_1to_1formats_FUNC,
gdk_1content_1formats_1builder_1new_FUNC,
+ gdk_1content_1formats_1contain_1gtype_FUNC,
gdk_1content_1formats_1get_1gtypes_FUNC,
gdk_1content_1formats_1get_1mime_1types_FUNC,
gdk_1content_1formats_1to_1string_FUNC,
+ gdk_1content_1formats_1unref_FUNC,
gdk_1content_1provider_1get_1value_FUNC,
gdk_1content_1provider_1new_1for_1value_FUNC,
gdk_1content_1provider_1new_1typed_FUNC,
@@ -67,6 +69,11 @@ typedef enum {
gdk_1content_1serializer_1return_1error_FUNC,
gdk_1content_1serializer_1return_1success_FUNC,
gdk_1content_1serializer_1set_1task_1data_FUNC,
+ gdk_1drop_1finish_FUNC,
+ gdk_1drop_1get_1actions_FUNC,
+ gdk_1drop_1get_1formats_FUNC,
+ gdk_1drop_1read_1value_1async_FUNC,
+ gdk_1drop_1read_1value_1finish_FUNC,
gdk_1paintable_1snapshot_FUNC,
gdk_1toplevel_1focus_FUNC,
gdk_1toplevel_1get_1state_FUNC,
@@ -211,6 +218,7 @@ typedef enum {
gtk_1text_1set_1tabs_FUNC,
gtk_1text_1set_1visibility_FUNC,
gtk_1tree_1view_1column_1cell_1get_1size_FUNC,
+ gtk_1tree_1view_1enable_1model_1drag_1dest_FUNC,
gtk_1widget_1action_1set_1enabled_FUNC,
gtk_1widget_1activate_1action_FUNC,
gtk_1widget_1add_1controller_FUNC,
@@ -231,6 +239,7 @@ typedef enum {
gtk_1widget_1measure_FUNC,
gtk_1widget_1paintable_1new_FUNC,
gtk_1widget_1pick_FUNC,
+ gtk_1widget_1remove_1controller_FUNC,
gtk_1widget_1set_1cursor_FUNC,
gtk_1widget_1set_1focusable_FUNC,
gtk_1widget_1set_1overflow_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
index 59edf503279..a070c4d1329 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
@@ -383,14 +383,17 @@ public static String getEnvironmentalVariable (String envVarName) {
public static final byte[] delete_text = ascii("delete-text");
public static final byte[] direction_changed = ascii("direction-changed");
public static final byte[] dpi_changed = ascii("notify::scale-factor");
+ public static final byte[] accept = ascii("accept");
public static final byte[] drag_begin = ascii("drag-begin");
public static final byte[] drag_data_delete = ascii("drag-data-delete");
public static final byte[] drag_data_get = ascii("drag-data-get");
public static final byte[] drag_data_received = ascii("drag-data-received");
public static final byte[] drag_drop = ascii("drag-drop");
public static final byte[] drag_end = ascii("drag-end");
+ public static final byte[] drag_enter = ascii("drag-enter");
public static final byte[] drag_leave = ascii("drag-leave");
public static final byte[] drag_motion = ascii("drag-motion");
+ public static final byte[] drop = ascii("drop");
public static final byte[] prepare = ascii("prepare");
public static final byte[] draw = ascii("draw");
public static final byte[] end = ascii("end");
@@ -408,6 +411,7 @@ public static String getEnvironmentalVariable (String envVarName) {
public static final byte[] hide = ascii("hide");
public static final byte[] icon_release = ascii("icon-release");
public static final byte[] insert_text = ascii("insert-text");
+ public static final byte[] items_changed = ascii("items-changed");
public static final byte[] key_press_event = ascii("key-press-event");
public static final byte[] key_release_event = ascii("key-release-event");
public static final byte[] key_pressed = ascii("key-pressed");
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java
index df933e27183..3c33dfcfb79 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java
@@ -228,6 +228,38 @@ public class GTK4 {
public static final native void gdk_content_formats_builder_add_mime_type(long builder, byte[] mime_type);
/** @param builder cast=(GdkContentFormatsBuilder *) */
public static final native long gdk_content_formats_builder_free_to_formats(long builder);
+ /**
+ * @param formats cast=(GdkContentFormats *)
+ * @param type cast=(GType)
+ */
+ public static final native boolean gdk_content_formats_contain_gtype(long formats, long type);
+ /** @param formats cast=(GdkContentFormats *) */
+ public static final native void gdk_content_formats_unref(long formats);
+
+ /* GdkDrop */
+ /**
+ * @param drop cast=(GdkDrop *)
+ * @param action cast=(GdkDragAction)
+ */
+ public static final native void gdk_drop_finish(long drop, int action);
+ /** @param drop cast=(GdkDrop *) */
+ public static final native int gdk_drop_get_actions(long drop);
+ /** @param drop cast=(GdkDrop *) */
+ public static final native long gdk_drop_get_formats(long drop);
+ /**
+ * @param drop cast=(GdkDrop *)
+ * @param type cast=(GType)
+ * @param cancellable cast=(GCancellable *)
+ * @param callback cast=(GAsyncReadyCallback)
+ * @param user_data cast=(gpointer)
+ */
+ public static final native void gdk_drop_read_value_async(long drop, long type, int io_priority, long cancellable, long callback, long user_data);
+ /**
+ * @param drop cast=(GdkDrop *)
+ * @param result cast=(GAsyncResult *)
+ * @param error cast=(GError **)
+ */
+ public static final native long gdk_drop_read_value_finish(long drop, long result, long[] error);
/* GtkFileChooser */
/**
@@ -705,6 +737,11 @@ public class GTK4 {
* @param controller cast=(GtkEventController *)
*/
public static final native void gtk_widget_add_controller(long widget, long controller);
+ /**
+ * @param widget cast=(GtkWidget *)
+ * @param controller cast=(GtkEventController *)
+ */
+ public static final native void gtk_widget_remove_controller(long widget, long controller);
/** @param widget cast=(GtkWidget *) */
public static final native long gtk_widget_get_first_child(long widget);
/** @param widget cast=(GtkWidget *) */
@@ -863,6 +900,14 @@ public class GTK4 {
/** @param menu_button cast=(GtkMenuButton *) */
public static final native void gtk_menu_button_set_use_underline(long menu_button, boolean use_underline);
+ /* GtkTreeView */
+ /**
+ * @param tree_view cast=(GtkTreeView *)
+ * @param formats cast=(GdkContentFormats *)
+ * @param actions cast=(GdkDragAction)
+ */
+ public static final native void gtk_tree_view_enable_model_drag_dest(long tree_view, long formats, int actions);
+
/* GtkTreeViewColumn */
/**
* @param tree_column cast=(GtkTreeViewColumn *)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Program/cocoa/org/eclipse/swt/program/Program.java b/bundles/org.eclipse.swt/Eclipse SWT Program/cocoa/org/eclipse/swt/program/Program.java
index 465abcc1180..786067fecee 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT Program/cocoa/org/eclipse/swt/program/Program.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT Program/cocoa/org/eclipse/swt/program/Program.java
@@ -153,20 +153,17 @@ private static NSURL findAppURLForExtension(NSString ext) {
// On macOS 12.0+, use the content type-based API which works reliably
// for all file types including third-party ones.
if (OS.VERSION >= OS.VERSION(12, 0, 0)) {
- long UTTypeClass = OS.objc_getClass("UTType");
- if (UTTypeClass != 0) {
- long utType = OS.objc_msgSend(UTTypeClass, OS.sel_typeWithFilenameExtension_, ext.id);
- if (utType != 0) {
- NSURL appURL = workspace.urlForApplicationToOpenContentType(utType);
- if (appURL != null) {
- return appURL;
- }
+ UTType utType = UTType.typeWithFilenameExtension(ext);
+ if (utType != null) {
+ NSURL appURL = workspace.URLForApplicationToOpenContentType(utType);
+ if (appURL != null) {
+ return appURL;
}
}
}
// Fallback: URL-based lookup (available since macOS 10.6, deprecated in macOS 12.0)
NSURL fileURL = NSURL.fileURLWithPath(NSString.stringWith("/tmp/dummy." + ext.getString()));
- return workspace.urlForApplicationToOpenURL(fileURL);
+ return workspace.URLForApplicationToOpenURL(fileURL);
}
static Program getProgram(NSBundle bundle) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/GCWin32Tests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/GCWin32Tests.java
index 6b4cb998c86..47b20458042 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/GCWin32Tests.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/GCWin32Tests.java
@@ -14,16 +14,19 @@
package org.eclipse.swt.graphics;
import static org.junit.Assert.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
+import java.util.*;
import java.util.concurrent.*;
+import java.util.stream.*;
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.widgets.*;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.*;
+import org.junit.jupiter.params.*;
+import org.junit.jupiter.params.provider.*;
@ExtendWith(PlatformSpecificExecutionExtension.class)
@ExtendWith(WithMonitorSpecificScalingExtension.class)
@@ -142,4 +145,69 @@ private static int renderTextAndCountNonWhitePixels(Image target, Font font, Str
}
return count;
}
+
+ /**
+ * Regression test for the size calculation in scaling/cropping GC.drawImage()
+ * operations with asymmetric source dimensions (smaller height than width) at
+ * fractional zoom levels.
+ *
+ * At fractional zoom levels the effective X and Y scale factors diverge because
+ * each axis is rounded independently (e.g. at 125%:
+ * scaleFactorX = 625/500 = 1.25 but
+ * scaleFactorY = 24/19 ≈ 1.263).
+ */
+ @ParameterizedTest
+ @MethodSource("zoomAndHeightArguments")
+ public void drawImage_asymmetricDimensionsAtFractionalZoom(int zoom, int height) {
+ Display display = Display.getDefault();
+
+ int logicalWidth = 500;
+ int logicalHeight = height;
+
+ PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+ ImageData srcData = new ImageData(logicalWidth, logicalHeight, 32, palette);
+ for (int y = 0; y < logicalHeight; y++) {
+ for (int x = 0; x < logicalWidth; x++) {
+ // left half red, right half blue – makes wrong-rectangle errors visible
+ srcData.setPixel(x, y, x < logicalWidth / 2 ? 0xFF0000 : 0x0000FF);
+ }
+ }
+ Image srcImage = new Image(display, srcData);
+
+ int previousZoom = DPIUtil.getDeviceZoom();
+ try {
+ DPIUtil.setDeviceZoom(zoom);
+
+ Image referenceImage = new Image(display, logicalWidth + 5, logicalHeight + 5);
+ GC referenceGC = new GC(referenceImage);
+ referenceGC.drawImage(srcImage, 0, 0);
+ referenceGC.dispose();
+
+ Image testImageScaled = new Image(display, logicalWidth + 5, logicalHeight + 5);
+ GC testGC = new GC(testImageScaled);
+ testGC.drawImage(srcImage, 0, 0, logicalWidth, logicalHeight);
+ testGC.dispose();
+ assertArrayEquals(referenceImage.getImageData(zoom).data, testImageScaled.getImageData(zoom).data);
+ testImageScaled.dispose();
+
+ Image testImageScaledCropped = new Image(display, logicalWidth + 5, logicalHeight + 5);
+ testGC = new GC(testImageScaledCropped);
+ testGC.drawImage(srcImage, 0, 0, logicalWidth, logicalHeight, 0, 0, logicalWidth, logicalHeight);
+ testGC.dispose();
+ assertArrayEquals(referenceImage.getImageData(zoom).data, testImageScaledCropped.getImageData(zoom).data);
+ testImageScaledCropped.dispose();
+
+ referenceImage.dispose();
+ } finally {
+ DPIUtil.setDeviceZoom(previousZoom);
+ srcImage.dispose();
+ }
+ }
+
+ private static Stream zoomAndHeightArguments() {
+ int[] zooms = { 25, 50, 75, 100, 125, 150, 175, 200 };
+ int[] heights = IntStream.rangeClosed(4, 20).toArray();
+ return Arrays.stream(zooms).boxed()
+ .flatMap(zoom -> Arrays.stream(heights).mapToObj(height -> Arguments.of(zoom, height)));
+ }
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/ImagesWin32Tests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/ImagesWin32Tests.java
index 6b60c2a20df..33f7e3fac26 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/ImagesWin32Tests.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/ImagesWin32Tests.java
@@ -13,7 +13,8 @@
*******************************************************************************/
package org.eclipse.swt.graphics;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
@@ -30,9 +31,219 @@ public void testImageIconTypeShouldNotChangeAfterCallingGetHandleForDifferentZoo
Image icon = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
try {
Image.win32_getHandle(icon, 200);
- assertEquals("Image type should stay to SWT.ICON", SWT.ICON, icon.type);
+ assertEquals(SWT.ICON, icon.type, "Image type should stay to SWT.ICON");
} finally {
icon.dispose();
}
}
+
+ /**
+ * Tests that a GC.drawImage() handle is reused across consecutive calls at
+ * different pixel sizes when the image only provides 100% zoom data. Because
+ * every zoom request falls back to the same 100% data, the effective (nearest
+ * available) zoom is always 100%, and a freshly allocated handle should not be
+ * required for each different draw size.
+ *
+ * See https://github.com/eclipse-platform/eclipse.platform.swt/issues/3419
+ */
+ @Test
+ public void testDrawingHandleIsReusedForSingleZoomImageAtDifferentSizes() {
+ PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+ ImageData imageData = new ImageData(10, 10, 24, palette);
+ // Provider only has 100% data; returns null for every other zoom
+ Image image = new Image(Display.getDefault(), (ImageDataProvider) zoom -> zoom == 100 ? imageData : null);
+ long[] firstHandle = {0};
+ long[] secondHandle = {0};
+ try {
+ // 20x20 pixels → 200% zoom equivalent for a 10x10 base image
+ image.executeOnImageHandleAtBestFittingSize(h -> firstHandle[0] = h.handle(), 20, 20);
+ // 30x30 pixels → 300% zoom equivalent; provider still falls back to 100%,
+ // so the nearest available zoom is still 100% and the handle must be reused
+ image.executeOnImageHandleAtBestFittingSize(h -> secondHandle[0] = h.handle(), 30, 30);
+ assertNotEquals(0L, firstHandle[0], "First handle should be non-zero");
+ assertEquals(firstHandle[0], secondHandle[0],
+ "Consecutive GC.drawImage() calls at different sizes should reuse the same "
+ + "handle when the nearest available zoom is the same (100% in this case)");
+ } finally {
+ image.dispose();
+ }
+ }
+
+ /**
+ * Tests that a GC.drawImage() handle is reused across consecutive calls at
+ * different pixel sizes when the image provides data at 100% and 200% zoom.
+ * Sizes that both map to the 200% nearest available zoom (e.g. 200% and 250%)
+ * should share the same underlying handle without re-allocating it.
+ *
+ * See https://github.com/eclipse-platform/eclipse.platform.swt/issues/3419
+ */
+ @Test
+ public void testDrawingHandleIsReusedForTwoZoomImageAtSizesWithSameNearestZoom() {
+ PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+ ImageData imageData100 = new ImageData(10, 10, 24, palette);
+ ImageData imageData200 = new ImageData(20, 20, 24, palette);
+ // Provider has explicit data at 100% and 200%; returns null for anything else
+ Image image = new Image(Display.getDefault(), (ImageDataProvider) zoom -> zoom == 100 ? imageData100 : zoom == 200 ? imageData200 : null);
+ long[] firstHandle = {0};
+ long[] secondHandle = {0};
+ try {
+ // 20x20 pixels → exactly 200% zoom for the 10x10 base image; uses 200% data
+ image.executeOnImageHandleAtBestFittingSize(h -> firstHandle[0] = h.handle(), 20, 20);
+ // 25x25 pixels → 250% zoom equivalent; nearest available is 200%, so the
+ // previously cached 200% handle should be reused
+ image.executeOnImageHandleAtBestFittingSize(h -> secondHandle[0] = h.handle(), 25, 25);
+ assertNotEquals(0L, firstHandle[0], "First handle should be non-zero");
+ assertEquals(firstHandle[0], secondHandle[0],
+ "Consecutive GC.drawImage() calls at different sizes should reuse the same "
+ + "handle when the nearest available zoom is the same (200% in this case)");
+ } finally {
+ image.dispose();
+ }
+ }
+
+ /**
+ * Tests that GC.drawImage() handles differ when consecutive calls at different
+ * pixel sizes land in different nearest-available-zoom regions for an image
+ * that provides distinct data at 100% and 200%. A size mapping to 100% and a
+ * size mapping to 200% must not share the same native handle, as they would
+ * represent different pixel content.
+ *
+ * See https://github.com/eclipse-platform/eclipse.platform.swt/issues/3419
+ */
+ @Test
+ public void testHandlesAreDifferentForTwoZoomImageAtDifferentNearestZooms() {
+ PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+ ImageData imageData100 = new ImageData(10, 10, 24, palette);
+ ImageData imageData200 = new ImageData(20, 20, 24, palette);
+ // Provider has explicit data at 100% and 200%; returns null for anything else
+ Image image = new Image(Display.getDefault(), (ImageDataProvider) zoom -> zoom == 100 ? imageData100 : zoom == 200 ? imageData200 : null);
+ long[] handle100Zone = {0};
+ long[] handle200Zone = {0};
+ try {
+ // 10x10 pixels → 100% zoom for the 10x10 base image; nearest available is 100%
+ image.executeOnImageHandleAtBestFittingSize(h -> handle100Zone[0] = h.handle(), 10, 10);
+ // 20x20 pixels → 200% zoom; nearest available is 200% → must differ from the
+ // 100% handle since the underlying pixel data is different
+ image.executeOnImageHandleAtBestFittingSize(h -> handle200Zone[0] = h.handle(), 20, 20);
+ assertNotEquals(0L, handle100Zone[0], "First handle should be non-zero");
+ assertNotEquals(handle100Zone[0], handle200Zone[0],
+ "GC.drawImage() calls where the nearest available zoom differs must not "
+ + "reuse the same handle (100% data vs 200% data)");
+ } finally {
+ image.dispose();
+ }
+ }
+
+ /**
+ * Tests that a GC.drawImage() handle at the exact imageZoom is returned in
+ * preference to a handle at nearestAvailableZoom when both are present in the
+ * image's handle manager.
+ *
+ * Explicitly creating a persistent handle at 200% via
+ * {@link Image#win32_getHandle(Image, int)} places it in the handle manager.
+ * When GC.drawImage() then targets a pixel size that maps to imageZoom=200
+ * (while nearestAvailableZoom stays 100% because the provider only has 100%
+ * data), the 200% handle must be found first via the imageZoom lookup and
+ * returned instead of the 100% one.
+ *
+ * See https://github.com/eclipse-platform/eclipse.platform.swt/issues/3419
+ */
+ @Test
+ public void testDrawImagePrefersExistingHandleAtExactImageZoom() {
+ PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+ ImageData imageData = new ImageData(10, 10, 24, palette);
+ Image image = new Image(Display.getDefault(), (ImageDataProvider) zoom -> zoom == 100 ? imageData : null);
+ try {
+ long handle100 = Image.win32_getHandle(image, 100);
+ long handle200 = Image.win32_getHandle(image, 200);
+ assertNotEquals(0L, handle100, "100% handle should be non-zero");
+ assertNotEquals(0L, handle200, "200% handle should be non-zero");
+ assertNotEquals(handle100, handle200, "Handles for different zooms should be distinct native objects");
+ long[] drawHandle = {0};
+ // 20x20 pixels → imageZoom=200 for a 10x10 base; nearestAvailableZoom=100
+ // The 200% handle already in the handle manager must be found and preferred
+ image.executeOnImageHandleAtBestFittingSize(h -> drawHandle[0] = h.handle(), 20, 20);
+ assertEquals(handle200, drawHandle[0],
+ "GC.drawImage() should prefer the existing handle at imageZoom=200 "
+ + "over the nearestAvailableZoom=100 handle");
+ } finally {
+ image.dispose();
+ }
+ }
+
+ /**
+ * Tests that when the pixel size requested by GC.drawImage() maps to a zoom
+ * equal to a current monitor's zoom, a persistent handle is created for that
+ * zoom level and is subsequently reusable via
+ * {@link Image#win32_getHandle(Image, int)}.
+ *
+ * A shell is created so that {@code Display.getShells()} is non-empty and
+ * the monitor zoom is visible to the handle-selection logic. Drawing at a
+ * pixel size whose imageZoom equals the shell's zoom triggers the
+ * monitor-zoom persistence path: the handle is stored in the image's handle
+ * manager and can be retrieved without allocating a second native object.
+ * On 100%-DPI machines the new {@code imageZoom == monitorZoom} branch
+ * overlaps with the existing {@code nearestAvailableZoom == 100} fallback;
+ * on HiDPI machines the new branch is exercised in isolation.
+ *
+ * See https://github.com/eclipse-platform/eclipse.platform.swt/issues/3419
+ */
+ @Test
+ public void testDrawImageCreatesAndReusesPersistentHandleForMonitorZoomImageZoom() {
+ PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+ ImageData imageData = new ImageData(10, 10, 24, palette);
+ Image image = new Image(Display.getDefault(), (ImageDataProvider) zoom -> zoom == 100 ? imageData : null);
+ Shell shell = new Shell(Display.getDefault());
+ try {
+ int shellZoom = shell.getZoom();
+ int pixelSize = 10 * shellZoom / 100;
+ long[] drawHandle = {0};
+ // Drawing at shellZoom's pixel size → imageZoom == shellZoom == monitorZoom
+ // A persistent handle must be created and stored in the handle manager
+ image.executeOnImageHandleAtBestFittingSize(h -> drawHandle[0] = h.handle(), pixelSize, pixelSize);
+ // If persisted, win32_getHandle returns the same native handle without a new allocation
+ long persistedHandle = Image.win32_getHandle(image, shellZoom);
+ assertNotEquals(0L, drawHandle[0], "Draw handle should be non-zero");
+ assertEquals(persistedHandle, drawHandle[0],
+ "GC.drawImage() at the monitor zoom should create a persistent handle "
+ + "so that win32_getHandle returns the same native object");
+ } finally {
+ image.dispose();
+ shell.dispose();
+ }
+ }
+
+ /**
+ * Tests that a persistent native handle already created via
+ * {@link Image#win32_getHandle(Image, int)} is found and reused by
+ * GC.drawImage() when the nearest available zoom for the requested draw size
+ * maps to the same zoom. This verifies that the
+ * {@code imageHandleManager.get(nearestAvailableZoom)} lookup is effective and
+ * avoids redundant handle allocation.
+ *
+ * See https://github.com/eclipse-platform/eclipse.platform.swt/issues/3419
+ */
+ @Test
+ public void testDrawImageReusesExistingPersistentHandleForNearestAvailableZoom() {
+ PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+ ImageData imageData = new ImageData(10, 10, 24, palette);
+ // Provider only has 100% data; every zoom falls back to 100%
+ Image image = new Image(Display.getDefault(), (ImageDataProvider) zoom -> zoom == 100 ? imageData : null);
+ try {
+ // Force creation of a persistent 100% handle (as would happen via GC.drawImage
+ // on a 100% zoom canvas or via Image.getImageData())
+ long persistentHandle = Image.win32_getHandle(image, 100);
+ assertNotEquals(0L, persistentHandle, "Persistent handle should be non-zero");
+ long[] drawHandle = {0};
+ // 20x20 pixels → 200% zoom equivalent for the 10x10 base image; nearest
+ // available is still 100%, so the already-cached persistent handle must be
+ // returned without allocating a new one
+ image.executeOnImageHandleAtBestFittingSize(h -> drawHandle[0] = h.handle(), 20, 20);
+ assertEquals(persistentHandle, drawHandle[0],
+ "GC.drawImage() should reuse the existing persistent handle when the "
+ + "nearest available zoom matches the cached handle's zoom (100% here)");
+ } finally {
+ image.dispose();
+ }
+ }
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/ToolBarWin32Tests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/ToolBarWin32Tests.java
new file mode 100644
index 00000000000..b89ad2dc3c4
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/ToolBarWin32Tests.java
@@ -0,0 +1,314 @@
+/*******************************************************************************
+ * Copyright (c) 2026 Vector Informatik GmbH 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
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.*;
+import java.util.function.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.layout.*;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.extension.*;
+
+/**
+ * Windows-specific tests for {@link ToolBar}'s image handling across monitor
+ * zoom changes.
+ */
+@ExtendWith(PlatformSpecificExecutionExtension.class)
+class ToolBarWin32Tests {
+
+ private static final int TIMEOUT_MILLIS = 5000;
+
+ private record ToolItemWithExpectedColor(ToolItem toolItem, RGB expectedColor) {
+ }
+
+ /**
+ * Regression test for a tool bar item rendering the wrong or a blank icon after
+ * a monitor zoom (DPI) change, as reported in issue
+ * #3466.
+ *
+ * The bug is triggered by clearing one item's image (which leaves the image
+ * list in a state that a later zoom change mishandles); neither disposing an
+ * image nor multiple monitors are required. The test observes the actual
+ * rendered result via public API only: each item gets a distinctly colored
+ * icon, and after the zoom change the dominant color under each item must still
+ * match that item's own icon.
+ */
+ @Test
+ void testIconsRenderedCorrectlyAfterZoomChangeWithImageListHole() {
+ Display display = new Display();
+ RGB[] colors = { new RGB(220, 40, 40), new RGB(40, 180, 40), new RGB(40, 40, 220), new RGB(230, 200, 30) };
+ Image[] icons = new Image[colors.length];
+ for (int i = 0; i < colors.length; i++) {
+ icons[i] = solidIcon(display, 16, colors[i]);
+ }
+ try {
+ Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+ ToolBar bar = new ToolBar(shell, SWT.FLAT);
+ ToolItem[] items = new ToolItem[colors.length];
+ for (int i = 0; i < colors.length; i++) {
+ items[i] = new ToolItem(bar, SWT.PUSH);
+ items[i].setImage(icons[i]);
+ }
+ shell.setSize(500, 90);
+ shell.open();
+
+ // Punch a hole below the other items: clear the first item's image.
+ items[0].setImage(null);
+
+ int zoom = bar.getAutoscalingZoom();
+ DPITestUtil.changeDPIZoom(bar.getShell(), zoom * 2);
+
+ // Only the first item is expected to rendered blank
+ Set itemsToCheck = new HashSet<>();
+ for (int i = 1; i < items.length; i++) {
+ itemsToCheck.add(new ToolItemWithExpectedColor(items[i], colors[i]));
+ }
+ // Dispatch events until every item renders its own icon color, or fail on
+ // timeout. With the bug an item permanently renders another item's icon or
+ // a blank one, so the condition is never met and the timeout triggers.
+ assertTrue(waitUntilIconsRenderOwnColor(display, () -> iconsRenderOwnColor(bar, itemsToCheck, colors),
+ TIMEOUT_MILLIS), "every tool item must render its own icon color after a zoom change");
+ } finally {
+ for (Image icon : icons)
+ icon.dispose();
+ display.dispose();
+ }
+ }
+
+ /**
+ * A tool bar addresses its normal, hot and disabled image list with a single
+ * index per item, and disposing an item frees its slot in those lists for
+ * reuse. The remaining items must keep rendering their own icon.
+ */
+ @Test
+ void testIconsRenderedCorrectlyAfterDisposingAnotherItem() {
+ Display display = new Display();
+ RGB[] colors = { new RGB(220, 40, 40), new RGB(40, 180, 40), new RGB(40, 40, 220) };
+ Image[] icons = createIcons(display, colors);
+ try {
+ Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+ ToolBar bar = new ToolBar(shell, SWT.FLAT);
+ ToolItem[] items = createItems(bar, icons);
+ shell.setSize(500, 90);
+ shell.open();
+
+ items[1].dispose();
+
+ Set itemsToCheck = Set.of(
+ new ToolItemWithExpectedColor(items[0], colors[0]),
+ new ToolItemWithExpectedColor(items[2], colors[2]));
+ assertTrue(waitUntilIconsRenderOwnColor(display, () -> iconsRenderOwnColor(bar, itemsToCheck, colors),
+ TIMEOUT_MILLIS), "every tool item must render its own icon after another item is disposed");
+ } finally {
+ disposeAll(icons, display);
+ }
+ }
+
+ /**
+ * Tool bars share the image lists for a given icon size, so the items of one
+ * tool bar must not be affected by those of another tool bar using icons of the
+ * same size.
+ */
+ @Test
+ void testIconsRenderedCorrectlyWithSecondToolBarUsingSameIconSize() {
+ Display display = new Display();
+ RGB[] colors = { new RGB(220, 40, 40), new RGB(40, 180, 40), new RGB(40, 40, 220), new RGB(230, 200, 30) };
+ Image[] icons = createIcons(display, colors);
+ try {
+ Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+ ToolBar firstBar = new ToolBar(shell, SWT.FLAT);
+ ToolItem[] firstItems = createItems(firstBar, icons[0], icons[1]);
+ ToolBar secondBar = new ToolBar(shell, SWT.FLAT);
+ ToolItem[] secondItems = createItems(secondBar, icons[2], icons[3]);
+ shell.setSize(500, 180);
+ shell.open();
+
+ Set firstItemsToCheck = Set.of(
+ new ToolItemWithExpectedColor(firstItems[0], colors[0]),
+ new ToolItemWithExpectedColor(firstItems[1], colors[1]));
+ Set secondItemsToCheck = Set.of(
+ new ToolItemWithExpectedColor(secondItems[0], colors[2]),
+ new ToolItemWithExpectedColor(secondItems[1], colors[3]));
+ assertTrue(
+ waitUntilIconsRenderOwnColor(display,
+ () -> iconsRenderOwnColor(firstBar, firstItemsToCheck, colors)
+ && iconsRenderOwnColor(secondBar, secondItemsToCheck, colors),
+ TIMEOUT_MILLIS),
+ "every tool item must render its own icon although both tool bars share the image lists");
+ } finally {
+ disposeAll(icons, display);
+ }
+ }
+
+ /**
+ * Changing the orientation moves every item's images into image lists created
+ * for the new orientation, which must retain the assignment of items to their
+ * icons.
+ */
+ @Test
+ void testIconsRenderedCorrectlyAfterOrientationChange() {
+ Display display = new Display();
+ RGB[] colors = { new RGB(220, 40, 40), new RGB(40, 180, 40), new RGB(40, 40, 220) };
+ Image[] icons = createIcons(display, colors);
+ try {
+ Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+ ToolBar bar = new ToolBar(shell, SWT.FLAT);
+ ToolItem[] items = createItems(bar, icons);
+ shell.setSize(500, 90);
+ shell.open();
+
+ bar.setOrientation(SWT.RIGHT_TO_LEFT);
+ bar.setOrientation(SWT.LEFT_TO_RIGHT);
+
+ Set itemsToCheck = new HashSet<>();
+ for (int i = 0; i < items.length; i++) {
+ itemsToCheck.add(new ToolItemWithExpectedColor(items[i], colors[i]));
+ }
+ assertTrue(waitUntilIconsRenderOwnColor(display, () -> iconsRenderOwnColor(bar, itemsToCheck, colors),
+ TIMEOUT_MILLIS), "every tool item must render its own icon after an orientation change");
+ } finally {
+ disposeAll(icons, display);
+ }
+ }
+
+ private static Image[] createIcons(Display display, RGB[] colors) {
+ Image[] icons = new Image[colors.length];
+ for (int i = 0; i < colors.length; i++) {
+ icons[i] = solidIcon(display, 16, colors[i]);
+ }
+ return icons;
+ }
+
+ private static ToolItem[] createItems(ToolBar bar, Image... icons) {
+ ToolItem[] items = new ToolItem[icons.length];
+ for (int i = 0; i < icons.length; i++) {
+ items[i] = new ToolItem(bar, SWT.PUSH);
+ items[i].setImage(icons[i]);
+ }
+ return items;
+ }
+
+ private static void disposeAll(Image[] icons, Display display) {
+ for (Image icon : icons) {
+ icon.dispose();
+ }
+ display.dispose();
+ }
+
+ private static boolean waitUntilIconsRenderOwnColor(Display display, BooleanSupplier condition,
+ long timeoutMillis) {
+ long deadline = System.currentTimeMillis() + timeoutMillis;
+ while (System.currentTimeMillis() < deadline) {
+ if (condition.getAsBoolean()) {
+ return true;
+ }
+ if (!display.readAndDispatch()) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+ }
+ }
+ return condition.getAsBoolean();
+ }
+
+ private static boolean iconsRenderOwnColor(ToolBar bar, Set items, RGB[] candidateColors) {
+ Image snapshot = renderToolBar(bar);
+ try {
+ for (ToolItemWithExpectedColor item : items) {
+ if (!item.expectedColor().equals(dominantIconColor(snapshot, item.toolItem().getBounds(), candidateColors))) {
+ return false;
+ }
+ }
+ return true;
+ } finally {
+ snapshot.dispose();
+ }
+ }
+
+ private static Image solidIcon(Display display, int size, RGB rgb) {
+ Image image = new Image(display, size, size);
+ GC gc = new GC(image);
+ Color color = new Color(display, rgb);
+ gc.setBackground(color);
+ gc.fillRectangle(0, 0, size, size);
+ gc.dispose();
+ return image;
+ }
+
+ private static Image renderToolBar(ToolBar bar) {
+ Point size = bar.getSize();
+ Image snapshot = new Image(bar.getDisplay(), Math.max(1, size.x), Math.max(1, size.y));
+ GC gc = new GC(snapshot);
+ bar.print(gc);
+ gc.dispose();
+ return snapshot;
+ }
+
+ /**
+ * Returns which of the given candidate icon colors dominates the area of an
+ * item. Each sufficiently saturated pixel is classified to its nearest
+ * candidate color; the candidate matching the most pixels wins. Classifying to
+ * a fixed palette (rather than comparing exact RGB values) makes the result
+ * deterministic despite anti-aliasing, DPI interpolation and theming.
+ */
+ private static RGB dominantIconColor(Image snapshot, Rectangle bounds, RGB[] candidates) {
+ ImageData data = snapshot.getImageData();
+ PaletteData palette = data.palette;
+ int[] votes = new int[candidates.length];
+ int x0 = Math.max(0, bounds.x), y0 = Math.max(0, bounds.y);
+ int x1 = Math.min(data.width, bounds.x + bounds.width);
+ int y1 = Math.min(data.height, bounds.y + bounds.height);
+ for (int y = y0; y < y1; y++) {
+ for (int x = x0; x < x1; x++) {
+ RGB rgb = palette.getRGB(data.getPixel(x, y));
+ int max = Math.max(rgb.red, Math.max(rgb.green, rgb.blue));
+ int min = Math.min(rgb.red, Math.min(rgb.green, rgb.blue));
+ if (max - min < 60) {
+ continue; // ignore low-saturation background/borders
+ }
+ int best = -1, bestDist = Integer.MAX_VALUE;
+ for (int c = 0; c < candidates.length; c++) {
+ int dr = rgb.red - candidates[c].red;
+ int dg = rgb.green - candidates[c].green;
+ int db = rgb.blue - candidates[c].blue;
+ int dist = dr * dr + dg * dg + db * db;
+ if (dist < bestDist) {
+ bestDist = dist;
+ best = c;
+ }
+ }
+ if (best >= 0)
+ votes[best]++;
+ }
+ }
+ int winner = -1, most = 0;
+ for (int c = 0; c < candidates.length; c++) {
+ if (votes[c] > most) {
+ most = votes[c];
+ winner = c;
+ }
+ }
+ return winner < 0 ? null : candidates[winner];
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Combo.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Combo.java
index 0597becb231..76e216736d1 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Combo.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Combo.java
@@ -1445,9 +1445,9 @@ boolean sendKeyEvent (NSEvent nsEvent, int type) {
int stateMask = 0;
long modifierFlags = nsEvent.modifierFlags();
if ((modifierFlags & OS.NSAlternateKeyMask) != 0) stateMask |= SWT.ALT;
- if ((modifierFlags & OS.NSShiftKeyMask) != 0) stateMask |= SWT.SHIFT;
- if ((modifierFlags & OS.NSControlKeyMask) != 0) stateMask |= SWT.CONTROL;
- if ((modifierFlags & OS.NSCommandKeyMask) != 0) stateMask |= SWT.COMMAND;
+ if ((modifierFlags & OS.NSEventModifierFlagShift) != 0) stateMask |= SWT.SHIFT;
+ if ((modifierFlags & OS.NSEventModifierFlagControl) != 0) stateMask |= SWT.CONTROL;
+ if ((modifierFlags & OS.NSEventModifierFlagCommand) != 0) stateMask |= SWT.COMMAND;
if (type != SWT.KeyDown) return result;
short keyCode = nsEvent.keyCode ();
if (stateMask == SWT.COMMAND) {
@@ -1484,7 +1484,7 @@ boolean sendTrackingKeyEvent (NSEvent nsEvent, int type) {
* queue.
*/
long modifiers = nsEvent.modifierFlags();
- if ((modifiers & OS.NSShiftKeyMask) == 0) {
+ if ((modifiers & OS.NSEventModifierFlagShift) == 0) {
short keyCode = nsEvent.keyCode ();
switch (keyCode) {
case 125: /* Arrow Down */
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java
index 8c2238e83cf..f28f96b24da 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java
@@ -1044,7 +1044,7 @@ void doCommandBySelector (long id, long sel, long selector) {
* is down, because we likely triggered the current key sequence via flagsChanged.
*/
long modifiers = nsEvent.modifierFlags();
- if (s.keyInputHappened == false || (modifiers & OS.NSCommandKeyMask) != 0) {
+ if (s.keyInputHappened == false || (modifiers & OS.NSEventModifierFlagCommand) != 0) {
s.keyInputHappened = true;
boolean [] consume = new boolean [1];
if (translateTraversal (nsEvent.keyCode (), nsEvent, consume)) return;
@@ -1363,9 +1363,9 @@ void flagsChanged (long id, long sel, long theEvent) {
int keyCode = Display.translateKey (nsEvent.keyCode ());
switch (keyCode) {
case SWT.ALT: mask = OS.NSAlternateKeyMask; break;
- case SWT.CONTROL: mask = OS.NSControlKeyMask; break;
- case SWT.COMMAND: mask = OS.NSCommandKeyMask; break;
- case SWT.SHIFT: mask = OS.NSShiftKeyMask; break;
+ case SWT.CONTROL: mask = OS.NSEventModifierFlagControl; break;
+ case SWT.COMMAND: mask = OS.NSEventModifierFlagCommand; break;
+ case SWT.SHIFT: mask = OS.NSEventModifierFlagShift; break;
case SWT.CAPS_LOCK:
Event event = new Event();
event.keyCode = keyCode;
@@ -2558,7 +2558,7 @@ boolean mouseEvent (long id, long sel, long theEvent, int type) {
switch (nsType) {
case OS.NSLeftMouseDown:
- if (nsEvent.clickCount() == 1 && (nsEvent.modifierFlags() & OS.NSControlKeyMask) == 0 && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
+ if (nsEvent.clickCount() == 1 && (nsEvent.modifierFlags() & OS.NSEventModifierFlagControl) == 0 && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
consume = new boolean[1];
NSPoint location = view.convertPoint_fromView_(nsEvent.locationInWindow(), null);
if (!view.isFlipped ()) {
@@ -4783,7 +4783,7 @@ boolean translateTraversal (int key, NSEvent theEvent, boolean [] consume) {
}
case 48: /* Tab */ {
long modifiers = theEvent.modifierFlags ();
- boolean next = (modifiers & OS.NSShiftKeyMask) == 0;
+ boolean next = (modifiers & OS.NSEventModifierFlagShift) == 0;
detail = next ? SWT.TRAVERSE_TAB_NEXT : SWT.TRAVERSE_TAB_PREVIOUS;
break;
}
@@ -4799,7 +4799,7 @@ boolean translateTraversal (int key, NSEvent theEvent, boolean [] consume) {
case 121: /* Page down */ {
all = true;
long modifiers = theEvent.modifierFlags ();
- if ((modifiers & OS.NSControlKeyMask) == 0) return false;
+ if ((modifiers & OS.NSEventModifierFlagControl) == 0) return false;
detail = key == 121 /* Page down */ ? SWT.TRAVERSE_PAGE_NEXT : SWT.TRAVERSE_PAGE_PREVIOUS;
break;
}
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 25f78cbc179..c2524f8e8c9 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
@@ -1103,7 +1103,7 @@ void createMainMenu () {
title = NSString.stringWith(SWT.getMessage("SWT_HideOthers"));
menuItem = appleMenu.addItemWithTitle(title, OS.sel_hideOtherApplications_, NSString.stringWith("h"));
- menuItem.setKeyEquivalentModifierMask(OS.NSCommandKeyMask | OS.NSAlternateKeyMask);
+ menuItem.setKeyEquivalentModifierMask(OS.NSEventModifierFlagCommand | OS.NSAlternateKeyMask);
menuItem.setTarget(applicationDelegate);
title = NSString.stringWith(SWT.getMessage("SWT_ShowAll"));
@@ -3924,9 +3924,9 @@ boolean performKeyEquivalent(NSWindow window, NSEvent nsEvent) {
long selector = 0;
long modifierFlags = nsEvent.modifierFlags();
if ((modifierFlags & OS.NSAlternateKeyMask) != 0) stateMask |= SWT.ALT;
- if ((modifierFlags & OS.NSShiftKeyMask) != 0) stateMask |= SWT.SHIFT;
- if ((modifierFlags & OS.NSControlKeyMask) != 0) stateMask |= SWT.CONTROL;
- if ((modifierFlags & OS.NSCommandKeyMask) != 0) stateMask |= SWT.COMMAND;
+ if ((modifierFlags & OS.NSEventModifierFlagShift) != 0) stateMask |= SWT.SHIFT;
+ if ((modifierFlags & OS.NSEventModifierFlagControl) != 0) stateMask |= SWT.CONTROL;
+ if ((modifierFlags & OS.NSEventModifierFlagCommand) != 0) stateMask |= SWT.COMMAND;
if (stateMask == SWT.COMMAND) {
short keyCode = nsEvent.keyCode ();
switch (keyCode) {
@@ -5679,7 +5679,7 @@ void applicationSendEvent (long id, long sel, long event) {
* Feature in Cocoa. The help key triggers context-sensitive help but doesn't get forwarded to the window as a key event.
* If the event is destined for the key window, is the help key, and is an NSKeyDown, send it directly to the window first.
*/
- if (window != null && window.isKeyWindow() && nsEvent.type() == OS.NSKeyDown && (nsEvent.modifierFlags() & OS.NSHelpKeyMask) != 0) {
+ if (window != null && window.isKeyWindow() && nsEvent.type() == OS.NSKeyDown && (nsEvent.modifierFlags() & OS.NSEventModifierFlagHelp) != 0) {
window.sendEvent(nsEvent);
}
@@ -5687,7 +5687,7 @@ void applicationSendEvent (long id, long sel, long event) {
* Feature in Cocoa. NSKeyUp events are not delivered to the window if the command key is down.
* If the event is destined for the key window, and it's a key up and the command key is down, send it directly to the window.
*/
- if (window != null && window.isKeyWindow() && nsEvent.type() == OS.NSKeyUp && (nsEvent.modifierFlags() & OS.NSCommandKeyMask) != 0) {
+ if (window != null && window.isKeyWindow() && nsEvent.type() == OS.NSKeyUp && (nsEvent.modifierFlags() & OS.NSEventModifierFlagCommand) != 0) {
window.sendEvent(nsEvent);
} else {
objc_super super_struct = new objc_super ();
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Link.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Link.java
index 6d075f0136a..c1f1fd465a7 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Link.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Link.java
@@ -824,7 +824,7 @@ int traversalCode (int key, NSEvent theEvent) {
int bits = super.traversalCode (key, theEvent);
if (key == 48 /* Tab */ && theEvent != null) {
long modifierFlags = theEvent.modifierFlags();
- boolean next = (modifierFlags & OS.NSShiftKeyMask) == 0;
+ boolean next = (modifierFlags & OS.NSEventModifierFlagShift) == 0;
if (next && focusIndex < offsets.length - 1) {
return bits & ~ SWT.TRAVERSE_TAB_NEXT;
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java
index 2bdf5da08c8..9c5bbfab320 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java
@@ -389,7 +389,7 @@ void createItem (MenuItem item, int index) {
long keyEquiv = 0;
if (keyEquivString != null) {
keyEquiv = keyEquivString.characterAtIndex(0);
- if ((keyMask & OS.NSCommandKeyMask) != 0) keyEquiv |= SWT.COMMAND;
+ if ((keyMask & OS.NSEventModifierFlagCommand) != 0) keyEquiv |= SWT.COMMAND;
if ((keyMask & OS.NSAlternateKeyMask) != 0) keyEquiv |= SWT.ALT;
item.accelerator = (int) keyEquiv;
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MenuItem.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MenuItem.java
index 512ef0ab5ca..5ddd1191c6d 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MenuItem.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MenuItem.java
@@ -623,9 +623,9 @@ public void setAccelerator (int accelerator) {
nsItem.setKeyEquivalent (nsstring.lowercaseString());
nsstring.release();
int mask = 0;
- if ((accelerator & SWT.SHIFT) != 0) mask |= OS.NSShiftKeyMask;
- if ((accelerator & SWT.CONTROL) != 0) mask |= OS.NSControlKeyMask;
- if ((accelerator & SWT.COMMAND) != 0) mask |= OS.NSCommandKeyMask;
+ if ((accelerator & SWT.SHIFT) != 0) mask |= OS.NSEventModifierFlagShift;
+ if ((accelerator & SWT.CONTROL) != 0) mask |= OS.NSEventModifierFlagControl;
+ if ((accelerator & SWT.COMMAND) != 0) mask |= OS.NSEventModifierFlagCommand;
if ((accelerator & SWT.ALT) != 0) mask |= OS.NSAlternateKeyMask;
nsItem.setKeyEquivalentModifierMask (mask);
}
@@ -951,10 +951,10 @@ boolean updateAccelerator (boolean show) {
if (i < buffer.length && buffer [i] == '\t') {
for (j = i + 1; j < buffer.length; j++) {
switch (buffer [j]) {
- case '\u2303': mask |= OS.NSControlKeyMask; i++; break;
+ case '\u2303': mask |= OS.NSEventModifierFlagControl; i++; break;
case '\u2325': mask |= OS.NSAlternateKeyMask; i++; break;
- case '\u21E7': mask |= OS.NSShiftKeyMask; i++; break;
- case '\u2318': mask |= OS.NSCommandKeyMask; i++; break;
+ case '\u21E7': mask |= OS.NSEventModifierFlagShift; i++; break;
+ case '\u2318': mask |= OS.NSEventModifierFlagCommand; i++; break;
default:
j = buffer.length;
break;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MessageBox.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MessageBox.java
index 53684bcb4d2..2358dc0186b 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MessageBox.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/MessageBox.java
@@ -151,16 +151,16 @@ public String getMessage () {
*/
public int open () {
NSAlert alert = (NSAlert) new NSAlert().alloc().init();
- int alertType = OS.NSInformationalAlertStyle;
+ int alertType = OS.NSAlertStyleInformational;
if ((style & SWT.ICON_ERROR) != 0) {
- alertType = OS.NSCriticalAlertStyle;
+ alertType = OS.NSAlertStyleCritical;
}
if (((style & SWT.ICON_INFORMATION) != 0) || ((style & SWT.ICON_WORKING) != 0) || ((style & SWT.ICON_QUESTION) != 0)) {
- alertType = OS.NSInformationalAlertStyle;
+ alertType = OS.NSAlertStyleInformational;
alert.setIcon(NSImage.imageNamed(OS.NSImageNameInfo));
}
if ((style & SWT.ICON_WARNING) != 0) {
- alertType = OS.NSWarningAlertStyle;
+ alertType = OS.NSAlertStyleWarning;
alert.setIcon(NSImage.imageNamed(OS.NSImageNameCaution));
}
alert.setAlertStyle(alertType);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ProgressBar.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ProgressBar.java
index eac59b1a91f..a01615d5b55 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ProgressBar.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ProgressBar.java
@@ -87,7 +87,11 @@ static int checkStyle (int style) {
@Override
public Point computeSize (int wHint, int hHint, boolean changed) {
checkWidget();
- int size = OS.NSProgressIndicatorPreferredThickness;
+ NSProgressIndicator widget = (NSProgressIndicator)view;
+ NSRect oldFrame = widget.frame();
+ widget.sizeToFit();
+ int size = (int)widget.frame().height;
+ widget.setFrame(oldFrame);
int width = 0, height = 0;
if ((style & SWT.HORIZONTAL) != 0) {
height = size;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Sash.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Sash.java
index e9792688bc5..200a9ec1e98 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Sash.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Sash.java
@@ -305,7 +305,7 @@ boolean sendKeyEvent(NSEvent nsEvent, int type) {
int xChange = 0, yChange = 0;
int stepSize = PAGE_INCREMENT;
long modifiers = nsEvent.modifierFlags();
- if ((modifiers & OS.NSControlKeyMask) != 0) stepSize = INCREMENT;
+ if ((modifiers & OS.NSEventModifierFlagControl) != 0) stepSize = INCREMENT;
if ((style & SWT.VERTICAL) != 0) {
if (keyCode == 126 || keyCode == 125) break;
xChange = keyCode == 123 ? -stepSize : stepSize;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ScrollBar.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ScrollBar.java
index ea25420fec6..8e29470b678 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ScrollBar.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/ScrollBar.java
@@ -481,18 +481,10 @@ void sendSelection () {
int hitPart = (int)((NSScroller)view).testPart(point);
Event event = new Event();
switch (hitPart) {
- case OS.NSScrollerDecrementLine:
- value -= increment;
- event.detail = SWT.ARROW_UP;
- break;
case OS.NSScrollerDecrementPage:
value -= pageIncrement;
event.detail = SWT.PAGE_UP;
break;
- case OS.NSScrollerIncrementLine:
- value += increment;
- event.detail = SWT.ARROW_DOWN;
- break;
case OS.NSScrollerIncrementPage:
value += pageIncrement;
event.detail = SWT.PAGE_DOWN;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Shell.java
index 9ef9aa678ea..0029ba4b3bb 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Shell.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Shell.java
@@ -2515,7 +2515,7 @@ void windowSendEvent (long id, long sel, long event) {
* swallowed to handle native traversal. If we find that, force the key event to
* the first responder.
*/
- if ((nsEvent.modifierFlags() & OS.NSControlKeyMask) != 0) {
+ if ((nsEvent.modifierFlags() & OS.NSEventModifierFlagControl) != 0) {
NSString chars = nsEvent.characters();
if (chars != null && chars.length() == 1) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Slider.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Slider.java
index 43e73d710fb..a6490a86622 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Slider.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Slider.java
@@ -333,18 +333,10 @@ void sendSelection () {
int hitPart = (int)((NSScroller)view).hitPart();
int value = getSelection ();
switch (hitPart) {
- case OS.NSScrollerDecrementLine:
- event.detail = SWT.ARROW_UP;
- value -= increment;
- break;
case OS.NSScrollerDecrementPage:
value -= pageIncrement;
event.detail = SWT.PAGE_UP;
break;
- case OS.NSScrollerIncrementLine:
- value += increment;
- event.detail = SWT.ARROW_DOWN;
- break;
case OS.NSScrollerIncrementPage:
value += pageIncrement;
event.detail = SWT.PAGE_DOWN;
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 49549fcf9ca..5d6825ec32a 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
@@ -258,7 +258,7 @@ boolean canDragRowsWithIndexes_atPoint(long id, long sel, long rowIndexes, NSPoi
boolean drag = (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect);
if (drag) {
- if (!widget.isRowSelected(row) && (modifiers & (OS.NSCommandKeyMask | OS.NSShiftKeyMask | OS.NSAlternateKeyMask)) == 0) {
+ if (!widget.isRowSelected(row) && (modifiers & (OS.NSEventModifierFlagCommand | OS.NSEventModifierFlagShift | OS.NSAlternateKeyMask)) == 0) {
NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
set = set.initWithIndex(row);
widget.selectRowIndexes (set, false);
@@ -2080,7 +2080,7 @@ void mouseDown (long id, long sel, long theEvent) {
// which is interpreted as a single click that clears the selection. Fix is to ignore control-click if the
// view has a context menu.
NSEvent event = new NSEvent(theEvent);
- if ((event.modifierFlags() & OS.NSControlKeyMask) != 0) return;
+ if ((event.modifierFlags() & OS.NSEventModifierFlagControl) != 0) return;
}
super.mouseDown(id, sel, theEvent);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Text.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Text.java
index ee965adcccd..17fd2df1630 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Text.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Text.java
@@ -1714,7 +1714,7 @@ boolean sendKeyEvent (NSEvent nsEvent, int type) {
if (!result) return result;
if (type != SWT.KeyDown) return result;
long modifierFlags = nsEvent.modifierFlags();
- if ((modifierFlags & OS.NSCommandKeyMask) != 0) {
+ if ((modifierFlags & OS.NSEventModifierFlagCommand) != 0) {
short keyCode = nsEvent.keyCode ();
switch (keyCode) {
case 7: /* X */
@@ -2460,8 +2460,8 @@ int traversalCode (int key, NSEvent theEvent) {
bits &= ~SWT.TRAVERSE_RETURN;
if (key == 48 /* Tab */ && theEvent != null) {
long modifiers = theEvent.modifierFlags ();
- boolean next = (modifiers & OS.NSShiftKeyMask) == 0;
- if (next && (modifiers & OS.NSControlKeyMask) == 0) {
+ boolean next = (modifiers & OS.NSEventModifierFlagShift) == 0;
+ if (next && (modifiers & OS.NSEventModifierFlagControl) == 0) {
bits &= ~(SWT.TRAVERSE_TAB_NEXT | SWT.TRAVERSE_TAB_PREVIOUS);
}
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tracker.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tracker.java
index aa8e2507e93..374a5f3c93d 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tracker.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Tracker.java
@@ -559,9 +559,9 @@ void key (NSEvent nsEvent) {
int mask = 0;
switch (keyCode) {
case SWT.ALT: mask = OS.NSAlternateKeyMask; break;
- case SWT.CONTROL: mask = OS.NSControlKeyMask; break;
- case SWT.COMMAND: mask = OS.NSCommandKeyMask; break;
- case SWT.SHIFT: mask = OS.NSShiftKeyMask; break;
+ case SWT.CONTROL: mask = OS.NSEventModifierFlagControl; break;
+ case SWT.COMMAND: mask = OS.NSEventModifierFlagCommand; break;
+ case SWT.SHIFT: mask = OS.NSEventModifierFlagShift; break;
case SWT.CAPS_LOCK:
Event event = new Event();
event.keyCode = keyCode;
@@ -583,7 +583,7 @@ void key (NSEvent nsEvent) {
}
}
- int stepSize = (modifierFlags & OS.NSControlKeyMask) != 0 ? STEPSIZE_SMALL : STEPSIZE_LARGE;
+ int stepSize = (modifierFlags & OS.NSEventModifierFlagControl) != 0 ? STEPSIZE_SMALL : STEPSIZE_LARGE;
int xChange = 0, yChange = 0;
switch (nsKeyCode) {
case 53: /* Esc */
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TrayItem.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TrayItem.java
index 00b271bfdf7..328e6139996 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TrayItem.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/TrayItem.java
@@ -510,7 +510,7 @@ boolean shouldShowMenu (NSEvent event) {
if (!(hooks(SWT.Selection) || hooks(SWT.DefaultSelection))) {
return true;
}
- if ((event.modifierFlags() & OS.NSDeviceIndependentModifierFlagsMask) == OS.NSControlKeyMask) {
+ if ((event.modifierFlags() & OS.NSDeviceIndependentModifierFlagsMask) == OS.NSEventModifierFlagControl) {
return true;
}
return 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 0a92f0beb2f..4195ef69532 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
@@ -312,7 +312,7 @@ boolean canDragRowsWithIndexes_atPoint(long id, long sel, long rowIndexes, NSPoi
boolean drag = (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect);
if (drag) {
- if (!widget.isRowSelected(row) && (modifiers & (OS.NSCommandKeyMask | OS.NSShiftKeyMask | OS.NSAlternateKeyMask | OS.NSControlKeyMask)) == 0) {
+ if (!widget.isRowSelected(row) && (modifiers & (OS.NSEventModifierFlagCommand | OS.NSEventModifierFlagShift | OS.NSAlternateKeyMask | OS.NSEventModifierFlagControl)) == 0) {
NSIndexSet set = (NSIndexSet)new NSIndexSet().alloc();
set = set.initWithIndex(row);
widget.selectRowIndexes (set, false);
@@ -2133,7 +2133,7 @@ void mouseDown (long id, long sel, long theEvent) {
// it from menuForEvent:. This has the side effect, however, of sending control-click to the NSTableView,
// which is interpreted as a single click that clears the selection. Fix is to ignore control-click,
NSEvent event = new NSEvent(theEvent);
- if ((event.modifierFlags() & OS.NSControlKeyMask) != 0) return;
+ if ((event.modifierFlags() & OS.NSEventModifierFlagControl) != 0) return;
}
super.mouseDown(id, sel, theEvent);
}
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 9e3b018b5f1..3804a64ecf6 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
@@ -1879,9 +1879,9 @@ boolean setInputState (Event event, NSEvent nsEvent, int type) {
}
long modifierFlags = nsEvent.modifierFlags();
if ((modifierFlags & OS.NSAlternateKeyMask) != 0) event.stateMask |= SWT.ALT;
- if ((modifierFlags & OS.NSShiftKeyMask) != 0) event.stateMask |= SWT.SHIFT;
- if ((modifierFlags & OS.NSControlKeyMask) != 0) event.stateMask |= SWT.CONTROL;
- if ((modifierFlags & OS.NSCommandKeyMask) != 0) event.stateMask |= SWT.COMMAND;
+ if ((modifierFlags & OS.NSEventModifierFlagShift) != 0) event.stateMask |= SWT.SHIFT;
+ if ((modifierFlags & OS.NSEventModifierFlagControl) != 0) event.stateMask |= SWT.CONTROL;
+ if ((modifierFlags & OS.NSEventModifierFlagCommand) != 0) event.stateMask |= SWT.COMMAND;
long state = NSEvent.pressedMouseButtons();
if ((state & 0x1) != 0) event.stateMask |= SWT.BUTTON1;
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 d66419e442d..672f294dafe 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
@@ -14,4 +14,4 @@
maj_ver=4
min_ver=974
-rev=7
+rev=10
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/widgets/Item.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/widgets/Item.java
index fd33f71ca76..c3e16f24878 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/widgets/Item.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/widgets/Item.java
@@ -230,7 +230,6 @@ private void handleDPIChange(Event event) {
// Refresh the image
Image image = getImage();
if (image != null) {
- setImage(null);
setImage(image);
}
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Combo.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Combo.java
index d58fed8720e..8b4df26c073 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Combo.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Combo.java
@@ -2555,7 +2555,7 @@ public void setText (String string) {
* fix is to block the firing of these events and fire them ourselves in a consistent manner.
*/
if (hooks (SWT.Verify) || filters (SWT.Verify)) {
- long ptr = GTK3.gtk_entry_get_text (entryHandle);
+ long ptr = GTK.GTK4 ? GTK4.gtk_entry_buffer_get_text (GTK4.gtk_entry_get_buffer (entryHandle)) : GTK3.gtk_entry_get_text (entryHandle);
string = verifyText (string, 0, (int)OS.g_utf16_strlen (ptr, -1));
if (string == null) return;
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java
index e6b18fbacfb..16dd1e00540 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java
@@ -165,8 +165,15 @@ Control[] _getChildren () {
long parentHandle = parentingHandle();
if (GTK.GTK4) {
+ /*
+ * The GTK4 child list is ordered back-to-front (first = bottom, last =
+ * top), because that is the order GTK4 paints its children in. This
+ * method has to hand out the topmost child first, so walk the native
+ * list backwards - that also makes the result match GTK3, whose
+ * swt_fixed list is kept in front-to-back order instead.
+ */
ArrayList childrenList = new ArrayList<>();
- for (long child = GTK4.gtk_widget_get_first_child(parentHandle); child != 0; child = GTK4.gtk_widget_get_next_sibling(child)) {
+ for (long child = GTK4.gtk_widget_get_last_child(parentHandle); child != 0; child = GTK4.gtk_widget_get_prev_sibling(child)) {
Widget childWidget = display.getWidget(child);
if (childWidget != null && childWidget instanceof Control && childWidget != this) {
childrenList.add((Control)childWidget);
@@ -727,10 +734,16 @@ void fixZOrder () {
if ((state & CANVAS) != 0) return;
long parentHandle = parentingHandle ();
if (GTK.GTK4) {
- /* TODO: GTK4 parent does not hold the list of children it has created (parent-children relationship can only be done
- * with GdkPopup) Will need to consider if we can get children some other way or not have to do fixZOrder at all
- * and use GdkPopup autohide feature.
+ /*
+ * Keep the widget's own content at the very bottom of the child list, so
+ * that child controls (e.g. Table/Tree editors) are never stacked behind
+ * it. This mirrors the GTK3 branch below, which lowers the widget's own
+ * internal GdkWindows underneath those of the children.
*/
+ long content = scrolledHandle != 0 ? scrolledHandle : handle;
+ if (content != 0 && GTK.gtk_widget_get_parent (content) == parentHandle) {
+ GTK4.gtk_widget_insert_after (content, parentHandle, 0L);
+ }
} else {
long parentWindow = gtk_widget_get_window (parentHandle);
if (parentWindow == 0) return;
@@ -1395,10 +1408,20 @@ void moveAbove (long child, long sibling) {
if (child == sibling) return;
long parentHandle = parentingHandle ();
if (GTK.GTK4) {
+ /*
+ * GTK4 has no per-widget GdkWindow: paint and hit-test order is simply
+ * the parent's child-list order, first = bottom, last = top. So "above"
+ * means "later in the list" - the mirror image of the GTK3 swt_fixed
+ * list, where the head of the list is the topmost child.
+ *
+ * gtk_widget_insert_before(..., NULL) appends (top of the z-order),
+ * gtk_widget_insert_after(..., sibling) places the child directly on
+ * top of that sibling.
+ */
if (sibling == 0) {
- GTK4.gtk_widget_insert_after(child, parentHandle, 0L);
+ GTK4.gtk_widget_insert_before(child, parentHandle, 0L);
} else {
- GTK4.gtk_widget_insert_before(child, parentHandle, sibling);
+ GTK4.gtk_widget_insert_after(child, parentHandle, sibling);
}
} else {
OS.swt_fixed_restack (parentHandle, child, sibling, true);
@@ -1409,15 +1432,25 @@ void moveAbove (long child, long sibling) {
void moveBelow (long child, long sibling) {
if (child == sibling) return;
long parentHandle = parentingHandle ();
- if (sibling == 0 && parentHandle == fixedHandle) {
+ /*
+ * GTK3-only: when sibling == 0 (move to the bottom of the z-order) the
+ * child would be stacked behind the scrolled content's GdkWindow, hiding
+ * overlay controls such as Table/Tree editors. Re-place it just above the
+ * scrolled content instead.
+ *
+ * Not needed on GTK4: widgets have no per-widget GdkWindow, so paint order
+ * is simply the parent's child-list order (first = bottom, last = top).
+ */
+ if (!GTK.GTK4 && sibling == 0 && parentHandle == fixedHandle) {
moveAbove (child, scrolledHandle != 0 ? scrolledHandle : handle);
return;
}
if (GTK.GTK4) {
+ /* Mirror image of moveAbove - see the comment there. */
if (sibling == 0) {
- GTK4.gtk_widget_insert_before(child, parentHandle, 0L);
+ GTK4.gtk_widget_insert_after(child, parentHandle, 0L);
} else {
- GTK4.gtk_widget_insert_after(child, parentHandle, sibling);
+ GTK4.gtk_widget_insert_before(child, parentHandle, sibling);
}
} else {
OS.swt_fixed_restack (parentHandle, child, sibling, false);
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 c78a643e29c..2bfa4ee4980 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
@@ -2501,7 +2501,9 @@ public void removePaintListener(PaintListener listener) {
void removeRelation () {
if (!isDescribedByLabel ()) return; /* there will not be any */
if (labelRelation != null) {
- _getAccessible().removeRelation (ACC.RELATION_LABELLED_BY, labelRelation._getAccessible());
+ if (accessible != null && labelRelation.accessible != null) {
+ accessible.removeRelation (ACC.RELATION_LABELLED_BY, labelRelation.accessible);
+ }
labelRelation = null;
}
}
@@ -4831,10 +4833,10 @@ void destroyWidget() {
// GTK windows don't have a parent, so destroy it now
GTK4.gtk_window_destroy(currHandle);
} else if (parent != null) {
- if (fixedHandle != 0) {
- // Remove widget from hierarchy by removing it from parent container
- OS.swt_fixed_remove(parent.parentingHandle(), fixedHandle);
- }
+ /* Use currHandle, not fixedHandle alone - widgets without a
+ * separate fixedHandle wrapper were otherwise never actually
+ * unparented here, leaving them alive and rendered natively. */
+ OS.swt_fixed_remove(parent.parentingHandle(), currHandle);
} else {
assert false : "widgets must have a parent or be a GtkWindow";
}
@@ -6153,6 +6155,20 @@ public void setVisible (boolean visible) {
if (enableWindow != 0) GDK.gdk_window_show_unraised(enableWindow);
}
gtk_widget_show (topHandle);
+ /*
+ * On GTK4, a Composite laid out while it (or an ancestor) is hidden can end
+ * up with its children sized against a stale 0x0 client area, because
+ * gtk_widget_hide() resets allocations to 0x0 (issue #3330) and setBounds on a
+ * hidden widget shows/allocates/re-hides it. The size given while hidden is
+ * still stored in the parent's swt_fixed child list, so re-running the parent's
+ * size allocation re-applies this control's real size (restoring its client
+ * area), after which a re-layout of its own subtree lets the children pick up
+ * the now-correct client area. See issue #3450.
+ */
+ if (GTK.GTK4 && this instanceof Composite composite && composite.layout != null) {
+ parent.forceResize ();
+ composite.layout (true, true);
+ }
}
} else {
/*
@@ -6226,9 +6242,12 @@ void setZOrder (Control sibling, boolean above, boolean fixRelations, boolean fi
long topHandle = topHandle ();
long siblingHandle = sibling != null ? sibling.topHandle () : 0;
- if (GTK.GTK4) {
- //TODO: Test GTK3 behavior then implement, probably using gdk_toplevel_lower
- } else {
+ /*
+ * Nothing to restack on GTK4: its widgets have no GdkWindow of their own, so
+ * the z-order is entirely determined by the position in the parent's child
+ * list, which parent.moveAbove()/moveBelow() below takes care of.
+ */
+ if (!GTK.GTK4) {
long window = gtk_widget_get_window (topHandle);
if (window != 0) {
long siblingWindow = 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 ab7d2e476e3..4a1bc89cce3 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
@@ -135,12 +135,14 @@ public class Display extends Device implements Executor {
long changeValueProc;
long snapshotDrawProc, keyPressReleaseProc, focusProc, windowActiveProc, enterMotionProc, leaveProc,
scrollProc, resizeProc, layoutProc, activateProc, gesturePressReleaseProc;
+ long menuItemsChangedProc;
long notifyProc;
long computeSizeProc;
Callback windowCallback2, windowCallback3, windowCallback4, windowCallback5, windowCallback6;
Callback changeValue;
Callback snapshotDraw, keyPressReleaseCallback, focusCallback, windowActiveCallback, enterMotionCallback, computeSizeCallback,
scrollCallback, leaveCallback, resizeCallback, layoutCallback, activateCallback, gesturePressReleaseCallback;
+ Callback menuItemsChangedCallback;
Callback notifyCallback;
EventTable eventTable, filterTable;
static String APP_NAME = "SWT"; //$NON-NLS-1$
@@ -3633,6 +3635,10 @@ void initializeCallbacks () {
activateCallback = new Callback(this, "activateProc", void.class, new Type[] {long.class, long.class, long.class}); //$NON-NLS-1$
activateProc = activateCallback.getAddress();
+ menuItemsChangedCallback = new Callback(this, "menuItemsChangedProc", void.class, new Type[] {
+ long.class, int.class, int.class, int.class, long.class}); //$NON-NLS-1$
+ menuItemsChangedProc = menuItemsChangedCallback.getAddress();
+
computeSizeCallback = new Callback(this, "computeSizeProc", void.class, new Type[] {long.class, long.class, long.class}); //$NON-NLS-1$
computeSizeProc = computeSizeCallback.getAddress();
}
@@ -4671,6 +4677,10 @@ void releaseDisplay () {
activateCallback = null;
activateProc = 0;
+ menuItemsChangedCallback.dispose();
+ menuItemsChangedCallback = null;
+ menuItemsChangedProc = 0;
+
computeSizeCallback.dispose();
computeSizeCallback = null;
computeSizeProc = 0;
@@ -6145,6 +6155,11 @@ void activateProc(long action, long parameter, long user_data) {
widget.gtk_activate(user_data);
}
+void menuItemsChangedProc(long model, int position, int removed, int added, long user_data) {
+ Widget widget = getWidget(user_data);
+ if (widget instanceof Menu menu) menu.modelItemsChanged();
+}
+
void resizeProc(long handle, int width, int height) {
Widget widget = getWidget(handle);
if (widget != null) widget.gtk_size_allocate(handle, 0);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java
index 8f5c2159541..19467e4b2d3 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java
@@ -261,6 +261,88 @@ boolean ableToSetLocation() {
return hasLocation;
}
+/*
+ * GtkPopoverMenu inserts section-separator widgets from a GLib idle callback
+ * (gtk_menu_section_box_handle_sync_separators). Calling gtk_popover_popup()
+ * synchronously would measure the menu before those widgets exist, undersizing
+ * it into a scrollbar. Deferring via asyncExec lets that idle run first.
+ */
+void popupGtk4Popover(boolean hasPointingTo, int pointX, int pointY) {
+ if (isDisposed()) return;
+ display.asyncExec(() -> {
+ if (isDisposed()) return;
+ if (hasPointingTo) {
+ GdkRectangle popoverPosition = new GdkRectangle();
+ popoverPosition.x = pointX;
+ popoverPosition.y = pointY;
+ popoverPosition.width = popoverPosition.height = 1;
+ GTK.gtk_popover_set_pointing_to(handle, popoverPosition);
+ // Hide during the fit (scheduleGtk4PopoverFit) so the menu appears
+ // directly at its final location without a visible jump.
+ GTK.gtk_widget_set_opacity(handle, 0.0);
+ GTK.gtk_popover_popup(handle);
+ scheduleGtk4PopoverFit(pointX, pointY, 0);
+ } else {
+ GTK.gtk_popover_popup(handle);
+ }
+ });
+}
+
+/*
+ * Keep a bottom-of-screen popup menu from being shrunk into a scrolled view.
+ *
+ * GtkPopover's layout carries GDK_ANCHOR_RESIZE_Y (a GtkPopoverMenu can always
+ * shrink), so when the menu fits neither below the anchor nor flipped above it,
+ * the compositor shrinks it and shows a scrollbar. Wayland has no global window
+ * coordinates, so we cannot compute the overflow directly; instead we compare
+ * the popover's allocated height to its natural height and shift the anchor up
+ * by the shortfall, which yields exactly that much more room below. Repeated
+ * until it fits (usually 2-3 passes; the bound is just a safety cap). The
+ * popover stays hidden until settled.
+ */
+static final int GTK4_POPOVER_FIT_MAX_ITERATIONS = 6;
+
+void scheduleGtk4PopoverFit(int pointX, int pointY, int iteration) {
+ display.asyncExec(() -> {
+ if (isDisposed()) return;
+ if (!GTK.gtk_widget_get_mapped(handle)) {
+ // Menu was dismissed before it settled; make sure it is not left
+ // permanently transparent for a future show.
+ GTK.gtk_widget_set_opacity(handle, 1.0);
+ return;
+ }
+ if (iteration >= GTK4_POPOVER_FIT_MAX_ITERATIONS) {
+ revealGtk4Popover();
+ return;
+ }
+ int[] natHeight = new int[1];
+ GTK4.gtk_widget_measure(handle, GTK.GTK_ORIENTATION_VERTICAL, -1, null, natHeight, null, null);
+ int allocated = GTK4.gtk_widget_get_height(handle);
+ if (natHeight[0] <= 0 || allocated <= 0) {
+ // Not measured/allocated yet; wait another turn.
+ scheduleGtk4PopoverFit(pointX, pointY, iteration + 1);
+ return;
+ }
+ int shortfall = natHeight[0] - allocated;
+ if (shortfall <= 0) {
+ revealGtk4Popover();
+ return;
+ }
+ int newPointY = pointY - shortfall;
+ GdkRectangle popoverPosition = new GdkRectangle();
+ popoverPosition.x = pointX;
+ popoverPosition.y = newPointY;
+ popoverPosition.width = popoverPosition.height = 1;
+ GTK.gtk_popover_set_pointing_to(handle, popoverPosition);
+ scheduleGtk4PopoverFit(pointX, newPointY, iteration + 1);
+ });
+}
+
+void revealGtk4Popover() {
+ if (isDisposed()) return;
+ GTK.gtk_widget_set_opacity(handle, 1.0);
+}
+
void _setVisible (boolean visible) {
if (visible == GTK.gtk_widget_get_mapped (handle)) return;
if (visible) {
@@ -307,7 +389,6 @@ void _setVisible (boolean visible) {
long eventPtr = 0;
if (ableToSetLocation()) {
if (GTK.GTK4) {
- GdkRectangle popoverPosition = new GdkRectangle();
/*
* gtk_popover_set_pointing_to expects coordinates in the coordinate
* space of the popover's current parent widget.
@@ -323,24 +404,16 @@ void _setVisible (boolean visible) {
* relative to that control - do not apply the shell to
* parent.handle translation.
*/
+ int pointX = x, pointY = y;
long currentParent = GTK.gtk_widget_get_parent(handle);
if (currentParent == parent.handle) {
double[] relX = new double[1], relY = new double[1];
if (GTK4.gtk_widget_translate_coordinates(parent.getShell().topHandle(), parent.handle, x, y, relX, relY)) {
- popoverPosition.x = (int) relX[0];
- popoverPosition.y = (int) relY[0];
- } else {
- popoverPosition.x = x;
- popoverPosition.y = y;
+ pointX = (int) relX[0];
+ pointY = (int) relY[0];
}
- } else {
- popoverPosition.x = x;
- popoverPosition.y = y;
}
- popoverPosition.width = popoverPosition.height = 1;
- GTK.gtk_popover_set_pointing_to(handle, popoverPosition);
-
- GTK.gtk_popover_popup(handle);
+ popupGtk4Popover(true, pointX, pointY);
} else {
// Create the GdkEvent manually as we need to control
// certain fields like the event window
@@ -384,7 +457,7 @@ void _setVisible (boolean visible) {
}
} else {
if (GTK.GTK4) {
- GTK.gtk_popover_popup(handle);
+ popupGtk4Popover(false, 0, 0);
} else {
/*
* GTK Feature: gtk_menu_popup is deprecated as of GTK3.22 and the new method gtk_menu_popup_at_pointer
@@ -871,6 +944,86 @@ long gtk_map (long widget) {
return super.gtk_map(widget);
}
+/**
+ * Re-runs the CASCADE submenu SHOW/HIDE wiring after the menu structure changed
+ * while already mapped. The initial wiring at
+ * {@link #gtk_map}/{@link #gtk_show} only covers submenus that existed then;
+ * ones attached, replaced or rebuilt later would otherwise never get their
+ * {@link SWT#Show} event, making lazily-populated submenus appear empty.
+ */
+private void reconnectDropDownMenuSignalsIfMapped() {
+ if (!GTK.GTK4) return;
+ if ((style & SWT.BAR) != 0) {
+ if (handle != 0 && GTK.gtk_widget_get_mapped(handle)) {
+ connectDropDownMenuSignals();
+ }
+ } else if ((style & SWT.POP_UP) != 0) {
+ if (handle != 0 && GTK.gtk_widget_get_mapped(handle)) {
+ connectCascadeSubMenuSignals(this, handle);
+ }
+ } else if ((style & SWT.DROP_DOWN) != 0) {
+ if (popoverHandle != 0 && GTK.gtk_widget_get_mapped(popoverHandle)) {
+ connectCascadeSubMenuSignals(this, popoverHandle);
+ }
+ }
+}
+
+/**
+ * Hooks this menu's {@code items-changed} handler on the given {@code GMenu}
+ * model (no-op for {@code 0}), routing back via {@link #handle}. Connected in the
+ * signal's after phase so it runs once GTK's {@code GtkMenuTracker} has
+ * already (re)built the nested GtkPopoverMenu widgets, letting re-wiring run
+ * synchronously.
+ */
+void hookItemsChanged(long model) {
+ if (GTK.GTK4 && model != 0) {
+ long closure = OS.g_cclosure_new(display.menuItemsChangedProc, handle, 0);
+ OS.g_signal_connect_closure(model, OS.items_changed, closure, true);
+ }
+}
+
+/**
+ * Called when this menu's {@code GMenuModel} emitted {@code items-changed} (its
+ * content was modified after creation). Re-runs the CASCADE submenu wiring from
+ * the nearest mapped ancestor so any nested GtkPopoverMenu GTK (re)built gets its
+ * {@link SWT#Show} routed to the SWT DROP_DOWN submenu. Runs synchronously (see
+ * {@link #hookItemsChanged(long)}); a cheap no-op if no ancestor is mapped.
+ */
+void modelItemsChanged() {
+ if (!GTK.GTK4 || isDisposed()) return;
+ Menu root = this;
+ while (root.cascade != null && root.cascade.parent != null && !root.cascade.parent.isDisposed()) {
+ root = root.cascade.parent;
+ }
+ root.reconnectDropDownMenuSignalsIfMapped();
+}
+
+/**
+ * Wires the SHOW/HIDE signals of the given DROP_DOWN {@code submenu} to the
+ * discovered {@code popover} GtkPopoverMenu widget, refreshing the SWT-side
+ * cache. If the submenu was previously wired to a now-stale popover (e.g. GTK
+ * rebuilt the widget after a model change), the stale handle is released first.
+ */
+private void wireSubMenuPopover(Menu submenu, long popover) {
+ if (submenu.popoverHandle == popover) return;
+ if (submenu.popoverHandle != 0) {
+ /*
+ * Release the stale popover we previously cached (mirrors deregister()). Its
+ * SHOW/HIDE closures are deliberately left connected: GTK normally destroys the
+ * widget along with the model change, and should it survive, removeWidget() above
+ * means its handlers no longer resolve to a widget and simply no-op.
+ */
+ display.removeWidget(submenu.popoverHandle);
+ OS.g_object_unref(submenu.popoverHandle);
+ submenu.popoverHandle = 0;
+ }
+ OS.g_object_ref(popover);
+ submenu.popoverHandle = popover;
+ display.addWidget(popover, submenu);
+ OS.g_signal_connect_closure_by_id(popover, display.signalIds[SHOW], 0, display.getClosure(SHOW), false);
+ OS.g_signal_connect_closure_by_id(popover, display.signalIds[HIDE], 0, display.getClosure(HIDE), false);
+}
+
private void connectDropDownMenuSignals() {
if (items == null) return;
long barItem = GTK4.gtk_widget_get_first_child(handle);
@@ -878,17 +1031,13 @@ private void connectDropDownMenuSignals() {
for (MenuItem menuItem : items) {
if (barItem == 0) break;
if ((menuItem.style & SWT.SEPARATOR) != 0) continue;
- if (menuItem.menu != null && menuItem.menu.popoverHandle == 0) {
+ if (menuItem.menu != null) {
long popover = findGtkPopoverMenuChild(barItem);
- if (popover != 0) {
- OS.g_object_ref(popover);
- menuItem.menu.popoverHandle = popover;
- display.addWidget(popover, menuItem.menu);
- OS.g_signal_connect_closure_by_id(popover, display.signalIds[SHOW], 0, display.getClosure(SHOW), false);
- OS.g_signal_connect_closure_by_id(popover, display.signalIds[HIDE], 0, display.getClosure(HIDE), false);
- /*
- * Also connect SHOW/HIDE signals for nested CASCADE submenus.
- */
+ /* Re-wire when the discovered popover differs from the cache (initial or GTK rebuilt it). */
+ if (popover != 0 && menuItem.menu.popoverHandle != popover) {
+ wireSubMenuPopover(menuItem.menu, popover);
+ }
+ if (menuItem.menu.popoverHandle != 0) {
connectCascadeSubMenuSignals(menuItem.menu);
}
}
@@ -900,30 +1049,33 @@ private void connectCascadeSubMenuSignals(Menu menu) {
connectCascadeSubMenuSignals(menu, menu.popoverHandle);
}
+/**
+ * Connects SHOW/HIDE signals for the CASCADE submenus of the given menu. A
+ * submenu whose GtkPopoverMenu is not (yet) present is simply skipped; the next
+ * pass triggered by MAP, SHOW or "items-changed" picks it up.
+ */
private void connectCascadeSubMenuSignals(Menu menu, long parentPopoverHandle) {
if (menu == null || parentPopoverHandle == 0 || menu.items == null) return;
for (MenuItem item : menu.items) {
if ((item.style & SWT.CASCADE) != 0 && item.menu != null) {
- /*
- * item.menu is the CASCADE submenu (always SWT.DROP_DOWN style).
- * Its popoverHandle is 0 until we find and register its GtkPopoverMenu.
- * Skip if already connected (popoverHandle != 0).
- */
- if (item.menu.popoverHandle != 0) continue;
+ /* Re-discover every pass: a rebuild can make GTK replace the widget,
+ * leaving a stale handle whose SHOW never fires (submenu appears empty). */
long nestedPopover = findNestedPopoverForModel(parentPopoverHandle, item.menu.modelHandle);
if (nestedPopover != 0) {
- OS.g_object_ref(nestedPopover);
- item.menu.popoverHandle = nestedPopover;
- display.addWidget(nestedPopover, item.menu);
- OS.g_signal_connect_closure_by_id(nestedPopover, display.signalIds[SHOW], 0, display.getClosure(SHOW), false);
- OS.g_signal_connect_closure_by_id(nestedPopover, display.signalIds[HIDE], 0, display.getClosure(HIDE), false);
- // Recurse to handle further nested CASCADE submenus
+ if (item.menu.popoverHandle != nestedPopover) {
+ wireSubMenuPopover(item.menu, nestedPopover);
+ }
connectCascadeSubMenuSignals(item.menu);
}
}
}
}
+/**
+ * Recursively searches the widget subtree rooted at {@code parentWidget} for the
+ * nested GtkPopoverMenu whose GMenuModel is {@code targetModel}, returning its
+ * handle or {@code 0} if it is not (yet) present.
+ */
private long findNestedPopoverForModel(long parentWidget, long targetModel) {
if (parentWidget == 0 || targetModel == 0) return 0;
long child = GTK4.gtk_widget_get_first_child(parentWidget);
@@ -983,6 +1135,10 @@ long gtk_show (long widget) {
return 0;
}
sendEvent (SWT.Show);
+ /* Wire cascade submenu SHOW/HIDE signals once the DROP_DOWN popover is shown. */
+ if (GTK.GTK4 && (style & SWT.DROP_DOWN) != 0 && popoverHandle != 0) {
+ connectCascadeSubMenuSignals(this, popoverHandle);
+ }
if (OS.ubuntu_menu_proxy_get() != 0) {
MenuItem[] items = getItems();
for (int i=0; idetailed action name: actionId qualified with the prefix the
+ * action group was inserted under (see Menu#createHandle), plus a target for
+ * SWT.RADIO. Use this where an action is referenced by name, such as
+ * g_menu_item_new() or gtk_named_action_new(), and never with the GActionMap
+ * API.
+ */
String actionName;
/**
@@ -264,38 +277,63 @@ void createHandle(int index) {
case SWT.SEPARATOR:
modelHandle = OS.g_menu_new();
handle = OS.g_menu_item_new_section(null, modelHandle);
+ /*
+ * A separator starts a new section GMenu; observe it for
+ * "items-changed" too so submenus added into this section later get
+ * wired (see Menu#hookItemsChanged and issue #3451).
+ */
+ parent.hookItemsChanged(modelHandle);
break;
case SWT.RADIO:
long stringVariantType = OS.g_variant_type_new(OS.G_VARIANT_TYPE_STRING);
+ actionId = String.valueOf(this.hashCode());
actionHandle = OS.g_simple_action_new_stateful(
- Converter.javaStringToCString(String.valueOf(this.hashCode())),
+ Converter.javaStringToCString(actionId),
stringVariantType,
OS.g_variant_new_string(Converter.javaStringToCString("untoggled")));
OS.g_action_map_add_action(parent.actionGroup, actionHandle);
- actionName = String.valueOf(parent.hashCode()) + "." + String.valueOf(this.hashCode()) + "::toggled";
+ actionName = String.valueOf(parent.hashCode()) + "." + actionId + "::toggled";
handle = OS.g_menu_item_new(null, Converter.javaStringToCString(actionName));
OS.g_variant_type_free(stringVariantType);
break;
case SWT.CHECK:
long boolVariantType = OS.g_variant_type_new(OS.G_VARIANT_TYPE_BOOLEAN);
+ actionId = String.valueOf(this.hashCode());
actionHandle = OS.g_simple_action_new_stateful(
- Converter.javaStringToCString(String.valueOf(this.hashCode())),
+ Converter.javaStringToCString(actionId),
0,
OS.g_variant_new_boolean(false));
OS.g_action_map_add_action(parent.actionGroup, actionHandle);
- actionName = String.valueOf(parent.hashCode()) + "." + String.valueOf(this.hashCode());
+ actionName = String.valueOf(parent.hashCode()) + "." + actionId;
handle = OS.g_menu_item_new(null, Converter.javaStringToCString(actionName));
OS.g_variant_type_free(boolVariantType);
break;
case SWT.CASCADE:
modelHandle = OS.g_menu_new();
- handle = OS.g_menu_item_new_submenu(Converter.javaStringToCString(""), modelHandle);
+ /*
+ * Give the CASCADE item an action so it can be enabled/disabled like
+ * on the other platforms and like GTK3. A plain submenu item created
+ * via g_menu_item_new_submenu has no action, so its GtkModelButton is
+ * always sensitive: setEnabled(false) would be a no-op and the (possibly
+ * empty) submenu could still be opened. Attaching a SimpleAction makes
+ * the item follow the action's enabled state. While the action is
+ * enabled, activating the item still navigates into the submenu (the
+ * action is not triggered); while disabled, the item is insensitive and
+ * the submenu cannot be opened.
+ */
+ actionId = String.valueOf(this.hashCode());
+ actionHandle = OS.g_simple_action_new(Converter.javaStringToCString(actionId), 0);
+ OS.g_action_map_add_action(parent.actionGroup, actionHandle);
+ actionName = String.valueOf(parent.hashCode()) + "." + actionId;
+ handle = OS.g_menu_item_new(Converter.javaStringToCString(""), Converter.javaStringToCString(actionName));
+ OS.g_menu_item_set_submenu(handle, modelHandle);
break;
case SWT.PUSH:
default:
- actionHandle = OS.g_simple_action_new(Converter.javaStringToCString(String.valueOf(this.hashCode())), 0);
+ actionId = String.valueOf(this.hashCode());
+ actionHandle = OS.g_simple_action_new(Converter.javaStringToCString(actionId), 0);
OS.g_action_map_add_action(parent.actionGroup, actionHandle);
- actionName = String.valueOf(parent.hashCode()) + "." + String.valueOf(this.hashCode());
+ actionName = String.valueOf(parent.hashCode()) + "." + actionId;
handle = OS.g_menu_item_new(null, Converter.javaStringToCString(actionName));
break;
}
@@ -517,10 +555,6 @@ public boolean getEnabled () {
checkWidget();
if (GTK.GTK4) {
- if ((style & SWT.CASCADE) != 0) {
- return true;
- }
-
return OS.g_action_get_enabled(actionHandle);
} else {
return GTK.gtk_widget_get_sensitive(handle);
@@ -653,6 +687,10 @@ long gtk_activate (long widget) {
}
}
+ if (GTK.GTK4 && (style & SWT.CHECK) != 0) {
+ OS.g_simple_action_set_state(actionHandle, OS.g_variant_new_boolean(!getSelection()));
+ }
+
sendSelectionEvent (SWT.Selection);
return 0;
}
@@ -684,7 +722,7 @@ void hookEvents() {
super.hookEvents();
if (GTK.GTK4) {
- if ((style & SWT.PUSH) != 0 || (style & SWT.RADIO) != 0) {
+ if ((style & SWT.PUSH) != 0 || (style & SWT.RADIO) != 0 || (style & SWT.CHECK) != 0) {
OS.g_signal_connect(actionHandle, OS.activate, display.activateProc, handle);
}
} else {
@@ -739,7 +777,12 @@ void releaseWidget() {
super.releaseWidget();
if (GTK.GTK4) {
- if (parent.actionGroup != 0 && actionName != null) OS.g_action_map_remove_action(parent.actionGroup, Converter.javaStringToCString(actionName));
+ /*
+ * Remove by actionId, not actionName: GActionMap keys actions by their own
+ * name, so passing the prefixed detailed name silently removes nothing and
+ * leaks the action for the lifetime of the parent's action group.
+ */
+ if (parent.actionGroup != 0 && actionId != null) OS.g_action_map_remove_action(parent.actionGroup, Converter.javaStringToCString(actionId));
} else {
long accelGroup = getAccelGroup();
if (accelGroup != 0) removeAccelerator(accelGroup);
@@ -1144,6 +1187,18 @@ public void setMenu (Menu menu) {
OS.g_menu_remove(section.getSectionHandle(), section.getItemPosition(this));
OS.g_menu_insert_item(section.getSectionHandle(), section.getItemPosition(this), handle);
+
+ /*
+ * If a DROP_DOWN is attached while its parent is already mapped (contributions
+ * added/rebuilt after the parent was shown, e.g. workspace restore), wire its
+ * SHOW/HIDE now; otherwise SWT.Show never fires and the submenu appears empty
+ * (issue #3451). The g_menu calls above already emit "items-changed" on the
+ * section model, so this is normally redundant; go through modelItemsChanged()
+ * anyway so both paths re-wire from the same (root) menu.
+ */
+ if (menu != null) {
+ parent.modelItemsChanged();
+ }
} else {
long accelGroup = getAccelGroup ();
if (accelGroup != 0) removeAccelerators (accelGroup);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Spinner.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Spinner.java
index 95077da2d68..a83cea83c8c 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Spinner.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Spinner.java
@@ -717,7 +717,7 @@ long gtk_commit (long imContext, long text) {
@Override
long gtk_delete_text (long widget, long start_pos, long end_pos) {
if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return 0;
- long ptr = GTK3.gtk_entry_get_text (GTK.GTK4 ? entryHandle : handle);
+ long ptr = GTK.GTK4 ? GTK.gtk_entry_buffer_get_text (GTK4.gtk_text_get_buffer (entryHandle)) : GTK3.gtk_entry_get_text (handle);
if (end_pos == -1) end_pos = OS.g_utf8_strlen (ptr, -1);
int start = (int)OS.g_utf8_offset_to_utf16_offset (ptr, start_pos);
int end = (int)OS.g_utf8_offset_to_utf16_offset (ptr, end_pos);
@@ -761,7 +761,7 @@ long gtk_insert_text (long widget, long new_text, long new_text_length, long pos
String oldText = new String (Converter.mbcsToWcs (buffer));
int [] pos = new int [1];
C.memmove (pos, position, 4);
- long ptr = GTK3.gtk_entry_get_text (GTK.GTK4 ? entryHandle : handle);
+ long ptr = GTK.GTK4 ? GTK.gtk_entry_buffer_get_text (GTK4.gtk_text_get_buffer (entryHandle)) : GTK3.gtk_entry_get_text (handle);
if (pos [0] == -1) pos [0] = (int)OS.g_utf8_strlen (ptr, -1);
int start = (int)OS.g_utf16_pointer_to_offset (ptr, pos [0]);
String newText = verifyText (oldText, start, start);
@@ -1311,7 +1311,7 @@ String verifyText (String string, int start, int end) {
event.text = string;
event.start = start;
event.end = end;
- long eventPtr = GTK3.gtk_get_current_event ();
+ long eventPtr = GTK.GTK4 ? 0 : GTK3.gtk_get_current_event ();
if (eventPtr != 0) {
int type = GDK.gdk_event_get_event_type(eventPtr);
switch (type) {
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 f750fa7b97e..f75676a3650 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
@@ -711,6 +711,13 @@ void createHandle (int index) {
if (!searchEnabled ()) {
GTK.gtk_tree_view_set_search_column (handle, -1);
}
+ if (GTK.GTK4) {
+ // Required before TableDropTargetEffect may use
+ // gtk_tree_view_set_drag_dest_row(), see Tree.createHandle() for details.
+ long formats = GTK4.gdk_content_formats_builder_free_to_formats(GTK4.gdk_content_formats_builder_new());
+ GTK4.gtk_tree_view_enable_model_drag_dest(handle, formats, 0);
+ GTK4.gdk_content_formats_unref(formats);
+ }
}
void createItem (TableColumn column, int index) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Text.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Text.java
index c062b3b2271..c63599f53ff 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Text.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Text.java
@@ -1001,7 +1001,7 @@ public int getCaretPosition () {
checkWidget ();
int result;
if ((style & SWT.SINGLE) != 0) {
- long ptr = GTK3.gtk_entry_get_text (handle);
+ long ptr = GTK.GTK4 ? GTK.gtk_entry_buffer_get_text (bufferHandle) : GTK3.gtk_entry_get_text (handle);
result = (int)OS.g_utf8_offset_to_utf16_offset (ptr, GTK.gtk_editable_get_position (handle));
} else {
byte [] position = new byte [ITER_SIZEOF];
@@ -1697,7 +1697,7 @@ long gtk_delete_range (long widget, long iter1, long iter2) {
@Override
long gtk_delete_text (long widget, long start_pos, long end_pos) {
if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return 0;
- long ptr = GTK3.gtk_entry_get_text (handle);
+ long ptr = GTK.GTK4 ? GTK.gtk_entry_buffer_get_text (bufferHandle) : GTK3.gtk_entry_get_text (handle);
if (end_pos == -1) end_pos = OS.g_utf8_strlen (ptr, -1);
int start = (int)OS.g_utf8_offset_to_utf16_offset (ptr, start_pos);
int end = (int)OS.g_utf8_offset_to_utf16_offset (ptr, end_pos);
@@ -1812,7 +1812,7 @@ long gtk_insert_text (long widget, long new_text, long new_text_length, long pos
String oldText = new String (Converter.mbcsToWcs (buffer));
int [] pos = new int [1];
C.memmove (pos, position, 4);
- long ptr = GTK3.gtk_entry_get_text (handle);
+ long ptr = GTK.GTK4 ? GTK.gtk_entry_buffer_get_text (bufferHandle) : GTK3.gtk_entry_get_text (handle);
if (pos [0] == -1) pos [0] = (int)OS.g_utf8_strlen (ptr, -1);
/* Use the selection when the text was deleted */
int start = pos [0], end = pos [0];
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolBar.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolBar.java
index 4a9782a213c..b9b25b89605 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolBar.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolBar.java
@@ -309,8 +309,10 @@ public int getItemCount () {
int itemCount = 0;
if (GTK.GTK4) {
+ /* Must match _getItems(): a Menu's GtkPopover is also parented here
+ * as a native child and would otherwise count as a phantom item. */
for (long child = GTK4.gtk_widget_get_first_child(handle); child != 0; child = GTK4.gtk_widget_get_next_sibling(child)) {
- itemCount++;
+ if (display.getWidget(child) instanceof ToolItem) itemCount++;
}
} else {
long list = GTK3.gtk_container_get_children (handle);
@@ -348,8 +350,9 @@ ToolItem[] _getItems () {
ArrayList childrenList = new ArrayList<>();
for (long child = GTK4.gtk_widget_get_first_child(handle); child != 0; child = GTK4.gtk_widget_get_next_sibling(child)) {
Widget childWidget = display.getWidget(child);
- if (childWidget != null) {
- childrenList.add((ToolItem)childWidget);
+ /* A Menu's GtkPopover is also a native child here; skip non-ToolItems. */
+ if (childWidget instanceof ToolItem toolItem) {
+ childrenList.add(toolItem);
}
}
@@ -530,10 +533,12 @@ void relayout () {
}
}
- if (GTK.GTK4) {
- /* TODO: GTK4 no more GtkToolbar, we have to use a generic GtkBox
- * therefore we will need to implement these style ourselves. */
- } else {
+ /*
+ * GTK4 has no GtkToolbar and thus no gtk_toolbar_set_style(). There, each item
+ * shows or hides its image and its label as they are set, and arranges them
+ * according to SWT.RIGHT, see ToolItem#createHandle.
+ */
+ if (!GTK.GTK4) {
int type = GTK.GTK_TOOLBAR_ICONS;
if (hasText && hasImage) {
if ((style & SWT.RIGHT) != 0) {
@@ -601,8 +606,14 @@ int setBounds (int x, int y, int width, int height, boolean move, boolean resize
@Override
void setBackgroundGdkRGBA (long context, long handle, GdkRGBA rgba) {
+ /*
+ * On GTK4 the tool bar is a GtkBox carrying the "toolbar" style class, so its CSS
+ * node is named "box" and a plain "toolbar" selector never matches, leaving the
+ * tool bar with the theme background instead of the requested one.
+ */
+ String selector = GTK.GTK4 ? "box.toolbar" : "toolbar";
// Form background string
- String css = "toolbar {background-color: " + display.gtk_rgba_to_css_string(rgba) + ";}";
+ String css = selector + " {background-color: " + display.gtk_rgba_to_css_string(rgba) + ";}";
// Cache background color
this.cssBackground = css;
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 d02f04f91f5..5a48e8e72d7 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
@@ -51,6 +51,11 @@ public class ToolItem extends Item {
/** GTK4 only field, used to keep track of the containing box of the image & label */
long boxHandle, groupHandle;
+ /** GTK4 only field, used to keep track of the box wrapping the image, see {@link #createHandle} */
+ long imageBoxHandle;
+
+ /** GTK4 only, gap between the image and the text when SWT.RIGHT is set on the tool bar */
+ static final int TEXT_IMAGE_SPACING = 4;
ToolBar parent;
Control control;
@@ -206,6 +211,16 @@ void createHandle (int index) {
state |= HANDLE;
int bits = SWT.SEPARATOR | SWT.RADIO | SWT.CHECK | SWT.PUSH | SWT.DROP_DOWN;
+ /*
+ * On GTK3 the tool bar arranges image and text on its own, based on the style
+ * set with gtk_toolbar_set_style(). GTK4 has no GtkToolbar, so the arrangement
+ * is done here: SWT.RIGHT puts the text beside the image, otherwise it goes
+ * below the image.
+ */
+ boolean textBesideImage = (parent.style & SWT.RIGHT) != 0;
+ int boxOrientation = textBesideImage ? GTK.GTK_ORIENTATION_HORIZONTAL : GTK.GTK_ORIENTATION_VERTICAL;
+ int boxSpacing = textBesideImage ? TEXT_IMAGE_SPACING : 0;
+
switch (style & bits) {
case SWT.SEPARATOR:
if (GTK.GTK4) {
@@ -222,7 +237,7 @@ void createHandle (int index) {
handle = GTK.gtk_box_new(GTK.GTK_ORIENTATION_HORIZONTAL, 0);
if (handle == 0) error(SWT.ERROR_NO_HANDLES);
- boxHandle = GTK.gtk_box_new(GTK.GTK_ORIENTATION_VERTICAL, 0);
+ boxHandle = GTK.gtk_box_new(boxOrientation, boxSpacing);
if (boxHandle == 0) error(SWT.ERROR_NO_HANDLES);
long button = GTK.gtk_button_new();
@@ -265,7 +280,7 @@ void createHandle (int index) {
if (GTK.GTK4) {
handle = GTK.gtk_toggle_button_new();
if (handle == 0) error(SWT.ERROR_NO_HANDLES);
- boxHandle = GTK.gtk_box_new(GTK.GTK_ORIENTATION_VERTICAL, 0);
+ boxHandle = GTK.gtk_box_new(boxOrientation, boxSpacing);
if (boxHandle == 0) error(SWT.ERROR_NO_HANDLES);
GTK4.gtk_button_set_child(handle, boxHandle);
@@ -280,7 +295,7 @@ void createHandle (int index) {
if (GTK.GTK4) {
handle = GTK.gtk_button_new();
if (handle == 0) error(SWT.ERROR_NO_HANDLES);
- boxHandle = GTK.gtk_box_new(GTK.GTK_ORIENTATION_VERTICAL, 0);
+ boxHandle = GTK.gtk_box_new(boxOrientation, boxSpacing);
if (boxHandle == 0) error(SWT.ERROR_NO_HANDLES);
GTK4.gtk_button_set_child(handle, boxHandle);
@@ -303,12 +318,28 @@ void createHandle (int index) {
GTK.gtk_widget_set_halign(imageHandle, GTK.GTK_ALIGN_CENTER);
GTK.gtk_widget_set_valign(imageHandle, GTK.GTK_ALIGN_CENTER);
+ /*
+ * A GtkPicture scales its content to whatever size it is measured for,
+ * so a picture put directly into a vertical box is asked for a height
+ * matching the box's width, which is the width of the label below it.
+ * The image, and with it the whole tool bar, then grows as wide labels
+ * appear. Wrapping the picture in a box perpendicular to the item's box
+ * keeps it at the image's own size, because a box measured across its
+ * orientation never offers a child more than the child's natural size.
+ */
+ imageBoxHandle = GTK.gtk_box_new(boxOrientation == GTK.GTK_ORIENTATION_VERTICAL
+ ? GTK.GTK_ORIENTATION_HORIZONTAL : GTK.GTK_ORIENTATION_VERTICAL, 0);
+ if (imageBoxHandle == 0) error(SWT.ERROR_NO_HANDLES);
+ GTK.gtk_widget_set_halign(imageBoxHandle, GTK.GTK_ALIGN_CENTER);
+ GTK.gtk_widget_set_valign(imageBoxHandle, GTK.GTK_ALIGN_CENTER);
+ GTK4.gtk_box_append(imageBoxHandle, imageHandle);
+
GTK.gtk_widget_set_valign(boxHandle, GTK.GTK_ALIGN_CENTER);
- GTK4.gtk_box_append(boxHandle, imageHandle);
+ GTK4.gtk_box_append(boxHandle, imageBoxHandle);
GTK4.gtk_box_append(boxHandle, labelHandle);
- gtk_widget_hide(imageHandle);
+ gtk_widget_hide(imageBoxHandle);
gtk_widget_hide(labelHandle);
} else {
labelHandle = GTK.gtk_label_new_with_mnemonic(null);
@@ -910,6 +941,22 @@ int gtk_gesture_press_event(long gesture, int n_press, double x, double y, long
sendSelectionEvent(SWT.Selection, e, false);
return GTK4.GTK_EVENT_SEQUENCE_CLAIMED;
}
+ /*
+ * GTK4: Handle right-click (button 3) to fire SWT.MenuDetect on the parent
+ * ToolBar, replicating the GTK3 gtk3_event_after behavior. The gesture
+ * coordinates are item-local; translate them to the ToolBar's coordinate
+ * space and then to screen coordinates before calling parent.showMenu().
+ */
+ if (n_press == 1 && GTK.gtk_gesture_single_get_current_button(gesture) == 3) {
+ double[] destX = new double[1];
+ double[] destY = new double[1];
+ boolean translated = GTK4.gtk_widget_translate_coordinates(handle, parent.handle, x, y, destX, destY);
+ int barX = translated ? (int) destX[0] : (int) x;
+ int barY = translated ? (int) destY[0] : (int) y;
+ Point screenPt = parent.toDisplay(barX, barY);
+ parent.showMenu(screenPt.x, screenPt.y);
+ return GTK4.GTK_EVENT_SEQUENCE_CLAIMED;
+ }
return GTK4.GTK_EVENT_SEQUENCE_NONE;
}
@@ -949,8 +996,8 @@ void hookEvents () {
OS.g_signal_connect(motionController, OS.enter, display.enterMotionProc, ENTER);
OS.g_signal_connect(motionController, OS.leave, display.leaveProc, LEAVE);
- //TODO: event-after
long clickController = GTK4.gtk_gesture_click_new();
+ GTK.gtk_gesture_single_set_button(clickController, 0);
GTK4.gtk_widget_add_controller(handle, clickController);
OS.g_signal_connect(clickController, OS.pressed, display.gesturePressReleaseProc, GESTURE_PRESSED);
} else {
@@ -1048,7 +1095,7 @@ void register () {
@Override
void releaseHandle () {
super.releaseHandle ();
- arrowHandle = labelHandle = imageHandle = eventHandle = 0;
+ arrowHandle = labelHandle = imageHandle = imageBoxHandle = eventHandle = 0;
}
@Override
@@ -1378,7 +1425,7 @@ void _setImage (Image image) {
}
if (GTK.GTK4) {
- gtk_widget_show(imageHandle);
+ gtk_widget_show(imageBoxHandle);
long pixbuf = ImageList.createPixbuf(image);
long texture = GDK.gdk_texture_new_for_pixbuf(pixbuf);
OS.g_object_unref(pixbuf);
@@ -1398,7 +1445,7 @@ void _setImage (Image image) {
} else {
if(GTK.GTK4) {
GTK4.gtk_picture_set_paintable(imageHandle, 0);
- gtk_widget_hide(imageHandle);
+ gtk_widget_hide(imageBoxHandle);
} else {
GTK3.gtk_image_set_from_surface(imageHandle, 0);
}
@@ -1500,8 +1547,16 @@ public void setText (String string) {
byte [] buffer = Converter.wcsToMbcs (chars, true);
if (GTK.GTK4) {
- gtk_widget_show(labelHandle);
GTK.gtk_label_set_text_with_mnemonic(labelHandle, buffer);
+ /*
+ * An empty label still asks for the height of a line of text, which would
+ * keep the tool bar as tall as it was while the text was shown.
+ */
+ if (string.isEmpty()) {
+ gtk_widget_hide(labelHandle);
+ } else {
+ gtk_widget_show(labelHandle);
+ }
} else {
GTK.gtk_label_set_text_with_mnemonic(labelHandle, buffer);
}
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 ec7d5ab9c09..7fd132ed41c 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
@@ -881,7 +881,23 @@ void createHandle (int index) {
GTK.gtk_tree_view_set_search_column (handle, -1);
}
- if (GTK.GTK4) bindArrowKeyBindings();
+ if (GTK.GTK4) {
+ bindArrowKeyBindings();
+ /*
+ * GTK renders the drop highlight requested through
+ * gtk_tree_view_set_drag_dest_row() from the private TreeViewDragInfo struct,
+ * but only gtk_tree_view_enable_model_drag_dest() ever allocates it and the
+ * snapshot code dereferences it without a NULL check. Driving the highlight
+ * ourselves, as setInsertMark() and TreeDropTargetEffect do, would therefore
+ * crash on the next repaint, so allocate the struct up front. The drop target
+ * GTK installs alongside it gets an empty format list and no actions, which
+ * makes it reject every drag so that GTK's own tree view drag handlers never
+ * compete with SWT's DropTarget.
+ */
+ long formats = GTK4.gdk_content_formats_builder_free_to_formats(GTK4.gdk_content_formats_builder_new());
+ GTK4.gtk_tree_view_enable_model_drag_dest(handle, formats, 0);
+ GTK4.gdk_content_formats_unref(formats);
+ }
}
/**
@@ -2977,7 +2993,15 @@ public void removeAll () {
long selection = GTK.gtk_tree_view_get_selection (handle);
OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
- GTK.gtk_tree_store_clear (modelHandle);
+ // Disconnect the model from the view before clearing it.
+ // gtk_tree_store_clear fires cell-data / row-changed callbacks for every
+ // row it removes. Those callbacks re-enter SWT (cellDataProc -> checkData
+ // -> getParentItem -> gtk_tree_model_get_path) with iterators that are
+ // already being freed, causing a SIGSEGV. With no model attached the view
+ // has nothing to render, so no callbacks are fired during the clear.
+ GTK.gtk_tree_view_set_model (handle, 0);
+ GTK.gtk_tree_store_clear (modelHandle);
+ GTK.gtk_tree_view_set_model (handle, modelHandle);
OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
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 e6b99131a7b..525cf88296d 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
@@ -1250,11 +1250,15 @@ private Rectangle computeSourceRectangle(ImageHandle imageHandle, Rectangle full
* computed to pixels depending on the factor of the full image bounds to the
* actual OS handle size that will be used.
*/
- float scaleFactor = Math.min(1f * imageHandle.width() / fullImageBounds.width, 1f * imageHandle.height() / fullImageBounds.height);
- int closestZoomOfHandle = Math.round(scaleFactor * 100);
- Rectangle srcPixels = Win32DPIUtils.pointToPixel(drawable, src, closestZoomOfHandle);
-
- if (closestZoomOfHandle != 100) {
+ float scaleFactorX = (1f * imageHandle.width()) / fullImageBounds.width;
+ float scaleFactorY = (1f * imageHandle.height()) / fullImageBounds.height;
+ int srcXPixels = Math.round(scaleFactorX * src.x);
+ int srcWidthPixels = Math.round(scaleFactorX * (src.x + src.width)) - srcXPixels;
+ int srcYPixels = Math.round(scaleFactorY * src.y);
+ int srcHeightPixels = Math.round(scaleFactorY * (src.y + src.height)) - srcYPixels;
+ Rectangle srcPixels = new Rectangle(srcXPixels, srcYPixels, srcWidthPixels, srcHeightPixels);
+
+ if (Math.abs(scaleFactorX - 1f) >= 0.01f || Math.abs(scaleFactorY - 1f) >= 0.01f) {
/*
* This is a HACK! Due to rounding errors at fractional scale factors,
* the coordinates may be slightly off. The workaround is to restrict
@@ -1263,7 +1267,7 @@ private Rectangle computeSourceRectangle(ImageHandle imageHandle, Rectangle full
int errX = srcPixels.x + srcPixels.width - imageHandle.width();
int errY = srcPixels.y + srcPixels.height - imageHandle.height();
if (errX != 0 || errY != 0) {
- if (errX <= closestZoomOfHandle / 100 && errY <= closestZoomOfHandle / 100) {
+ if (errX <= Math.max(1, scaleFactorX) && errY <= Math.max(1, scaleFactorY)) {
srcPixels.intersect(new Rectangle(0, 0, imageHandle.width(), imageHandle.height()));
} else {
SWT.error (SWT.ERROR_INVALID_ARGUMENT);
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 12a78ed8464..098efadcb9d 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
@@ -18,6 +18,7 @@
import java.io.*;
import java.util.*;
+import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
@@ -29,6 +30,7 @@
import org.eclipse.swt.internal.gdip.*;
import org.eclipse.swt.internal.image.*;
import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.widgets.*;
/**
* Instances of this class are graphics which have been prepared
@@ -173,6 +175,15 @@ Set getAllZooms() {
return zoomLevelToImageHandle.keySet();
}
+ Integer getNearestAvailableZoom(int zoom) {
+ TreeSet availableZooms = new TreeSet<>(getAllZooms());
+ if (availableZooms.contains(zoom)) {
+ return zoom;
+ }
+ Integer higher = availableZooms.higher(zoom);
+ return higher != null ? higher : availableZooms.lower(zoom);
+ }
+
void destroyHandles(Predicate filter) {
zoomLevelToImageHandle.entrySet().removeIf(entry -> {
if (filter.test(entry.getKey())) {
@@ -201,28 +212,39 @@ public String toString() {
}
private class HandleAtSize {
+ record TemporaryHandleForZoom(DestroyableImageHandle handle, int zoom) {}
+
private InternalImageHandle handleContainer = null;
- private DestroyableImageHandle temporaryHandleContainer = null;
+ private TemporaryHandleForZoom temporaryHandleContainer = null;
private int requestedWidth = -1;
private int requestedHeight = -1;
public void destroy() {
- if (temporaryHandleContainer != null) {
- temporaryHandleContainer.destroy();
- temporaryHandleContainer = null;
+ TemporaryHandleForZoom previousHandle = reset();
+ if (previousHandle != null) {
+ previousHandle.handle().destroy();
}
+ }
+
+ private TemporaryHandleForZoom reset() {
+ TemporaryHandleForZoom previousHandle = temporaryHandleContainer;
+ temporaryHandleContainer = null;
handleContainer = null;
requestedWidth = -1;
requestedHeight = -1;
+ return previousHandle;
}
public ImageHandle refresh(int width, int height) {
if (!isReusable(width, height)) {
- destroy();
+ TemporaryHandleForZoom previousHandle = reset();
requestedWidth = width;
requestedHeight = height;
handleContainer = createHandleAtExactSize(width, height)
- .orElseGet(() -> getOrCreateImageHandleAtClosestSize(width, height));
+ .orElseGet(() -> getOrCreateImageHandleAtClosestSize(width, height, previousHandle));
+ if (previousHandle != null && previousHandle.handle() != handleContainer) {
+ previousHandle.handle().destroy();
+ }
}
return handleContainer;
}
@@ -238,23 +260,58 @@ private boolean isReusable(int width, int height) {
private Optional createHandleAtExactSize(int width, int height) {
Optional imageData = imageProvider.loadImageDataAtExactSize(width, height);
if (imageData.isPresent()) {
- temporaryHandleContainer = init(imageData.get(), -1);
- return Optional.of(temporaryHandleContainer);
+ temporaryHandleContainer = new TemporaryHandleForZoom(init(imageData.get(), -1), 0);
+ return Optional.of(temporaryHandleContainer.handle());
}
return Optional.empty();
}
- private InternalImageHandle getOrCreateImageHandleAtClosestSize(int widthHint, int heightHint) {
+ private InternalImageHandle getOrCreateImageHandleAtClosestSize(int widthHint, int heightHint, TemporaryHandleForZoom previousHandle) {
Rectangle bounds = getBounds(100);
int imageZoomForWidth = 100 * widthHint / bounds.width;
int imageZoomForHeight = 100 * heightHint / bounds.height;
int imageZoom = DPIUtil.getZoomForAutoscaleProperty(Math.max(imageZoomForWidth, imageZoomForHeight));
+ int nearestAvailableZoom = imageProvider.nearestAvailableZoom(imageZoom);
+ InternalImageHandle bestFittingHandle = getPersistentHandle(imageZoom, nearestAvailableZoom);
+ if (bestFittingHandle != null) {
+ return bestFittingHandle;
+ }
+ if (previousHandle != null && previousHandle.zoom() == nearestAvailableZoom) {
+ temporaryHandleContainer = previousHandle;
+ return previousHandle.handle();
+ }
+ ElementAtZoom imageData = imageProvider.loadImageData(imageZoom);
+ temporaryHandleContainer = new TemporaryHandleForZoom(init(imageData.element(), -1), imageData.zoom());
+ return temporaryHandleContainer.handle();
+ }
+
+ private InternalImageHandle getPersistentHandle(int imageZoom, int nearestAvailableZoom) {
InternalImageHandle bestFittingHandle = imageHandleManager.get(imageZoom);
- if (bestFittingHandle == null) {
- ImageData bestFittingImageData = imageProvider.loadImageData(imageZoom).element();
- bestFittingHandle = temporaryHandleContainer = init(bestFittingImageData, -1);
+ if (bestFittingHandle != null) {
+ return bestFittingHandle;
+ }
+ if (getShellZooms().contains(imageZoom)) {
+ return getHandleInternal(imageZoom, imageZoom);
+ }
+ bestFittingHandle = imageHandleManager.get(nearestAvailableZoom);
+ if (bestFittingHandle != null) {
+ return bestFittingHandle;
+ }
+ if (nearestAvailableZoom == 100) {
+ return getHandleInternal(100, 100);
}
- return bestFittingHandle;
+ return null;
+ }
+
+ private Set getShellZooms() {
+ if (getDevice() instanceof Display display) {
+ try {
+ return Arrays.stream(display.getShells()).map(Shell::getZoom).collect(Collectors.toSet());
+ } catch (SWTException e) {
+ return Collections.emptySet();
+ }
+ }
+ return Collections.emptySet();
}
}
@@ -957,6 +1014,10 @@ public static long win32_getHandle (Image image, int zoom) {
}
ImageHandle getHandle (int targetZoom, int nativeZoom) {
+ return getHandleInternal(targetZoom, nativeZoom);
+}
+
+InternalImageHandle getHandleInternal (int targetZoom, int nativeZoom) {
if (isDisposed()) {
return null;
}
@@ -2090,6 +2151,8 @@ protected boolean isPersistentImageHandleRequriedForImageData() {
return false;
}
+ abstract int nearestAvailableZoom(int zoom);
+
/**
* Returns image data at the best-fitting available zoom for the given zoom.
* The returned data will have a potential gray/disable style applied.
@@ -2101,8 +2164,7 @@ protected boolean isPersistentImageHandleRequriedForImageData() {
abstract AbstractImageProviderWrapper createCopy(Image image);
ElementAtZoom getClosestAvailableImageData(int zoom) {
- TreeSet availableZooms = new TreeSet<>(imageHandleManager.getAllZooms());
- int closestZoom = Optional.ofNullable(availableZooms.higher(zoom)).orElse(availableZooms.lower(zoom));
+ int closestZoom = imageHandleManager.getNearestAvailableZoom(zoom);
ImageData imageData = imageHandleManager.get(closestZoom).getImageData();
return new ElementAtZoom<>(imageData, closestZoom);
}
@@ -2179,6 +2241,11 @@ protected DestroyableImageHandle newImageHandle(ZoomContext zoomContext) {
ImageData resizedData = newImageData (zoomContext.targetZoom());
return newImageHandle(resizedData, zoomContext);
}
+
+ @Override
+ int nearestAvailableZoom(int zoom) {
+ return zoomForHandle;
+ }
}
private abstract class ImageFromImageDataProviderWrapper extends AbstractImageProviderWrapper {
@@ -2249,6 +2316,11 @@ protected ElementAtZoom loadImageData(int zoom) {
AbstractImageProviderWrapper createCopy(Image image) {
return image.new PlainImageDataProviderWrapper(this.imageDataAtBaseZoom);
}
+
+ @Override
+ int nearestAvailableZoom(int zoom) {
+ return baseZoom;
+ }
}
private class MaskedImageDataProviderWrapper extends ImageFromImageDataProviderWrapper {
@@ -2281,6 +2353,11 @@ protected ElementAtZoom loadImageData(int zoom) {
AbstractImageProviderWrapper createCopy(Image image) {
return image.new MaskedImageDataProviderWrapper(this.srcAt100, this.maskAt100);
}
+
+ @Override
+ int nearestAvailableZoom(int zoom) {
+ return 100;
+ }
}
private class ImageDataLoaderStreamProviderWrapper extends ImageFromImageDataProviderWrapper {
@@ -2325,6 +2402,14 @@ protected Optional loadImageDataAtExactSize(int targetWidth, int targ
}
return Optional.empty();
}
+
+ @Override
+ int nearestAvailableZoom(int zoom) {
+ if (ImageDataLoader.isDynamicallySizable(new ByteArrayInputStream(this.inputStreamData))) {
+ return zoom;
+ }
+ return FileFormat.DEFAULT_ZOOM;
+ }
}
private class PlainImageProviderWrapper extends AbstractImageProviderWrapper {
@@ -2388,6 +2473,14 @@ protected ElementAtZoom loadImageData(int zoom) {
return getClosestAvailableImageData(zoom);
}
+ @Override
+ int nearestAvailableZoom(int zoom) {
+ if (imageHandleManager.isEmpty()) {
+ return 100;
+ }
+ return imageHandleManager.getNearestAvailableZoom(zoom);
+ }
+
@Override
protected DestroyableImageHandle newImageHandle(ZoomContext zoomContext) {
int targetZoom = zoomContext.targetZoom();
@@ -2533,6 +2626,7 @@ private class ImageFileNameProviderWrapper extends BaseImageProviderWrapper loadImageData(int zoom) {
ElementAtZoom fileForZoom = DPIUtil.validateAndGetImagePathAtZoom(provider, zoom);
@@ -2564,6 +2658,14 @@ protected ElementAtZoom loadImageData(int zoom) {
return adaptImageDataIfDisabledOrGray(imageDataAtZoom);
}
+ @Override
+ int nearestAvailableZoom(int zoom) {
+ if (provider instanceof ImageDataAtSizeProvider) {
+ return zoom;
+ }
+ return DPIUtil.validateAndGetImagePathAtZoom(provider, zoom).zoom();
+ }
+
@Override
public int hashCode() {
return Objects.hash(provider, styleFlag);
@@ -2807,6 +2909,14 @@ protected Optional loadImageDataAtExactSize(int targetWidth, int targ
}
return Optional.empty();
}
+
+ @Override
+ int nearestAvailableZoom(int zoom) {
+ if (provider instanceof ImageDataAtSizeProvider) {
+ return zoom;
+ }
+ return DPIUtil.validateAndGetImageDataAtZoom (provider, zoom).zoom();
+ }
}
private class ImageGcDrawerWrapper extends DynamicImageProviderWrapper {
@@ -2848,6 +2958,11 @@ protected ElementAtZoom loadImageData(int zoom) {
return new ElementAtZoom<>(loadImageData(new ZoomContext(zoom)), zoom);
}
+ @Override
+ int nearestAvailableZoom(int zoom) {
+ return zoom;
+ }
+
private ImageData loadImageData(ZoomContext zoomContext) {
currentZoom = zoomContext;
int targetZoom = zoomContext.targetZoom();
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 05658442854..c32726acb1b 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
@@ -394,14 +394,6 @@ public void put (int index, Image image) {
images [index] = image;
}
-public void remove (int index) {
- int count = OS.ImageList_GetImageCount (handle);
- if (!(0 <= index && index < count)) return;
- zoomToHandle.values().forEach(handle -> OS.ImageList_Remove (handle, index));
- System.arraycopy (images, index + 1, images, index, --count - index);
- images [index] = null;
-}
-
public int removeRef() {
return --refCount;
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java
index 75b22c3c684..91189e8b012 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java
@@ -7124,15 +7124,13 @@ LRESULT wmNotifyToolTip (NMHDR hdr, long wParam, long lParam) {
LRESULT result = super.wmNotify (hdr, wParam, lParam);
if (result != null) return result;
if (toolTipText != null) break;
- result = positionTooltip(hdr, lParam);
- return result;
+ return positionTooltip(hdr, lParam) ? LRESULT.ONE : null;
}
}
return null;
}
-private LRESULT positionTooltip(NMHDR hdr, long lParam) {
- LRESULT result = null;
+private boolean positionTooltip(NMHDR hdr, long lParam) {
LVHITTESTINFO pinfo = new LVHITTESTINFO ();
int pos = OS.GetMessagePos ();
POINT pt = new POINT();
@@ -7161,9 +7159,11 @@ private LRESULT positionTooltip(NMHDR hdr, long lParam) {
long hwndToolTip = OS.SendMessage(handle, OS.LVM_GETTOOLTIPS, 0, 0);
int flags = OS.SWP_NOACTIVATE | OS.SWP_NOZORDER;
Rectangle adjustedTooltipBounds = getDisplay().fitRectangleBoundsIntoMonitorWithCursor(toolRect);
- OS.SetWindowPos(hwndToolTip, 0, adjustedTooltipBounds.x, adjustedTooltipBounds.y,
- adjustedTooltipBounds.width, adjustedTooltipBounds.height, flags);
- result = LRESULT.ONE;
+ if (adjustedTooltipBounds != null) {
+ OS.SetWindowPos(hwndToolTip, 0, adjustedTooltipBounds.x, adjustedTooltipBounds.y,
+ adjustedTooltipBounds.width, adjustedTooltipBounds.height, flags);
+ return true;
+ }
} else if (isCustomToolTip()) {
RECT itemRect = getItemBounds(pinfo, item, hDC);
NMTTDISPINFO lpnmtdi = new NMTTDISPINFO();
@@ -7183,7 +7183,7 @@ private LRESULT positionTooltip(NMHDR hdr, long lParam) {
string.getChars (0, string.length (), chars, 0);
shell.setToolTipText (lpnmtdi, chars);
OS.MoveMemory (lParam, lpnmtdi, NMTTDISPINFO.sizeof);
- result = LRESULT.ONE;
+ return true;
}
}
}
@@ -7191,7 +7191,7 @@ private LRESULT positionTooltip(NMHDR hdr, long lParam) {
if (newFont != 0) OS.SelectObject (hDC, oldFont);
OS.ReleaseDC (handle, hDC);
}
- return result;
+ return false;
}
private RECT getItemBounds(LVHITTESTINFO pinfo, TableItem item, long hDC) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java
index 6e523eef5b3..68e839fcefe 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java
@@ -1712,8 +1712,6 @@ record ToolItemData(ToolItem toolItem, TBBUTTON button) {
// Remove and re-add all button the let Windows resize the tool bar
Stack buttondata = new Stack<>();
for (int i = itemCount - 1; i >= 0; i--) {
- TBBUTTON lpButton = new TBBUTTON ();
- OS.SendMessage (handle, OS.TB_GETBUTTON, i, lpButton);
ToolItem item = toolItems[i];
if ((item.style & SWT.SEPARATOR) != 0 && item.getControl() != null) {
// Take note of widths of separators with control, so they can be resized
@@ -1721,6 +1719,13 @@ record ToolItemData(ToolItem toolItem, TBBUTTON button) {
seperatorWidth[i] = item.getWidth();
}
item.notifyListeners(SWT.ZoomChanged, event);
+ // Capture the button data AFTER handling the zoom change. The zoom refresh
+ // may update the item's image-list slot (iBitmap), so capturing the button
+ // beforehand could re-add it with a stale image index, resulting in the
+ // wrong (or a blank) icon being shown. Reading the button here ensures the
+ // current, post-refresh image index is preserved.
+ TBBUTTON lpButton = new TBBUTTON ();
+ OS.SendMessage (handle, OS.TB_GETBUTTON, i, lpButton);
buttondata.push(new ToolItemData(item, lpButton));
OS.SendMessage(handle, OS.TB_DELETEBUTTON, i, 0);
}
@@ -1738,6 +1743,11 @@ record ToolItemData(ToolItem toolItem, TBBUTTON button) {
}
}
}
+ // Refresh the image lists so the image list for the correct zoom is used
+ setImageList(getImageList());
+ setDisabledImageList(getDisabledImageList());
+ setHotImageList(getHotImageList());
+ boolean toolBarEnabled = getEnabled();
for (int i = 0; i < itemCount; i++) {
ToolItem item = toolItems[i];
// If the separator is used with a control, we must reset the size to the cached value,
@@ -1745,12 +1755,9 @@ record ToolItemData(ToolItem toolItem, TBBUTTON button) {
if ((item.style & SWT.SEPARATOR) != 0 && item.getControl() != null) {
item.setWidth(seperatorWidth[i]);
}
+ // Make sure the tool item is resized with the new image and font size
+ toolItems[i].updateImages(toolItems[i].getEnabled() && toolBarEnabled);
}
-
- // Refresh the image lists so the image list for the correct zoom is used
- setImageList(getImageList());
- setDisabledImageList(getDisabledImageList());
- setHotImageList(getHotImageList());
OS.SendMessage(handle, OS.TB_AUTOSIZE, 0, 0);
clearSizeCache(true);
}
diff --git a/examples/org.eclipse.swt.examples/META-INF/MANIFEST.MF b/examples/org.eclipse.swt.examples/META-INF/MANIFEST.MF
index b7b9968fa3f..c078217c52e 100644
--- a/examples/org.eclipse.swt.examples/META-INF/MANIFEST.MF
+++ b/examples/org.eclipse.swt.examples/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin.SWTStandaloneExampleSet.name
Bundle-SymbolicName: org.eclipse.swt.examples; singleton:=true
-Bundle-Version: 3.109.100.qualifier
+Bundle-Version: 3.109.200.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-21
diff --git a/examples/org.eclipse.swt.examples/src/examples_control.properties b/examples/org.eclipse.swt.examples/src/examples_control.properties
index 54bc35f9c0d..ad7f2ef4442 100644
--- a/examples/org.eclipse.swt.examples/src/examples_control.properties
+++ b/examples/org.eclipse.swt.examples/src/examples_control.properties
@@ -232,6 +232,7 @@ Set_Min_Visible = Minimize
Set_Max_Visible = Maximize
Set_Unselected_Close_Visible = Close on Unselected Tabs
Set_Unselected_Image_Visible = Image on Unselected Tabs
+Set_MRU_Active = Activate MRU
Selection_Foreground_Color = Selection Foreground Color
Selection_Background_Color = Selection Background Color
Item_Foreground_Color = Item Foreground Color
diff --git a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/controlexample/CTabFolderTab.java b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/controlexample/CTabFolderTab.java
index 728f988c7d4..74b7450e906 100644
--- a/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/controlexample/CTabFolderTab.java
+++ b/examples/org.eclipse.swt.examples/src/org/eclipse/swt/examples/controlexample/CTabFolderTab.java
@@ -63,7 +63,7 @@ class CTabFolderTab extends Tab {
/* Other widgets added to the "Other" group */
Button singleTabButton, imageButton, showMinButton, showMaxButton,
- topRightButton, unselectedCloseButton, unselectedImageButton;
+ topRightButton, unselectedCloseButton, unselectedImageButton, activateMRUButton;
ToolBar topRightControl;
@@ -233,6 +233,12 @@ void createOtherGroup () {
unselectedCloseButton.setText (ControlExample.getResourceString("Set_Unselected_Close_Visible"));
unselectedCloseButton.setSelection(true);
unselectedCloseButton.addSelectionListener (widgetSelectedAdapter(event -> setUnselectedCloseVisible()));
+
+ activateMRUButton = new Button (otherGroup, SWT.CHECK);
+ activateMRUButton.setText (ControlExample.getResourceString("Set_MRU_Active"));
+ activateMRUButton.setSelection(false);
+ activateMRUButton.addSelectionListener (widgetSelectedAdapter(event -> setMRUActive()));
+
}
/**
@@ -412,6 +418,7 @@ void setExampleWidgetState () {
setImages();
setMinimizeVisible();
setMaximizeVisible();
+ setMRUActive();
setUnselectedCloseVisible();
setUnselectedImageVisible();
setSelectionBackground ();
@@ -458,6 +465,13 @@ void setMaximizeVisible () {
tabFolder1.setMaximizeVisible(showMaxButton.getSelection ());
setExampleWidgetSize();
}
+ /**
+ * Activates/deactivates the MRU setting
+ */
+ void setMRUActive () {
+ tabFolder1.setMRUVisible(activateMRUButton.getSelection ());
+ setExampleWidgetSize();
+ }
/**
* Sets the top right control to a toolbar
*/
diff --git a/features/org.eclipse.swt.tools.feature/feature.xml b/features/org.eclipse.swt.tools.feature/feature.xml
index e931cf31d75..bbd29d9849f 100644
--- a/features/org.eclipse.swt.tools.feature/feature.xml
+++ b/features/org.eclipse.swt.tools.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Issue3329_TreeCrashBug.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Issue3329_TreeCrashBug.java
new file mode 100644
index 00000000000..4668816fec8
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Issue3329_TreeCrashBug.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2026 Andrey Loskutov 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:
+ * Andrey Loskutov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+/**
+ * Manual reproducer for the Tree.removeAll() crash on Linux GTK with
+ * SWT.VIRTUAL trees.
+ *
+ * STEPS TO REPRODUCE: 1. Run this snippet. 2. Expand any root item so its
+ * children become visible (this creates Java TreeItem objects with GTK iters
+ * backed by live GNodes). 3. Click GO.
+ *
+ * EXPECTED: Tree content refreshes cleanly. ACTUAL: SIGSEGV inside
+ * gtk_tree_model_get_path (libgtk-3.so.0).
+ *
+ * ROOT CAUSE (mirrors the original JFace crash test provided in the ticket):
+ *
+ * Tree.removeAll() calls gtk_tree_store_clear(). GTK fires cellDataProc
+ * synchronously for rows that become visible as the cursor moves during
+ * deletion. For an UNCACHED root item (never rendered, so no ID column value in
+ * the model), Tree._getItem() calls getId() which calls gtk_tree_store_set() to
+ * assign the ID. That gtk_tree_store_set fires a synchronous "row-changed"
+ * signal which re-enters cellDataProc a second time for the same row. The inner
+ * cellDataProc finds the item still uncached and calls checkData() ->
+ * sendEvent(SWT.SetData).
+ *
+ * At this point gtk_tree_store_clear has already removed (and freed the GNodes
+ * of) the earlier root items and their children. The Java TreeItem objects for
+ * those freed rows are still alive (release() is called after
+ * gtk_tree_store_clear returns), but their handle field contains a GtkTreeIter
+ * whose user_data pointer is now dangling.
+ *
+ * JFace's SetData handler calls viewer.replace() which calls
+ * internalFindItems() -> getTreePathFromItem() -> getParentItem() on every
+ * existing TreeItem widget. Calling getParentItem() on any item whose GTK row
+ * has been freed passes the stale GtkTreeIter to gtk_tree_model_get_path(),
+ * which dereferences the freed GNode -> SIGSEGV at si_addr=0x17 (null-like
+ * offset into freed memory).
+ *
+ * This reproducer replicates that by explicitly calling getParentItem() on the
+ * previously-collected child items (same as getTreePathFromItem does) inside
+ * the SetData listener that fires during gtk_tree_store_clear.
+ */
+public class Issue3329_TreeCrashBug {
+
+ private static final int ROOT_COUNT = 40;
+ private static final int CHILD_COUNT = 60;
+
+ public static void main(String[] args) {
+ var display = new Display();
+ var shell = new Shell(display);
+ shell.setLayout(new GridLayout());
+
+ var button = new Button(shell, SWT.PUSH);
+ button.setText("GO"); //$NON-NLS-1$
+
+ var tree = new Tree(shell, SWT.VIRTUAL | SWT.BORDER);
+ tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ // Collect every child TreeItem as it is rendered during v1 population.
+ // These objects hold GTK iters (GtkTreeIter.user_data -> GNode).
+ // After removeAll() frees those GNodes the handles become dangling.
+ List prevChildren = new ArrayList<>();
+
+ tree.addListener(SWT.SetData, e -> {
+ TreeItem item = (TreeItem) e.item;
+ TreeItem parent = item.getParentItem();
+ if (parent == null) {
+ item.setText("v1_" + e.index); //$NON-NLS-1$
+ item.setItemCount(CHILD_COUNT);
+ } else {
+ item.setText(parent.getText() + "_" + e.index); //$NON-NLS-1$
+ prevChildren.add(item); // remember this child — its GNode will be freed on removeAll()
+ }
+ });
+
+ tree.setItemCount(ROOT_COUNT);
+
+ // GO button: replace the tree content with a new version.
+ // Crashes if at least one root was expanded (prevChildren is non-empty)
+ // AND there are uncached roots below the visible viewport.
+ button.addListener(SWT.Selection, e -> {
+ for (var l : tree.getListeners(SWT.SetData)) {
+ tree.removeListener(SWT.SetData, l);
+ }
+
+ // New SetData listener registered BEFORE removeAll().
+ // It fires re-entrantly from inside gtk_tree_store_clear (via the
+ // cellDataProc -> getId -> gtk_tree_store_set -> row-changed -> cellDataProc
+ // -> checkData -> SetData chain described in the root-cause comment above).
+ //
+ // At the time it fires, the earlier roots and their children have
+ // already been removed; prevChildren[i].handle contains a freed GNode.
+ // Calling getParentItem() on those items passes the stale GtkTreeIter
+ // to gtk_tree_model_get_path() -> SIGSEGV.
+ //
+ // This mirrors AbstractTreeViewer.getTreePathFromItem() which walks all
+ // existing TreeItem widgets via getParentItem() inside internalFindItems().
+ tree.addListener(SWT.SetData, ev -> {
+ for (TreeItem child : prevChildren) {
+ // child is NOT disposed yet (release() happens after gtk_tree_store_clear),
+ // but child.handle is a stale GtkTreeIter with a freed GNode pointer.
+ if (!child.isDisposed()) {
+ child.getParentItem(); // <-- SIGSEGV on production GTK3
+ // G_DISABLE_CHECKS)
+ }
+ }
+ TreeItem item = (TreeItem) ev.item;
+ TreeItem parent = item.getParentItem();
+ if (parent == null) {
+ item.setText("v2_" + ev.index); //$NON-NLS-1$
+ item.setItemCount(CHILD_COUNT);
+ } else {
+ item.setText(parent.getText() + "_" + ev.index); //$NON-NLS-1$
+ }
+ });
+
+ tree.removeAll(); // triggers the crash
+ tree.setItemCount(ROOT_COUNT);
+ });
+
+ shell.setSize(300, 250); // small window -> more uncached (out-of-viewport) roots
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+}
\ No newline at end of file
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java
index ffef5ae21e7..651f6d0fd2d 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java
@@ -3045,6 +3045,79 @@ public void test_BrowserFunction_availableOnLoad_concurrentInstances_issue20() {
assertTrue(browser2FuncAvailable.get(), "BrowserFunction for second browser missing when page load completed");
}
+/**
+ * Regression test: a disposed BrowserFunction must no longer be available (re-injected) after a
+ * subsequent navigation. This verifies that deregistration removes the persistent document-created
+ * script (whose ID is captured asynchronously on the Edge backend).
+ */
+@Test
+public void test_BrowserFunction_disposedFunctionRemovedAfterNavigation() {
+ BrowserFunction function = new BrowserFunction(browser, "disposableFunc") {
+ @Override
+ public Object function(Object[] arguments) {
+ return "alive";
+ }
+ };
+
+ AtomicBoolean firstPageLoaded = new AtomicBoolean(false);
+ ProgressListener firstPageListener = completedAdapter(e -> firstPageLoaded.set(true));
+ browser.addProgressListener(firstPageListener);
+ browser.setText("first page");
+ shell.open();
+ assertTrue(waitForPassCondition(firstPageLoaded::get), "First page did not load");
+ // The function is registered and usable now (this also ensures its registration has settled).
+ assertEquals("alive", browser.evaluate("return disposableFunc();"));
+ browser.removeProgressListener(firstPageListener);
+
+ // Dispose the function, then navigate: it must be gone on the new page.
+ function.dispose();
+ AtomicBoolean secondPageLoaded = new AtomicBoolean(false);
+ browser.addProgressListener(completedAdapter(e -> secondPageLoaded.set(true)));
+ browser.setText("second page");
+ assertTrue(waitForPassCondition(secondPageLoaded::get), "Second page did not load");
+
+ Object stillDefined = browser.evaluate("return typeof disposableFunc === 'function';");
+ assertEquals(Boolean.FALSE, stillDefined,
+ "A disposed BrowserFunction must not be re-injected on a subsequently loaded page");
+}
+
+/**
+ * Regression test: redefining a BrowserFunction with the same name (which deregisters the previous
+ * one and registers the new one) must take effect and survive navigations - the newest definition
+ * wins and the previous one is not resurrected.
+ */
+@Test
+public void test_BrowserFunction_redefineSameNameSurvivesNavigation() {
+ new BrowserFunction(browser, "f") {
+ @Override
+ public Object function(Object[] arguments) {
+ return "v1";
+ }
+ };
+ new BrowserFunction(browser, "f") {
+ @Override
+ public Object function(Object[] arguments) {
+ return "v2";
+ }
+ };
+
+ AtomicBoolean firstPageLoaded = new AtomicBoolean(false);
+ ProgressListener firstPageListener = completedAdapter(e -> firstPageLoaded.set(true));
+ browser.addProgressListener(firstPageListener);
+ browser.setText("first page");
+ shell.open();
+ assertTrue(waitForPassCondition(firstPageLoaded::get), "First page did not load");
+ assertEquals("v2", browser.evaluate("return f();"), "The most recent definition of 'f' must win");
+ browser.removeProgressListener(firstPageListener);
+
+ AtomicBoolean secondPageLoaded = new AtomicBoolean(false);
+ browser.addProgressListener(completedAdapter(e -> secondPageLoaded.set(true)));
+ browser.setText("second page");
+ assertTrue(waitForPassCondition(secondPageLoaded::get), "Second page did not load");
+ assertEquals("v2", browser.evaluate("return f();"),
+ "The redefined BrowserFunction must survive navigation and the previous definition must not be resurrected");
+}
+
@Test
@Disabled("Too fragile on CI, Display.getDefault().post(event) does not work reliably")
public void test_TabTraversalOutOfBrowser() {
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabFolder.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabFolder.java
index ac61c9e2984..d0a0bafa065 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabFolder.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabFolder.java
@@ -44,8 +44,11 @@
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.internal.DPIUtil;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
@@ -54,6 +57,7 @@
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
@@ -69,6 +73,7 @@
*
* @see org.eclipse.swt.custom.CTabFolder
*/
+@SuppressWarnings("restriction")
public class Test_org_eclipse_swt_custom_CTabFolder extends Test_org_eclipse_swt_widgets_Composite {
@Override
@@ -522,6 +527,51 @@ public void test_topRightWrapOverflow() {
+ "topRight.y=" + topRightBounds.y + " tab.bottom=" + (tabBounds.y + tabBounds.height));
}
+/**
+ * A tab control is rescaled after the folder itself, so the folder must recompute
+ * its tab height once a tab control reports a zoom change. Test for issue 3456.
+ */
+@Test
+public void test_tabHeightRecomputedOnTabControlZoomChange() {
+ makeCleanEnvironment();
+ shell.setSize(800, 400);
+
+ CTabItem item = new CTabItem(ctabFolder, SWT.NONE);
+ item.setText("Tab 1");
+ ctabFolder.setSelection(0);
+
+ int topRightHeight = 20;
+ Composite topRight = new Composite(ctabFolder, SWT.NONE);
+ FixedSizeLayout topRightLayout = new FixedSizeLayout(60, topRightHeight);
+ topRight.setLayout(topRightLayout);
+ ctabFolder.setTopRight(topRight, SWT.RIGHT | SWT.WRAP);
+
+ SwtTestUtil.openShell(shell);
+ processEvents();
+
+ int defaultTabHeight = ctabFolder.getTabHeight();
+
+ // A taller tab control makes the folder grow its tab height
+ topRightLayout.height = defaultTabHeight * 3;
+ ctabFolder.setTabHeight(SWT.DEFAULT);
+ processEvents();
+ int grownTabHeight = ctabFolder.getTabHeight();
+ assertTrue(grownTabHeight > defaultTabHeight, "tab height should grow with the tab control");
+
+ // Shrinking the tab control alone leaves the tab height stale, which is the state
+ // the folder ends up in after measuring a control that was not yet rescaled
+ topRightLayout.height = topRightHeight;
+ assertEquals(grownTabHeight, ctabFolder.getTabHeight(), "precondition: tab height is stale");
+
+ Event zoomChanged = new Event();
+ zoomChanged.detail = DPIUtil.getDeviceZoom();
+ topRight.notifyListeners(SWT.ZoomChanged, zoomChanged);
+ processEvents();
+
+ assertEquals(defaultTabHeight, ctabFolder.getTabHeight(),
+ "tab height should be recomputed after a zoom change of a tab control");
+}
+
/**
* Min/max and chevron icon can appear below tab row.
* Test for bug 499215, 533582.
@@ -1050,6 +1100,61 @@ public void test_dirtyIndicator_closesWhenCloseEnabled() {
}
}
+/**
+ * All tabs are painted with the same GC, so the dirty indicator must not leave it in
+ * advanced graphics mode.
+ */
+@Test
+public void test_dirtyIndicator_doesNotChangeAdvancedGraphicsMode() {
+ makeCleanEnvironment(SWT.CLOSE);
+ shell.setLayout(new FillLayout());
+
+ for (int i = 0; i < 2; i++) {
+ CTabItem item = new CTabItem(ctabFolder, SWT.NONE);
+ item.setText("Tab " + i);
+ }
+ ctabFolder.setDirtyIndicatorStyle(true);
+ // the dirty item is painted before the selected one, which is painted last
+ ctabFolder.getItem(0).setShowDirty(true);
+ ctabFolder.setSelection(1);
+ shell.setSize(800, 400);
+ SwtTestUtil.openShell(shell);
+ processEvents();
+
+ assertTrue(getCloseRect(ctabFolder.getItem(0)).width > 0, "dirty indicator is not laid out");
+
+ // paint into an image so that the test does not depend on the display sending paint events
+ Rectangle bounds = ctabFolder.getBounds();
+ Image image = new Image(shell.getDisplay(), bounds.width, bounds.height);
+ GC gc = new GC(image);
+ try {
+ boolean advancedBefore = gc.getAdvanced();
+
+ Event paint = new Event();
+ paint.gc = gc;
+ paint.width = bounds.width;
+ paint.height = bounds.height;
+ ctabFolder.notifyListeners(SWT.Paint, paint);
+
+ assertEquals(advancedBefore, gc.getAdvanced(),
+ "Painting the dirty indicator must not change the advanced graphics mode of the GC");
+ } finally {
+ gc.dispose();
+ image.dispose();
+ }
+}
+
+private static Rectangle getCloseRect(CTabItem item) {
+ try {
+ Field closeRect = CTabItem.class.getDeclaredField("closeRect");
+ closeRect.setAccessible(true);
+ return (Rectangle) closeRect.get(item);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ fail("Failed to access closeRect via reflection: " + e.getMessage());
+ return null;
+ }
+}
+
@Test
public void test_moveItem_forward() {
createTabFolder(null, 5);
@@ -1117,4 +1222,24 @@ public void test_moveItem_errorCases() {
"out-of-range to index must be rejected");
}
+/** Layout with a preferred size the test can change at will. */
+private static final class FixedSizeLayout extends Layout {
+ int width;
+ int height;
+
+ FixedSizeLayout(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
+ return new Point(wHint == SWT.DEFAULT ? width : wHint, hHint == SWT.DEFAULT ? height : hHint);
+ }
+
+ @Override
+ protected void layout(Composite composite, boolean flushCache) {
+ }
+}
+
}
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java
index 29b2292b5ab..5d7449c8e36 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java
@@ -382,6 +382,20 @@ public void test_drawImageLorg_eclipse_swt_graphics_ImageIIIIIIII() {
images.dispose();
}
+/**
+ * See https://github.com/eclipse-platform/eclipse.platform.swt/issues/3442
+ */
+@Test
+public void test_drawImage_emptyImage() {
+ Image emptyImage = new Image(display, IMAGE_SIZE, IMAGE_SIZE);
+ try {
+ gc.drawImage(emptyImage, 0, 0, IMAGE_SIZE, IMAGE_SIZE, 0, 0, IMAGE_SIZE / 3, IMAGE_SIZE / 3);
+ ImageDataTestHelper.assertImageDataEqual(image.getImageData(), emptyImage.getImageData(), image.getImageData());
+ } finally {
+ emptyImage.dispose();
+ }
+}
+
@Test
public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII() {
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Region.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Region.java
index 8fa5e15f5a2..9efe1153ba1 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Region.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Region.java
@@ -14,6 +14,7 @@
*******************************************************************************/
package org.eclipse.swt.tests.junit;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import org.eclipse.swt.SWTException;
@@ -57,25 +58,12 @@ public void test_ConstructorLorg_eclipse_swt_graphics_Device() {
@Test
public void test_add$I() {
- Region reg = new Region(display);
- try {
- reg.add((int[])null);
- reg.dispose();
- fail("no exception thrown for adding a null rectangle");
- }
- catch (IllegalArgumentException e) {
- }
- reg.dispose();
- try {
- reg.add(new int[]{});
- reg.dispose();
- fail("no exception thrown on disposed region");
- }
- catch (SWTException e) {
- }
- reg.dispose();
+ Region emptyRegion = new Region(display);
+ assertThrows(IllegalArgumentException.class, () -> emptyRegion.add((int[]) null), "no exception thrown for adding a null rectangle");
+ emptyRegion.dispose();
+ assertThrows(SWTException.class, () -> emptyRegion.add(new int[]{}), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
reg.add(new int[] {0,0, 50,0, 50,25, 0,25});
Rectangle box = reg.getBounds();
reg.dispose();
@@ -112,21 +100,11 @@ public void test_addLorg_eclipse_swt_graphics_Rectangle() {
// add a second rectangle
reg.add(new Rectangle(200, 200, 10,10));
- try {
- reg.add((Rectangle)null);
- fail("no exception thrown for adding a null rectangle");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> reg.add((Rectangle)null), "no exception thrown for adding a null rectangle");
reg.dispose();
- try {
- reg.add(new Rectangle(20,30,10,5));
- fail("no exception thrown for adding a rectangle after Region got disposed");
- }
- catch (SWTException e) {
- }
+ assertThrows(SWTException.class, () -> reg.add(new Rectangle(20,30,10,5)), "no exception thrown for adding a rectangle after Region got disposed");
}
@Test
@@ -138,34 +116,21 @@ public void test_addLorg_eclipse_swt_graphics_Region() {
reg1.add(reg2);
reg2.dispose();
- try {
- reg1.add((Region)null);
- fail("no exception thrown for adding a null region");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> reg1.add((Region)null), "no exception thrown for adding a null region");
- try {
- reg2 = new Region(display);
- reg2.add(new Rectangle(1,1,100,200));
- reg2.dispose();
- reg1.add(reg2);
- fail("no exception thrown for adding to a Region a Region which got disposed");
- }
- catch (IllegalArgumentException e) {
- }
+ Region disposedRegion = new Region(display);
+ disposedRegion.add(new Rectangle(1,1,100,200));
+ disposedRegion.dispose();
+ assertThrows(IllegalArgumentException.class, () -> reg1.add(disposedRegion), "no exception thrown for adding to a Region a Region which got disposed");
reg1.dispose();
+ Region liveRegion = new Region(display);
try {
- reg2 = new Region(display);
- reg2.add(new Rectangle(1,1,100,200));
- reg1.add(reg2);
- fail("no exception thrown for adding a Region to a Region which got disposed");
- }
- catch (SWTException e) {
+ liveRegion.add(new Rectangle(1,1,100,200));
+ assertThrows(SWTException.class, () -> reg1.add(liveRegion), "no exception thrown for adding a Region to a Region which got disposed");
} finally {
- if (reg2 != null) reg2.dispose();
+ liveRegion.dispose();
}
}
@@ -177,16 +142,11 @@ public void test_containsII() {
Point pointInRect2 = new Point(1049,1009);
Point pointNotInRect12 = new Point(49,110);
- Region reg = new Region(display);
- reg.dispose();
- try {
- reg.contains(pointInRect1.x, pointInRect1.y);
- fail("no exception thrown on disposed region");
- }
- catch (Exception e) {
- }
+ Region disposedRegion = new Region(display);
+ disposedRegion.dispose();
+ assertThrows(Exception.class, () -> disposedRegion.contains(pointInRect1.x, pointInRect1.y), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
if (reg.contains(pointInRect1.x, pointInRect1.y)) {
reg.dispose();
fail("Empty region should not contain point");
@@ -217,16 +177,11 @@ public void test_containsLorg_eclipse_swt_graphics_Point() {
Point pointInRect2 = new Point(1049,1009);
Point pointNotInRect12 = new Point(49,110);
- Region reg = new Region(display);
- reg.dispose();
- try {
- reg.contains(pointInRect1);
- fail("no exception thrown on disposed region");
- }
- catch (Exception e) {
- }
+ Region disposedRegion = new Region(display);
+ disposedRegion.dispose();
+ assertThrows(Exception.class, () -> disposedRegion.contains(pointInRect1), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
if (reg.contains(pointInRect1)) {
reg.dispose();
fail("Empty region should not contain point");
@@ -315,22 +270,17 @@ public void test_equalsLjava_lang_Object() {
@Test
public void test_getBounds() {
- Region reg = new Region(display);
- reg.dispose();
+ Region disposedRegion = new Region(display);
+ disposedRegion.dispose();
- try {
- reg.getBounds();
- fail("Region disposed should throw Exception");
- }
- catch (Exception e) {
- }
+ assertThrows(Exception.class, () -> disposedRegion.getBounds(), "Region disposed should throw Exception");
Rectangle rect1 = new Rectangle(10,10,50,30);
Rectangle rect2 = new Rectangle(100,100,10,10);
// the rectangle enclosing the two preceding rectangles
Rectangle rect12Bounds = new Rectangle(10,10,100,100);
- reg = new Region(display);
+ Region reg = new Region(display);
reg.add(rect1);
Rectangle rect1Bis = reg.getBounds();
if (rect1Bis.x != rect1.x || rect1Bis.y != rect1.y ||
@@ -391,16 +341,11 @@ public void test_intersectLorg_eclipse_swt_graphics_Rectangle() {
Rectangle rect4 = new Rectangle(48,24,10,10);
Rectangle rect5 = new Rectangle(24,20,24,10);
- Region reg = new Region(display);
- reg.dispose();
- try {
- reg.intersect(rect1);
- fail("no exception thrown on disposed region");
- }
- catch (SWTException e) {
- }
+ Region disposedRegion = new Region(display);
+ disposedRegion.dispose();
+ assertThrows(SWTException.class, () -> disposedRegion.intersect(rect1), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
reg.intersect(rect1);
if (!reg.isEmpty()) {
reg.dispose();
@@ -447,20 +392,14 @@ public void test_intersectLorg_eclipse_swt_graphics_Rectangle() {
@Test
public void test_intersectLorg_eclipse_swt_graphics_Region() {
- Region reg = new Region(display);
Region reg1 = new Region(display);
reg1.add(new Rectangle(0,0,48,24));
- reg.dispose();
- try {
- reg.intersect(reg1);
- reg1.dispose();
- fail("no exception thrown on disposed region");
- }
- catch (SWTException e) {
- }
+ Region disposedRegion = new Region(display);
+ disposedRegion.dispose();
+ assertThrows(SWTException.class, () -> disposedRegion.intersect(reg1), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
reg.intersect(reg1);
if (!reg.isEmpty()) {
reg.dispose();
@@ -548,16 +487,11 @@ public void test_intersectsIIII() {
Rectangle rectNotInter12 = new Rectangle(40,50,5,15);
- Region reg = new Region(display);
- reg.dispose();
- try {
- reg.intersects(rectInter1.x, rectInter1.y, rectInter1.width, rectInter1.height);
- fail("no exception thrown on disposed region");
- }
- catch (Exception e) {
- }
+ Region disposedRegion = new Region(display);
+ disposedRegion.dispose();
+ assertThrows(Exception.class, () -> disposedRegion.intersects(rectInter1.x, rectInter1.y, rectInter1.width, rectInter1.height), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
if (reg.intersects(rect1.x, rect1.y, rect1.width, rect1.height)) {
reg.dispose();
fail("intersects can't return true on empty region");
@@ -603,16 +537,11 @@ public void test_intersectsLorg_eclipse_swt_graphics_Rectangle() {
Rectangle rectNotInter12 = new Rectangle(40,50,5,15);
- Region reg = new Region(display);
- reg.dispose();
- try {
- reg.intersects(rectInter1);
- fail("no exception thrown on disposed region");
- }
- catch (Exception e) {
- }
+ Region disposedRegion = new Region(display);
+ disposedRegion.dispose();
+ assertThrows(Exception.class, () -> disposedRegion.intersects(rectInter1), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
if (reg.intersects(rect1)) {
reg.dispose();
fail("intersects can't return true on empty region");
@@ -682,25 +611,12 @@ public void test_isEmpty() {
@Test
public void test_subtract$I() {
- Region reg = new Region(display);
- try {
- reg.subtract((int[])null);
- reg.dispose();
- fail("no exception thrown for subtract a null array");
- }
- catch (IllegalArgumentException e) {
- }
- reg.dispose();
- try {
- reg.subtract(new int[]{});
- reg.dispose();
- fail("no exception thrown on disposed region");
- }
- catch (SWTException e) {
- }
- reg.dispose();
+ Region emptyRegion = new Region(display);
+ assertThrows(IllegalArgumentException.class, () -> emptyRegion.subtract((int[]) null), "no exception thrown for subtract a null array");
+ emptyRegion.dispose();
+ assertThrows(SWTException.class, () -> emptyRegion.subtract(new int[]{}), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
reg.add(new int[] {0,0, 50,0, 50,25, 0,25});
reg.subtract(new int[] {0,0, 50,0, 50,20, 0,20});
Rectangle box = reg.getBounds();
@@ -731,16 +647,11 @@ public void test_subtractLorg_eclipse_swt_graphics_Rectangle() {
Rectangle rect4 = new Rectangle(50,25,10,10);
Rectangle rect5 = new Rectangle(0,0,60,20);
- Region reg = new Region(display);
- reg.dispose();
- try {
- reg.subtract(rect1);
- fail("no exception thrown on disposed region");
- }
- catch (SWTException e) {
- }
+ Region disposedRegion = new Region(display);
+ disposedRegion.dispose();
+ assertThrows(SWTException.class, () -> disposedRegion.subtract(rect1), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
reg.subtract(rect1);
if (!reg.isEmpty()) {
reg.dispose();
@@ -791,17 +702,11 @@ public void test_subtractLorg_eclipse_swt_graphics_Region() {
Region reg1 = new Region(display);
reg1.add(new Rectangle(0,0,50,25));
- Region reg = new Region(display);
- reg.dispose();
- try {
- reg.subtract(reg1);
- reg1.dispose();
- fail("no exception thrown on disposed region");
- }
- catch (SWTException e) {
- }
+ Region disposedRegion = new Region(display);
+ disposedRegion.dispose();
+ assertThrows(SWTException.class, () -> disposedRegion.subtract(reg1), "no exception thrown on disposed region");
- reg = new Region(display);
+ Region reg = new Region(display);
reg.subtract(reg1);
if (!reg.isEmpty()) {
reg.dispose();
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Button.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Button.java
index df252704b57..4c38c6e7da2 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Button.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Button.java
@@ -17,8 +17,8 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
@@ -75,12 +75,7 @@ public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
new Button(shell, SWT.PUSH | SWT.CHECK);
- try {
- new Button(null, 0);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new Button(null, 0), "No exception thrown for parent == null");
}
@Test
@@ -96,21 +91,13 @@ public void widgetDefaultSelected(SelectionEvent e) {
}
};
- try {
- button.addSelectionListener(null);
- fail("No exception thrown for addSelectionListener with null argument");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> button.addSelectionListener(null), "No exception thrown for addSelectionListener with null argument");
button.addSelectionListener(listener);
button.notifyListeners(SWT.Selection, new Event());
assertTrue(listenerCalled);
- try {
- button.removeSelectionListener(null);
- fail("No exception thrown for removeSelectionListener with null argument");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> button.removeSelectionListener(null), "No exception thrown for removeSelectionListener with null argument");
listenerCalled = false;
button.removeSelectionListener(listener);
button.notifyListeners(SWT.Selection, new Event());
@@ -362,26 +349,21 @@ public void test_setForegroundAlphaRadiokButton() {
@Test
public void test_setImageLorg_eclipse_swt_graphics_Image() {
- Image image = button.getImage();
- button.setImage(image);
- assertEquals(image, button.getImage());
+ Image initialImage = button.getImage();
+ button.setImage(initialImage);
+ assertEquals(initialImage, button.getImage());
button.setImage(null);
assertNull(button.getImage());
ImageGcDrawer noOpGcDrawer = (gc, width, height) -> {};
- image = new Image(shell.getDisplay(), noOpGcDrawer, 10, 10);
+ Image image = new Image(shell.getDisplay(), noOpGcDrawer, 10, 10);
button.setImage(image);
assertEquals(image, button.getImage());
button.setImage(null);
image.dispose();
- try {
- button.setImage(image);
- button.setImage(null);
- fail("No exception thrown for disposed image");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> button.setImage(image), "No exception thrown for disposed image");
}
@Test
@@ -435,12 +417,7 @@ public void test_setTextLjava_lang_String() {
assertEquals(cases[i], button.getText());
}
- try {
- button.setText(null);
- fail("No exception thrown for text == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> button.setText(null), "No exception thrown for text == null");
button.setText("");
}
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Canvas.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Canvas.java
index aa9c89e4e18..6a349cf77c4 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Canvas.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Canvas.java
@@ -16,7 +16,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
@@ -55,12 +55,7 @@ protected void setWidget(Widget w) {
@Override
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
- try {
- new Canvas(null, SWT.NONE);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new Canvas(null, SWT.NONE), "No exception thrown for parent == null");
}
@Test
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Combo.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Combo.java
index 7b977c2eddc..89851719cb5 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Combo.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Combo.java
@@ -20,7 +20,6 @@
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.util.concurrent.atomic.AtomicInteger;
@@ -1061,12 +1060,7 @@ public void test_consistency_Segments () {
}
listenerCalled = true;
};
- try {
- combo.addSegmentListener(null);
- fail("No exception thrown for addSegmentListener(null)");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> combo.addSegmentListener(null), "No exception thrown for addSegmentListener(null)");
combo.addSegmentListener(sl1);
doSegmentsTest(true);
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Composite.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Composite.java
index 927748e2b6b..093f37095ee 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Composite.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Composite.java
@@ -15,8 +15,8 @@
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import java.util.concurrent.atomic.AtomicReference;
@@ -55,12 +55,7 @@ public void setUp() {
@Override
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
- try {
- composite = new Composite(null, 0);
- fail("No exception thrown");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new Composite(null, 0), "No exception thrown for parent == null");
int[] cases = {SWT.H_SCROLL, SWT.V_SCROLL, SWT.H_SCROLL | SWT.V_SCROLL};
for (int style : cases)
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_CoolItem.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_CoolItem.java
index cf8cf4416b4..45ed52e9017 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_CoolItem.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_CoolItem.java
@@ -16,8 +16,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
@@ -51,30 +51,15 @@ public void test_ConstructorLorg_eclipse_swt_widgets_CoolBarI() {
CoolBar coolBar = new CoolBar(shell, 0);
new CoolItem(coolBar, 0);
- try {
- new CoolItem(null, 0);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new CoolItem(null, 0), "No exception thrown for parent == null");
}
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_CoolBarII() {
CoolBar coolBar = new CoolBar(shell, 0);
CoolItem coolItem = new CoolItem(coolBar, 0, 0);
- try {
- coolItem = new CoolItem(coolBar, 0, -1);
- fail("No exception thrown for index == -1");
- }
- catch (IllegalArgumentException e){
- }
- try {
- coolItem = new CoolItem(coolBar, 0, 2);
- fail("No exception thrown for index == 2");
- }
- catch (IllegalArgumentException e){
- }
+ assertThrows(IllegalArgumentException.class, () -> new CoolItem(coolBar, 0, -1), "No exception thrown for index == -1");
+ assertThrows(IllegalArgumentException.class, () -> new CoolItem(coolBar, 0, 2), "No exception thrown for index == 2");
assertEquals(1, coolBar.getItemCount());
coolItem = new CoolItem(coolBar, 0, 1);
assertEquals(2, coolBar.getItemCount());
@@ -198,22 +183,12 @@ public void test_setControlLorg_eclipse_swt_widgets_Control() {
assertEquals(size2, coolItem.getSize());
}
- button = new Button(coolBar, SWT.PUSH);
- button.dispose();
- try {
- coolItem.setControl(button);
- fail("No exception when control.isDisposed()");
- }
- catch (IllegalArgumentException e) {
- }
+ Button disposedButton = new Button(coolBar, SWT.PUSH);
+ disposedButton.dispose();
+ assertThrows(IllegalArgumentException.class, () -> coolItem.setControl(disposedButton), "No exception when control.isDisposed()");
- button = new Button(shell, SWT.PUSH);
- try {
- coolItem.setControl(button);
- fail("No exception thrown when control has wrong parent");
- }
- catch (IllegalArgumentException e) {
- }
+ Button wrongParentButton = new Button(shell, SWT.PUSH);
+ assertThrows(IllegalArgumentException.class, () -> coolItem.setControl(wrongParentButton), "No exception thrown when control has wrong parent");
}
@Test
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_ExpandBar.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_ExpandBar.java
index 9a25249c42c..dbb676b1da3 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_ExpandBar.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_ExpandBar.java
@@ -18,7 +18,6 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import java.util.ArrayList;
import java.util.List;
@@ -132,12 +131,7 @@ public void test_addExpandListenerItemExpandedAdapterLorg_eclipse_swt_events_Exp
@Override
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
- try {
- new ExpandBar(null, 0);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new ExpandBar(null, 0), "No exception thrown for parent == null");
}
@Test
@@ -161,17 +155,11 @@ public void test_getItemI() {
}
expandBar = new ExpandBar(shell, 0);
- number = 5;
items = new ExpandItem[number];
for (int i = 0; i expandBar.getItem(number), "No exception thrown for illegal index argument");
}
@Test
@@ -209,12 +197,7 @@ public void test_indexOfLorg_eclipse_swt_widgets_ExpandItem() {
items[i] = new ExpandItem(expandBar, 0);
}
for (int i = 0; i < number; i++) {
- try {
- expandBar.indexOf(null);
- fail("No exception thrown for expandItem == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> expandBar.indexOf(null), "No exception thrown for expandItem == null");
}
}
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_ExpandItem.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_ExpandItem.java
index 8b6f23925fa..25afe1d849c 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_ExpandItem.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_ExpandItem.java
@@ -15,8 +15,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
@@ -44,12 +44,7 @@ public void setUp() {
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_ExpandItemI() {
- try {
- new ExpandItem(null, SWT.NULL);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new ExpandItem(null, SWT.NULL), "No exception thrown for parent == null");
}
@Test
@@ -88,22 +83,12 @@ public void test_setControlLorg_eclipse_swt_widgets_Control() {
Button button = new Button(expandBar, SWT.PUSH);
expandItem.setControl(button);
- button = new Button(expandBar, SWT.PUSH);
- button.dispose();
- try {
- expandItem.setControl(button);
- fail("No exception when control.isDisposed()");
- }
- catch (IllegalArgumentException e) {
- }
-
- button = new Button(shell, SWT.PUSH);
- try {
- expandItem.setControl(button);
- fail("No exception thrown when control has wrong parent");
- }
- catch (IllegalArgumentException e) {
- }
+ Button disposedButton = new Button(expandBar, SWT.PUSH);
+ disposedButton.dispose();
+ assertThrows(IllegalArgumentException.class, () -> expandItem.setControl(disposedButton), "No exception when control.isDisposed()");
+
+ Button wrongParentButton = new Button(shell, SWT.PUSH);
+ assertThrows(IllegalArgumentException.class, () -> expandItem.setControl(wrongParentButton), "No exception thrown when control has wrong parent");
}
@Test
@@ -138,11 +123,7 @@ public void test_setImageLorg_eclipse_swt_graphics_Image() {
public void test_setTextLjava_lang_String() {
expandItem.setText("ABCDEFG");
assertEquals("ABCDEFG", expandItem.getText());
- try {
- expandItem.setText(null);
- fail("No exception thrown for addArmListener with null argument");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> expandItem.setText(null), "No exception thrown for addArmListener with null argument");
expandItem.setText("ABCDEFG");
assertTrue(expandItem.getText().startsWith("ABCDEFG"));
}
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_List.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_List.java
index baae135621e..ea137af58c6 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_List.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_List.java
@@ -18,7 +18,6 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
@@ -50,11 +49,7 @@ public void setUp() {
@Override
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
- try {
- list = new List(null, 0);
- fail("No exception thrown"); //should never get here
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new List(null, 0), "No exception thrown for parent == null");
int[] cases =
{
@@ -70,11 +65,7 @@ public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
@Test
public void test_addLjava_lang_String() {
- try {
- list.add(null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.add(null), "No exception thrown");
list.add("");
assertArrayEquals(new String[] {""}, list.getItems());
list.add("some \n text");
@@ -86,11 +77,7 @@ public void test_addLjava_lang_String() {
setSingleList();
- try {
- list.add(null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.add(null), "No exception thrown");
list.add("");
assertArrayEquals(new String[] {""}, list.getItems());
@@ -102,11 +89,7 @@ public void test_addLjava_lang_String() {
@Test
public void test_addLjava_lang_StringI() {
- try {
- list.add("some text", 2);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.add("some text", 2), "No exception thrown");
assertEquals(0, list.getItemCount());
list.add("", 0);
@@ -116,27 +99,15 @@ public void test_addLjava_lang_StringI() {
list.add("some text", 0);
assertArrayEquals(new String[] {"some text", "", "some \n text" }, list.getItems());
- try {
- list.add(null, 0);
- fail("No exception thrown string == null");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.add(null, 0), "No exception thrown string == null");
- try {
- list.add("string", -1);
- fail("No exception thrown index < 0");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.add("string", -1), "No exception thrown index < 0");
// test single-selection list
setSingleList();
- try {
- list.add("some text", 2);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.add("some text", 2), "No exception thrown");
assertEquals(0, list.getItemCount());
@@ -147,17 +118,9 @@ public void test_addLjava_lang_StringI() {
list.add("some text", 0);
assertArrayEquals(new String[] {"some text", "", "some \n text" }, list.getItems());
- try {
- list.add(null, 0);
- fail("No exception thrown string == null");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.add(null, 0), "No exception thrown string == null");
- try {
- list.add("string", -1);
- fail("No exception thrown index < 0");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.add("string", -1), "No exception thrown index < 0");
}
@Test
@@ -226,11 +189,7 @@ public void test_computeSizeIIZ() {
list.setItems(items);
list.setSelection(items);
assertArrayEquals(list.getSelection(), items);
- try {
- list.deselect(null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.deselect(null), "No exception thrown");
assertArrayEquals(list.getSelection(), items);
list.deselect(new int[] {
});
@@ -250,11 +209,7 @@ public void test_computeSizeIIZ() {
list.setItems(items);
list.setSelection(new String[] { "item3" });
assertArrayEquals(list.getSelection(), new String[] { "item3" });
- try {
- list.deselect(null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.deselect(null), "No exception thrown");
assertArrayEquals(list.getSelection(), new String[] { "item3" });
list.deselect(new int[] {});
@@ -481,34 +436,18 @@ public void test_getItemHeight() {
public void test_getItemI() {
String[] items = { "item0", "item1", "item2", "item3" };
list.setItems(items);
- try {
- list.getItem(5);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.getItem(5), "No exception thrown");
- try {
- list.getItem(-1);
- fail("No exception thrown for index < 0");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.getItem(-1), "No exception thrown for index < 0");
assertEquals(list.getItem(3), "item3");
setSingleList();
list.setItems(items);
- try {
- list.getItem(5);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.getItem(5), "No exception thrown");
- try {
- list.getItem(-1);
- fail("No exception thrown for index < 0");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.getItem(-1), "No exception thrown for index < 0");
//assert(":a:", list.getItem(5)==null);
assertEquals("item3", list.getItem(3));
@@ -615,11 +554,7 @@ public void test_getSelectionCount() {
assertEquals(3, list.getSelectionCount());
list.deselectAll();
- try {
- list.setSelection((String[]) null);
- fail("No exception thrown for selection == null");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setSelection((String[]) null), "No exception thrown for selection == null");
assertEquals(list.getSelectionCount(), 0);
@@ -748,11 +683,7 @@ public void test_indexOfLjava_lang_String() {
assertEquals(list.indexOf("text3"), 2);
assertEquals(list.indexOf("text4"), -1);
- try {
- list.indexOf(null);
- fail("No exception thrown for item == null");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.indexOf(null), "No exception thrown for item == null");
String[] items2 = { "text1", "text2", "text2" }; //two identical
@@ -772,11 +703,7 @@ public void test_indexOfLjava_lang_String() {
assertEquals(-1, list.indexOf("text4"));
- try {
- list.indexOf(null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.indexOf(null), "No exception thrown");
assertEquals(1, list.indexOf("text2"));
@@ -797,11 +724,7 @@ public void test_indexOfLjava_lang_StringI() {
list.setItems(items2);
assertEquals(list.indexOf("text2", 2), 2);
- try {
- list.indexOf(null, 0);
- fail("No exception thrown for string == null");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.indexOf(null, 0), "No exception thrown for string == null");
setSingleList();
@@ -811,11 +734,7 @@ public void test_indexOfLjava_lang_StringI() {
assertEquals(1, list.indexOf("text2", 1));
assertEquals(2, list.indexOf("text2", 2));
- try {
- list.indexOf(null, 0);
- fail("No exception thrown for string == null");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.indexOf(null, 0), "No exception thrown for string == null");
}
@Test
@@ -845,11 +764,7 @@ public void test_isSelectedI() {
@Test
public void test_remove$I() {
- try {
- list.remove((int[]) null);
- fail("No exception thrown for indices == null");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove((int[]) null), "No exception thrown for indices == null");
String[] items = { "text0", "text1", "text2", "text3" };
@@ -863,35 +778,19 @@ public void test_isSelectedI() {
list.setItems(items);
// index > number of elements in list
- try {
- list.remove(new int[] { 4, 1});
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(new int[] { 4, 1}), "No exception thrown");
assertArrayEquals(list.getItems(), items);
- try {
- list.remove(new int[] { 3, 1, -1 });
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(new int[] { 3, 1, -1 }), "No exception thrown");
assertArrayEquals(list.getItems(), items);
list.setItems(items);
assertEquals(list.getItemCount(), 4);
- try {
- list.remove(new int[] { -1, -1 });
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(new int[] { -1, -1 }), "No exception thrown");
assertArrayEquals(list.getItems(), items);
- try {
- list.remove(new int[] { -2, -1 });
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(new int[] { -2, -1 }), "No exception thrown");
assertArrayEquals(list.getItems(), items);
list.setItems(items);
@@ -909,12 +808,7 @@ public void test_isSelectedI() {
setSingleList();
- try {
- int[] indices = null;
- list.remove(indices);
- fail("No exception thrown for indices == null");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove((int[]) null), "No exception thrown for indices == null");
list.setItems(items);
assertEquals(4, list.getItemCount());
@@ -934,29 +828,17 @@ public void test_isSelectedI() {
assertEquals(4, list.getItemCount());
// index > number of elements in list
- try {
- list.remove(new int[] { 4, 1});
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(new int[] { 4, 1}), "No exception thrown");
assertArrayEquals(list.getItems(), items);
- try {
- list.remove(new int[] { 3, 1, -1 });
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(new int[] { 3, 1, -1 }), "No exception thrown");
assertArrayEquals(list.getItems(), items);
list.setItems(items);
assertEquals(4, list.getItemCount());
- try {
- list.remove(new int[] { -1, -1 });
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(new int[] { -1, -1 }), "No exception thrown");
assertArrayEquals(items, list.getItems());
@@ -1003,18 +885,10 @@ public void test_removeI() {
list.setItems(items);
assertEquals(list.getItemCount(), 3);
- try {
- list.remove(3);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3), "No exception thrown");
assertEquals(list.getItemCount(), 3);
- try {
- list.remove(-1);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(-1), "No exception thrown");
assertEquals(list.getItemCount(), 3);
list.remove(1);
@@ -1024,19 +898,11 @@ public void test_removeI() {
list.setItems(items);
assertEquals(list.getItemCount(), 3);
- try {
- list.remove(3, 4);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3, 4), "No exception thrown");
assertEquals(list.getItemCount(), 3);
- try {
- list.remove(3, 3);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3, 3), "No exception thrown");
assertEquals(list.getItemCount(), 3);
@@ -1057,18 +923,10 @@ public void test_removeI() {
setSingleList();
list.setItems(items);
assertEquals(3, list.getItemCount());
- try {
- list.remove(3);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3), "No exception thrown");
assertEquals(3, list.getItemCount());
/////////////////////////////////////////////////
- try {
- list.remove(-1);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(-1), "No exception thrown");
assertEquals(3, list.getItemCount());
////////////////////////////////////////////////
@@ -1097,19 +955,11 @@ public void test_removeII() {
list.setItems(items);
assertEquals(3, list.getItemCount());
- try {
- list.remove(3, 4);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3, 4), "No exception thrown");
assertEquals(3, list.getItemCount());
- try {
- list.remove(3, 3);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3, 3), "No exception thrown");
assertEquals(3, list.getItemCount());
list.remove(0, 0);
@@ -1119,18 +969,10 @@ public void test_removeII() {
list.setItems(items);
assertEquals(3, list.getItemCount());
- try {
- list.remove(-1, 1);
- fail("No exception thrown for start index < 0");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(-1, 1), "No exception thrown for start index < 0");
assertEquals(3, list.getItemCount());
- try {
- list.remove(3, 4);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3, 4), "No exception thrown");
assertEquals(3, list.getItemCount());
list.remove(0, 2);
@@ -1139,11 +981,7 @@ public void test_removeII() {
list.setItems(items);
assertEquals(3, list.getItemCount());
- try {
- list.remove(3, 3);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3, 3), "No exception thrown");
assertEquals(3, list.getItemCount());
list.remove(2, 0);
@@ -1155,28 +993,16 @@ public void test_removeII() {
list.setItems(items);
assertEquals(3, list.getItemCount());
//////////////////////////////////////////////////////////////
- try {
- list.remove(3, 4);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3, 4), "No exception thrown");
assertEquals(3, list.getItemCount());
/////////////////////////////////////////////////////////
- try {
- list.remove(3, 3);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(3, 3), "No exception thrown");
assertEquals(3, list.getItemCount());
//////////////////////////////////////////////////////////////
- try {
- list.remove(-1, 1);
- fail("No exception thrown for start index < 0");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(-1, 1), "No exception thrown for start index < 0");
assertEquals(3, list.getItemCount());
list.remove(1, 2);
@@ -1187,11 +1013,7 @@ public void test_removeII() {
list.setItems(items);
assertEquals(3, list.getItemCount());
- try {
- list.remove(2, 10);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove(2, 10), "No exception thrown");
assertEquals(3, list.getItemCount());
assertEquals("text2", list.getItem(1));
@@ -1206,18 +1028,10 @@ public void test_removeLjava_lang_String() {
list.setItems(items);
assertEquals(list.getItemCount(), 4);
- try {
- list.remove((String) null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove((String) null), "No exception thrown");
assertEquals(list.getItemCount(), 4);
- try {
- list.remove("items989");
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove("items989"), "No exception thrown");
assertEquals(list.getItemCount(), 4);
list.setItems(items);
@@ -1234,18 +1048,10 @@ public void test_removeLjava_lang_String() {
list.setItems(items);
assertEquals(4, list.getItemCount());
- try {
- list.remove((String) null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove((String) null), "No exception thrown");
assertEquals(4, list.getItemCount());
////////////////////////////////////////
- try {
- list.remove("items989");
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.remove("items989"), "No exception thrown");
assertEquals(4, list.getItemCount());
@@ -1261,11 +1067,7 @@ public void test_removeLjava_lang_String() {
@Test
public void test_select$I() {
- try {
- list.select((int[]) null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.select((int[]) null), "No exception thrown");
String[] items = { "item0", "item1", "item2", "item3" };
list.setItems(items);
@@ -1317,11 +1119,7 @@ public void test_removeLjava_lang_String() {
setSingleList();
list.setItems(items);
- try {
- list.select((int[]) null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.select((int[]) null), "No exception thrown");
list.select(new int[]{ -1 });
assertArrayEquals(list.getSelectionIndices(), new int[] {});
@@ -1600,30 +1398,18 @@ public void test_setItemILjava_lang_String() {
assertEquals(list.getItemCount(), 0);
int[] cases = { -10, 0, 10 };
for (int index : cases) {
- try {
- list.setItem(index, null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setItem(index, null), "No exception thrown");
}
assertEquals(list.getItemCount(), 0);
for (int index : cases) {
- try {
- list.setItem(index, "");
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setItem(index, ""), "No exception thrown");
}
assertEquals(list.getItemCount(), 0);
int cases2[] = { 10, 15, 0 };
for (int index : cases2) {
- try {
- list.setItem(index, "fred");
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setItem(index, "fred"), "No exception thrown");
assertEquals(list.getItemCount(), 0);
}
@@ -1634,22 +1420,14 @@ public void test_setItemILjava_lang_String() {
setSingleList();
assertEquals(0, list.getItemCount());
for (int index : cases) {
- try {
- list.setItem(index, null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setItem(index, null), "No exception thrown");
}
setSingleList();
for (int index : cases) {
- try {
- list.setItem(index, "");
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setItem(index, ""), "No exception thrown");
}
assertEquals(0, list.getItemCount());
@@ -1657,11 +1435,7 @@ public void test_setItemILjava_lang_String() {
setSingleList();
for (int index : cases2) {
- try {
- list.setItem(index, "fred");
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setItem(index, "fred"), "No exception thrown");
assertEquals(0, list.getItemCount());
}
@@ -1674,11 +1448,7 @@ public void test_setItemILjava_lang_String() {
@Test
public void test_setItems$Ljava_lang_String() {
- try {
- list.setItems((String[])null);
- fail("No exception thrown for items == null");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setItems((String[])null), "No exception thrown for items == null");
// TODO An SWTError should never happen and should not
// be part of the test case. List should throw an
@@ -1705,11 +1475,7 @@ public void test_setItemILjava_lang_String() {
assertArrayEquals(items, list.getItems());
}
- try {
- list.setItems((String[])null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setItems((String[])null), "No exception thrown");
setSingleList();
@@ -1719,11 +1485,7 @@ public void test_setItemILjava_lang_String() {
}
- try {
- list.setItems((String[])null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setItems((String[])null), "No exception thrown");
}
@Test
@@ -1735,11 +1497,7 @@ public void test_setItemILjava_lang_String() {
list.setSelection(new int [0]);
assertArrayEquals(list.getSelectionIndices(), new int[0]);
- try {
- list.setSelection((int[]) null);
- fail("No exception thrown for MULTI: setSelection((int[]) null)");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setSelection((int[]) null), "No exception thrown for MULTI: setSelection((int[]) null)");
list.setSelection(new int [] {2});
assertArrayEquals(list.getSelectionIndices(), new int[] {2});
@@ -1793,11 +1551,7 @@ public void test_setItemILjava_lang_String() {
assertArrayEquals(list.getSelectionIndices(), new int[0]);
assertEquals(list.getFocusIndex(), -1);
- try {
- list.setSelection((int[]) null);
- fail("No exception thrown for EMPTY MULTI: setSelection((int[]) null)");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setSelection((int[]) null), "No exception thrown for EMPTY MULTI: setSelection((int[]) null)");
list.setSelection(new int [] {0});
assertArrayEquals(list.getSelectionIndices(), new int[0]);
@@ -1827,11 +1581,7 @@ public void test_setItemILjava_lang_String() {
list.setSelection(new int [0]);
assertArrayEquals(list.getSelectionIndices(), new int[0]);
- try {
- list.setSelection((int[]) null);
- fail("No exception thrown for SINGLE: setSelection((int[]) null)");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setSelection((int[]) null), "No exception thrown for SINGLE: setSelection((int[]) null)");
list.setSelection(new int [] {2});
assertArrayEquals(list.getSelectionIndices(), new int[] {2});
@@ -1880,11 +1630,7 @@ public void test_setItemILjava_lang_String() {
assertArrayEquals(list.getSelectionIndices(), new int[0]);
assertEquals(list.getFocusIndex(), -1);
- try {
- list.setSelection((int[]) null);
- fail("No exception thrown for EMPTY SINGLE: setSelection((int[]) null)");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setSelection((int[]) null), "No exception thrown for EMPTY SINGLE: setSelection((int[]) null)");
list.setSelection(new int [] {0});
assertArrayEquals(list.getSelectionIndices(), new int[0]);
@@ -1919,11 +1665,7 @@ public void test_setItemILjava_lang_String() {
assertEquals(list.getFocusIndex(), -1);
}
- try {
- list.setSelection((String[]) null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setSelection((String[]) null), "No exception thrown");
list.setSelection(new String [] {"fred 2"});
assertArrayEquals(list.getSelection(), new String [] {"fred 2"});
@@ -1966,11 +1708,7 @@ public void test_setItemILjava_lang_String() {
assertArrayEquals(list.getSelection(), new String[0]);
assertEquals(list.getFocusIndex(), -1);
- try {
- list.setSelection((String[]) null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setSelection((String[]) null), "No exception thrown");
list.setSelection(new String [] {"fred 0"});
assertArrayEquals(list.getSelection(), new String[0]);
@@ -1988,11 +1726,7 @@ public void test_setItemILjava_lang_String() {
list.setSelection(new String [0]);
assertArrayEquals(list.getSelection(), new String[0]);
- try {
- list.setSelection((String[]) null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setSelection((String[]) null), "No exception thrown");
list.setSelection(new String [] {"fred 2"});
assertArrayEquals(list.getSelection(), new String[] {"fred 2"});
@@ -2032,11 +1766,7 @@ public void test_setItemILjava_lang_String() {
assertArrayEquals(list.getSelection(), new String[0]);
assertEquals(list.getFocusIndex(), -1);
- try {
- list.setSelection((String[]) null);
- fail("No exception thrown");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> list.setSelection((String[]) null), "No exception thrown");
list.setSelection(new String [] {"fred 0"});
assertArrayEquals(list.getSelection(), new String[0]);
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_MenuItem.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_MenuItem.java
index 1db0b857eca..5ea3cbc497d 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_MenuItem.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_MenuItem.java
@@ -195,6 +195,19 @@ public void test_setEnabledZ() {
assertFalse(menuItem.getEnabled());
}
+@Test
+public void test_setEnabledZ_cascade() {
+ MenuItem cascadeItem = new MenuItem(menu, SWT.CASCADE);
+ Menu subMenu = new Menu(shell, SWT.DROP_DOWN);
+ cascadeItem.setMenu(subMenu);
+ assertTrue(cascadeItem.getEnabled());
+ cascadeItem.setEnabled(false);
+ assertFalse(cascadeItem.getEnabled());
+ cascadeItem.setEnabled(true);
+ assertTrue(cascadeItem.getEnabled());
+ cascadeItem.dispose();
+}
+
@Tag("gtk4-todo")
@Override
@Test
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TabFolder.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TabFolder.java
index 751d1c75051..075c58e9276 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TabFolder.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TabFolder.java
@@ -15,8 +15,8 @@
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import java.util.ArrayList;
import java.util.List;
@@ -48,12 +48,7 @@ public void setUp() {
@Override
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
- try {
- new TabFolder(null, 0);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new TabFolder(null, 0), "No exception thrown for parent == null");
}
@Override
@@ -108,26 +103,11 @@ public void test_getItemI() {
for (int i = 0; i < number; i++) {
assertEquals(items[i], tabFolder.getItem(i));
}
- try {
- tabFolder.getItem(number);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tabFolder.getItem(number), "No exception thrown for illegal index argument");
- try {
- tabFolder.getItem(number+1);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tabFolder.getItem(number+1), "No exception thrown for illegal index argument");
- try {
- tabFolder.getItem(-1);
- fail("No exception thrown for index == -1");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tabFolder.getItem(-1), "No exception thrown for index == -1");
}
@Test
@@ -226,12 +206,7 @@ public void test_indexOfLorg_eclipse_swt_widgets_TabItem() {
tis[i] = new TabItem(tabFolder, 0);
}
for (int i = 0; i tabFolder.indexOf(null), "No exception thrown for tabItem == null");
}
//
@@ -312,25 +287,11 @@ public void test_setSelectionI() {
TabItem[] items = new TabItem[number];
for (int i = 0; i < number; i++)
items[i] = new TabItem(tabFolder, 0);
- try {
- tabFolder.setSelection((TabItem) null);
- fail("No exception thrown for selection == null");
- }
- catch (IllegalArgumentException e) {
- }
- finally {
- assertArrayEquals(new TabItem[]{items[0]}, tabFolder.getSelection());
- }
+ assertThrows(IllegalArgumentException.class, () -> tabFolder.setSelection((TabItem) null), "No exception thrown for selection == null");
+ assertArrayEquals(new TabItem[]{items[0]}, tabFolder.getSelection());
- try {
- tabFolder.setSelection((TabItem[]) null);
- fail("No exception thrown for selection == null");
- }
- catch (IllegalArgumentException e) {
- }
- finally {
- assertArrayEquals(new TabItem[]{items[0]}, tabFolder.getSelection());
- }
+ assertThrows(IllegalArgumentException.class, () -> tabFolder.setSelection((TabItem[]) null), "No exception thrown for selection == null");
+ assertArrayEquals(new TabItem[]{items[0]}, tabFolder.getSelection());
//
makeCleanEnvironment();
@@ -390,18 +351,12 @@ public void test_setSelectionI() {
//
makeCleanEnvironment();
+ TabItem[] recreatedItems = new TabItem[number];
for (int i = 0; i < number; i++)
- items[i] = new TabItem(tabFolder, 0);
- try {
- tabFolder.setSelection( new TabItem[]{items[0], null});
- tabFolder.setSelection( new TabItem[]{null});
- fail("No exception thrown for selection == null");
- }
- catch (IllegalArgumentException e) {
- }
- finally {
- assertArrayEquals(new TabItem[]{items[0]}, tabFolder.getSelection());
- }
+ recreatedItems[i] = new TabItem(tabFolder, 0);
+ assertThrows(IllegalArgumentException.class, () -> tabFolder.setSelection(new TabItem[]{recreatedItems[0], null}), "No exception thrown for a null item in the selection");
+ assertThrows(IllegalArgumentException.class, () -> tabFolder.setSelection(new TabItem[]{null}), "No exception thrown for selection == null");
+ assertArrayEquals(new TabItem[]{recreatedItems[0]}, tabFolder.getSelection());
}
/* custom */
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Table.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Table.java
index 1a46337a071..f5a151d83d6 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Table.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Table.java
@@ -18,8 +18,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import java.util.ArrayList;
import java.util.List;
@@ -51,12 +51,7 @@ public void setUp() {
@Override
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
- try {
- new Table(null, 0);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new Table(null, 0), "No exception thrown for parent == null");
}
@Override
@@ -92,12 +87,7 @@ public void test_computeSizeIIZ() {
table.selectAll();
assertEquals(number, table.getSelectionCount());
- try{
- table.deselect(null);
- fail("No exception thrown for selection == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.deselect(null), "No exception thrown for selection == null");
assertEquals(number, table.getSelectionCount());
table.selectAll();
@@ -257,36 +247,16 @@ public void test_getColumnCount() {
@Test
public void test_getColumnI() {
- try {
- table.getColumn(0);
- fail("No exception thrown for index out of range");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getColumn(0), "No exception thrown for index out of range");
TableColumn column0 = new TableColumn(table, SWT.LEFT);
- try {
- table.getColumn(1);
- fail("No exception thrown for index out of range");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getColumn(1), "No exception thrown for index out of range");
assertEquals(column0, table.getColumn(0));
TableColumn column1 = new TableColumn(table, SWT.LEFT);
assertEquals(column1, table.getColumn(1));
column1.dispose();
- try {
- table.getColumn(1);
- fail("No exception thrown for index out of range");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getColumn(1), "No exception thrown for index out of range");
column0.dispose();
- try {
- table.getColumn(0);
- fail("No exception thrown for index out of range");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getColumn(0), "No exception thrown for index out of range");
}
@Test
@@ -372,19 +342,9 @@ public void test_getItemI() {
for (int i = 0; i < number; i++)
assertEquals(items[i], table.getItem(i));
- try {
- table.getItem(number);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getItem(number), "No exception thrown for illegal index argument");
- try {
- table.getItem(number+1);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getItem(number+1), "No exception thrown for illegal index argument");
// note: SWT.SINGLE
makeCleanEnvironment(true);
@@ -394,19 +354,9 @@ public void test_getItemI() {
for (int i = 0; i < number; i++) {
assertEquals(items[i], table.getItem(i));
}
- try {
- table.getItem(number);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getItem(number), "No exception thrown for illegal index argument");
- try {
- table.getItem(number+1);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getItem(number+1), "No exception thrown for illegal index argument");
}
@Test
@@ -640,12 +590,7 @@ public void test_indexOfLorg_eclipse_swt_widgets_TableItem() {
}
for (int i = 0; i < number; i++) {
- try {
- table.indexOf((TableItem)null);
- fail("No exception thrown for tableItem == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.indexOf((TableItem)null), "No exception thrown for tableItem == null");
}
// another table
@@ -683,12 +628,7 @@ public void test_indexOfLorg_eclipse_swt_widgets_TableItem() {
}
for (int i = 0; i < number; i++) {
- try {
- table.indexOf((TableItem)null);
- fail("No exception thrown for tableItem == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.indexOf((TableItem)null), "No exception thrown for tableItem == null");
}
makeCleanEnvironment(true);
@@ -767,26 +707,11 @@ public void test_isSelectedI() {
TableItem[] items = new TableItem[number];
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.remove(null);
- fail("No exception thrown for tableItems == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.remove(null), "No exception thrown for tableItems == null");
- try {
- table.remove(new int[] {2, 1, 0, -100, 5, 5, 2, 1, 0, 0, 0});
- fail("No exception thrown for illegal index arguments");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.remove(new int[] {2, 1, 0, -100, 5, 5, 2, 1, 0, 0, 0}), "No exception thrown for illegal index arguments");
- try {
- table.remove(new int[] {2, 1, 0, number, 5, 5, 2, 1, 0, 0, 0});
- fail("No exception thrown for illegal index arguments");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.remove(new int[] {2, 1, 0, number, 5, 5, 2, 1, 0, 0, 0}), "No exception thrown for illegal index arguments");
table.remove(new int[] {});
@@ -847,10 +772,7 @@ public void test_removeII() {
TableItem[] items = new TableItem[number];
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.remove(-number, number + 100);
- fail("No exception thrown for illegal index range");
- } catch (IllegalArgumentException e) {}
+ assertThrows(IllegalArgumentException.class, () -> table.remove(-number, number + 100), "No exception thrown for illegal index range");
makeCleanEnvironment(false);
@@ -871,10 +793,7 @@ public void test_removeII() {
items = new TableItem[number];
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.remove(2, 100);
- fail("No exception thrown for illegal index range");
- } catch (IllegalArgumentException e) {}
+ assertThrows(IllegalArgumentException.class, () -> table.remove(2, 100), "No exception thrown for illegal index range");
assertArrayEquals(items, table.getItems());
makeCleanEnvironment(false);
@@ -882,10 +801,7 @@ public void test_removeII() {
items = new TableItem[number];
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.remove(2, number);
- fail("No exception thrown for illegal index range");
- } catch (IllegalArgumentException e) {}
+ assertThrows(IllegalArgumentException.class, () -> table.remove(2, number), "No exception thrown for illegal index range");
assertArrayEquals(items, table.getItems());
makeCleanEnvironment(false);
@@ -937,20 +853,14 @@ public void test_removeII() {
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.remove(-20, -10);
- fail("No exception thrown for illegal index range");
- } catch (IllegalArgumentException e) {}
+ assertThrows(IllegalArgumentException.class, () -> table.remove(-20, -10), "No exception thrown for illegal index range");
assertArrayEquals(items, table.getItems());
makeCleanEnvironment(false);
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.remove(20, 40);
- fail("No exception thrown for illegal index range");
- } catch (IllegalArgumentException e) {}
+ assertThrows(IllegalArgumentException.class, () -> table.remove(20, 40), "No exception thrown for illegal index range");
assertArrayEquals(items, table.getItems());
makeCleanEnvironment(false);
@@ -998,10 +908,7 @@ public void test_removeII() {
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
assertEquals(number, table.getItemCount());
- try {
- table.remove(-10, 2);
- fail("No exception thrown for illegal index range");
- } catch (IllegalArgumentException e) {}
+ assertThrows(IllegalArgumentException.class, () -> table.remove(-10, 2), "No exception thrown for illegal index range");
assertEquals(number, table.getItemCount());
if (SwtTestUtil.fCheckSWTPolicy) {
table.remove(10, 2);
@@ -1016,10 +923,7 @@ public void test_removeII() {
for (int i = 3; i < number; i++) {
assertFalse(items[i].isDisposed());
}
- try {
- table.remove(1, 200);
- fail("No exception thrown for illegal index range");
- } catch (IllegalArgumentException e) {}
+ assertThrows(IllegalArgumentException.class, () -> table.remove(1, 200), "No exception thrown for illegal index range");
assertEquals(number - 3, table.getItemCount());
assertArrayEquals(new TableItem[] {items[3], items[4]}, table.getItems());
@@ -1038,29 +942,23 @@ public void test_removeII() {
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.remove(number, number);
- fail("No exception thrown for illegal index range");
- } catch (IllegalArgumentException e) {}
+ assertThrows(IllegalArgumentException.class, () -> table.remove(number, number), "No exception thrown for illegal index range");
makeCleanEnvironment(false);
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.remove(number, number + 100);
- fail("No exception thrown for illegal index range");
- } catch (IllegalArgumentException e) {}
+ assertThrows(IllegalArgumentException.class, () -> table.remove(number, number + 100), "No exception thrown for illegal index range");
makeCleanEnvironment(false);
- number = 15;
- items = new TableItem[number];
- for (int i = 0; i < number; i++)
+ int largerNumber = 15;
+ items = new TableItem[largerNumber];
+ for (int i = 0; i < largerNumber; i++)
items[i] = new TableItem(table, 0);
table.remove(new int[] {2, 1, 0, 5, 5});
- assertEquals(number-4, table.getItemCount());
+ assertEquals(largerNumber-4, table.getItemCount());
assertTrue(items[0].isDisposed());
assertTrue(items[1].isDisposed());
assertTrue(items[2].isDisposed());
@@ -1071,12 +969,7 @@ public void test_removeII() {
@Test
public void test_select$I() {
- try {
- table.select(null);
- fail("No exception thrown for selection == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.select(null), "No exception thrown for selection == null");
int number = 15;
TableItem[] items = new TableItem[number];
@@ -1128,15 +1021,8 @@ public void test_removeII() {
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.select(null);
- fail("No exception thrown for selection == null");
- }
- catch (IllegalArgumentException e) {
- }
- finally {
- assertEquals(0, table.getSelectionCount());
- }
+ assertThrows(IllegalArgumentException.class, () -> table.select(null), "No exception thrown for selection == null");
+ assertEquals(0, table.getSelectionCount());
table.select(new int[] {0});
assertArrayEquals(new int[] {0}, table.getSelectionIndices());
@@ -1329,69 +1215,33 @@ public void test_selectII() {
assertArrayEquals(table.getColumnOrder(), new int[0]);
table.setColumnOrder(new int[0]);
assertArrayEquals(table.getColumnOrder(), new int[0]);
- try {
- table.setColumnOrder(null);
- fail("No exception thrown for null argument");
- } catch (IllegalArgumentException ex) {}
- try {
- table.setColumnOrder(new int[1]);
- fail("No exception thrown for invalid argument");
- } catch (IllegalArgumentException ex) {}
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(null), "No exception thrown for null argument");
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(new int[1]), "No exception thrown for invalid argument");
TableColumn column0 = new TableColumn(table, SWT.NONE);
TableColumn column1 = new TableColumn(table, SWT.NONE);
TableColumn column2 = new TableColumn(table, SWT.NONE);
assertArrayEquals(table.getColumnOrder(), new int[]{0, 1, 2});
- try {
- table.setColumnOrder(null);
- fail("No exception thrown for null argument");
- } catch (IllegalArgumentException ex) {}
- try {
- table.setColumnOrder(new int[0]);
- fail("No exception thrown for invalid argument");
- } catch (IllegalArgumentException ex) {}
- try {
- table.setColumnOrder(new int[]{0,1});
- fail("No exception thrown for invalid argument");
- } catch (IllegalArgumentException ex) {}
- try {
- table.setColumnOrder(new int[]{0, 1, 2, 3});
- fail("No exception thrown for invalid argument");
- } catch (IllegalArgumentException ex) {}
- try {
- table.setColumnOrder(new int[]{0, 0, 1});
- fail("No exception thrown for invalid argument");
- } catch (IllegalArgumentException ex) {}
- try {
- table.setColumnOrder(new int[]{3, 0, 1});
- fail("No exception thrown for invalid argument");
- } catch (IllegalArgumentException ex) {}
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(null), "No exception thrown for null argument");
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(new int[0]), "No exception thrown for invalid argument");
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(new int[]{0,1}), "No exception thrown for invalid argument");
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(new int[]{0, 1, 2, 3}), "No exception thrown for invalid argument");
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(new int[]{0, 0, 1}), "No exception thrown for invalid argument");
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(new int[]{3, 0, 1}), "No exception thrown for invalid argument");
table.setColumnOrder(new int[]{2, 1, 0});
assertArrayEquals(table.getColumnOrder(), new int[] {2, 1, 0});
column2.dispose();
assertArrayEquals(table.getColumnOrder(), new int[] {1, 0});
- try {
- table.setColumnOrder(new int[]{0, 1, 2});
- fail("No exception thrown for invalid argument");
- } catch (IllegalArgumentException ex) {}
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(new int[]{0, 1, 2}), "No exception thrown for invalid argument");
column1.dispose();
assertArrayEquals(table.getColumnOrder(), new int[]{0});
column0.dispose();
assertArrayEquals(table.getColumnOrder(), new int[0]);
- try {
- table.setColumnOrder(new int[1]);
- fail("No exception thrown for invalid argument");
- } catch (IllegalArgumentException ex) {}
+ assertThrows(IllegalArgumentException.class, () -> table.setColumnOrder(new int[1]), "No exception thrown for invalid argument");
Table table2 = new Table(table.getParent(), SWT.NONE);
table2.dispose();
- try {
- table2.getColumnOrder();
- fail("No exception thrown for widget is Disposed");
- } catch (SWTException ex) {}
- try {
- table2.setColumnOrder(new int[0]);
- fail("No exception thrown for widget is Disposed");
- } catch (SWTException ex) {}
+ assertThrows(SWTException.class, () -> table2.getColumnOrder(), "No exception thrown for widget is Disposed");
+ assertThrows(SWTException.class, () -> table2.setColumnOrder(new int[0]), "No exception thrown for widget is Disposed");
}
@Override
@@ -1456,23 +1306,13 @@ public void test_setItemCountI() {
assertEquals(4, table.indexOf(table.getItems()[4]));
table.setItemCount(3);
assertEquals(3, table.getItemCount());
- try {
- table.getItem(4);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getItem(4), "No exception thrown for illegal index argument");
table.setItemCount(40);
assertEquals(40, table.getItemCount());
table.getItem(39);
table.setItemCount(0);
assertEquals(0, table.getItemCount());
- try {
- table.getItem(39);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.getItem(39), "No exception thrown for illegal index argument");
}
@Test
@@ -1495,12 +1335,7 @@ public void test_setRedrawZ() {
TableItem[] items = new TableItem[number];
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.setSelection((int[]) null);
- fail("No exception thrown for selection == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> table.setSelection((int[]) null), "No exception thrown for selection == null");
table.setSelection(new int[]{});
assertArrayEquals(new int[]{}, table.getSelectionIndices());
@@ -1532,15 +1367,8 @@ public void test_setRedrawZ() {
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.setSelection((int[]) null);
- fail("No exception thrown for selection range == null");
- }
- catch (IllegalArgumentException e) {
- }
- finally {
- assertEquals(0, table.getSelectionCount());
- }
+ assertThrows(IllegalArgumentException.class, () -> table.setSelection((int[]) null), "No exception thrown for selection range == null");
+ assertEquals(0, table.getSelectionCount());
table.setSelection(new int[] {});
assertArrayEquals(new int[] {}, table.getSelectionIndices());
@@ -1579,25 +1407,11 @@ public void test_setRedrawZ() {
TableItem[] items = new TableItem[number];
for (int i = 0; i < number; i++)
items[i] = new TableItem(table, 0);
- try {
- table.setSelection((TableItem[]) null);
- fail("No exception thrown for selection range == null");
- }
- catch (IllegalArgumentException e) {
- }
- finally {
- assertEquals(0, table.getSelectionCount());
- }
+ assertThrows(IllegalArgumentException.class, () -> table.setSelection((TableItem[]) null), "No exception thrown for selection range == null");
+ assertEquals(0, table.getSelectionCount());
- try {
- table.setSelection((TableItem) null);
- fail("No exception thrown for selection == null");
- }
- catch (IllegalArgumentException e) {
- }
- finally {
- assertEquals(0, table.getSelectionCount());
- }
+ assertThrows(IllegalArgumentException.class, () -> table.setSelection((TableItem) null), "No exception thrown for selection == null");
+ assertEquals(0, table.getSelectionCount());
table.setSelection(new TableItem[]{});
assertEquals(0, table.getSelectionCount());
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TableColumn.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TableColumn.java
index 7a1cf107b8e..08ad4dab85b 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TableColumn.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TableColumn.java
@@ -15,8 +15,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
@@ -47,46 +47,21 @@ public void setUp() {
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_TableI() {
- try {
- new TableColumn(null, SWT.NULL);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new TableColumn(null, SWT.NULL), "No exception thrown for parent == null");
}
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_TableII() {
- try {
- new TableColumn(null, SWT.NULL, 0);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
-
- try {
- new TableColumn(table, SWT.NULL, -1);
- fail("No exception thrown for index == -1");
- }
- catch (IllegalArgumentException e) {
- }
-
- try {
- new TableColumn(table, SWT.NULL, 2);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new TableColumn(null, SWT.NULL, 0), "No exception thrown for parent == null");
+
+ assertThrows(IllegalArgumentException.class, () -> new TableColumn(table, SWT.NULL, -1), "No exception thrown for index == -1");
+
+ assertThrows(IllegalArgumentException.class, () -> new TableColumn(table, SWT.NULL, 2), "No exception thrown for illegal index argument");
}
@Test
public void test_addSelectionListenerLorg_eclipse_swt_events_SelectionListener() {
- try {
- tableColumn.addSelectionListener(null);
- fail("No exception thrown for selectionListener == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableColumn.addSelectionListener(null), "No exception thrown for selectionListener == null");
}
@Test
@@ -138,12 +113,7 @@ public void test_removeSelectionListenerLorg_eclipse_swt_events_SelectionListene
tableColumn.removeSelectionListener(listener);
tableColumn.addSelectionListener(listener);
tableColumn.removeSelectionListener(listener);
- try {
- tableColumn.removeSelectionListener(null);
- fail("No exception thrown for selectionListener == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableColumn.removeSelectionListener(null), "No exception thrown for selectionListener == null");
}
@Test
@@ -189,14 +159,8 @@ public void test_setMoveableZ() {
TableColumn tableColumn2 = new TableColumn(tableColumn.getParent(), SWT.NONE);
tableColumn2.dispose();
- try {
- tableColumn2.getMoveable();
- fail("No exception thrown for widget is Disposed");
- } catch (SWTException ex) {}
- try {
- tableColumn2.setMoveable(true);
- fail("No exception thrown for widget is Disposed");
- } catch (SWTException ex) {}
+ assertThrows(SWTException.class, () -> tableColumn2.getMoveable(), "No exception thrown for widget is Disposed");
+ assertThrows(SWTException.class, () -> tableColumn2.setMoveable(true), "No exception thrown for widget is Disposed");
}
@Test
@@ -221,12 +185,7 @@ public void test_setTextLjava_lang_String() {
tableColumn.setText("text");
assertEquals(tableColumn.getText(), "text");
- try {
- tableColumn.setText(null);
- fail("No exception thrown for column header == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableColumn.setText(null), "No exception thrown for column header == null");
}
/* custom */
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TableItem.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TableItem.java
index 1f4c976d336..7b9f6f96166 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TableItem.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TableItem.java
@@ -18,7 +18,6 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
@@ -440,13 +439,9 @@ public void test_setBackgroundILorg_eclipse_swt_graphics_Color() {
tableItem.setBackground(null);
assertEquals(table.getBackground(),tableItem.getBackground(0));
- try {
- Color color = new Color(255, 0, 0);
- color.dispose();
- tableItem.setBackground(color);
- fail("No exception thrown for color disposed");
- } catch (IllegalArgumentException e) {
- }
+ Color disposedColor = new Color(255, 0, 0);
+ disposedColor.dispose();
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setBackground(disposedColor), "No exception thrown for color disposed");
}
@Test
@@ -457,11 +452,7 @@ public void test_setBackgroundLorg_eclipse_swt_graphics_Color() {
tableItem.setBackground(null);
assertEquals(table.getBackground(),tableItem.getBackground());
color.dispose();
- try {
- tableItem.setBackground(color);
- fail("No exception thrown for color disposed");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setBackground(color), "No exception thrown for color disposed");
}
@Test
@@ -483,11 +474,11 @@ public void test_setCheckedZ() {
@Test
public void test_setFontLorg_eclipse_swt_graphics_Font() {
Display display = tableItem.getDisplay();
- Font font = tableItem.getFont();
- tableItem.setFont(font);
- assertEquals(tableItem.getFont(), font);
+ Font initialFont = tableItem.getFont();
+ tableItem.setFont(initialFont);
+ assertEquals(tableItem.getFont(), initialFont);
- font = new Font(display, SwtTestUtil.testFontName, 10, SWT.NORMAL);
+ Font font = new Font(display, SwtTestUtil.testFontName, 10, SWT.NORMAL);
tableItem.setFont(font);
assertEquals(tableItem.getFont(), font);
@@ -495,12 +486,7 @@ public void test_setFontLorg_eclipse_swt_graphics_Font() {
assertEquals(tableItem.getFont(), table.getFont());
font.dispose();
- try {
- tableItem.setFont(font);
- tableItem.setFont(null);
- fail("No exception thrown for disposed font");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setFont(font), "No exception thrown for disposed font");
}
@Test
@@ -546,12 +532,7 @@ public void test_setFontILorg_eclipse_swt_graphics_Font() {
font.dispose();
font2.dispose();
- try {
- tableItem.setFont(0, font);
- tableItem.setFont(0, null);
- fail("No exception thrown for disposed font");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setFont(0, font), "No exception thrown for disposed font");
}
@Test
@@ -593,13 +574,9 @@ public void test_setForegroundILorg_eclipse_swt_graphics_Color() {
tableItem.setForeground(null);
assertEquals(table.getForeground(),tableItem.getForeground(0));
- try {
- Color color = new Color(255, 0, 0);
- color.dispose();
- tableItem.setForeground(color);
- fail("No exception thrown for color disposed");
- } catch (IllegalArgumentException e) {
- }
+ Color disposedColor = new Color(255, 0, 0);
+ disposedColor.dispose();
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setForeground(disposedColor), "No exception thrown for color disposed");
}
@Test
@@ -610,11 +587,7 @@ public void test_setForegroundLorg_eclipse_swt_graphics_Color() {
tableItem.setForeground(null);
assertEquals(table.getForeground(),tableItem.getForeground());
color.dispose();
- try {
- tableItem.setForeground(color);
- fail("No exception thrown for color disposed");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setForeground(color), "No exception thrown for color disposed");
}
@Test
@@ -659,12 +632,7 @@ public void test_setGrayedZ() {
for (int i = 0; i < images.length; i++) {
assertEquals(images[i], tableItem.getImage(i));
}
- try {
- tableItem.setImage((Image []) null);
- fail("No exception thrown for images == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setImage((Image []) null), "No exception thrown for images == null");
}
@Test
@@ -700,12 +668,7 @@ public void test_setImageILorg_eclipse_swt_graphics_Image() {
assertEquals(images[0], tableItem.getImage(0));
images[0].dispose();
- try {
- tableItem.setImage(0, images[0]);
- tableItem.setImage(0, null);
- fail("No exception thrown for disposed font");
- } catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setImage(0, images[0]), "No exception thrown for disposed image");
}
@SuppressWarnings("deprecation")
@@ -727,12 +690,7 @@ public void test_setImageIndentI() {
final String TestString = "test";
final String TestStrings[] = new String[] {TestString, TestString + "1", TestString + "2"};
- try {
- tableItem.setText((String []) null);
- fail("No exception thrown for strings == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setText((String []) null), "No exception thrown for strings == null");
/*
* Test the getText/setText API with a Table that has only
@@ -820,19 +778,9 @@ public void test_setTextILjava_lang_String(){
assertEquals(0, tableItem.getText(-1).length());
- try {
- tableItem.setText(-1, null);
- fail("No exception thrown for string == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setText(-1, null), "No exception thrown for string == null");
- try {
- tableItem.setText(0, null);
- fail("No exception thrown for string == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tableItem.setText(0, null), "No exception thrown for string == null");
/*
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Tree.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Tree.java
index 233adea21f1..ec55e2f693f 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Tree.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Tree.java
@@ -19,8 +19,8 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import java.util.ArrayList;
import java.util.List;
@@ -59,12 +59,7 @@ public void setUp() {
@Override
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_CompositeI() {
- try {
- tree = new Tree(null, 0);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new Tree(null, 0), "No exception thrown for parent == null");
int[] cases = {0, SWT.BORDER};
for (int style : cases)
@@ -126,36 +121,16 @@ public void test_getColumnCount() {
@Test
public void test_getColumnI() {
- try {
- tree.getColumn(0);
- fail("No exception thrown for index out of range");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.getColumn(0), "No exception thrown for index out of range");
TreeColumn column0 = new TreeColumn(tree, SWT.LEFT);
- try {
- tree.getColumn(1);
- fail("No exception thrown for index out of range");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.getColumn(1), "No exception thrown for index out of range");
assertEquals(column0, tree.getColumn(0));
TreeColumn column1 = new TreeColumn(tree, SWT.LEFT);
assertEquals(column1, tree.getColumn(1));
column1.dispose();
- try {
- tree.getColumn(1);
- fail("No exception thrown for index out of range");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.getColumn(1), "No exception thrown for index out of range");
column0.dispose();
- try {
- tree.getColumn(0);
- fail("No exception thrown for index out of range");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.getColumn(0), "No exception thrown for index out of range");
}
@Test
@@ -218,26 +193,11 @@ public void test_getItemI() {
for (int i = 0; i < number; i++)
assertEquals(items[i], tree.getItem(i));
- try {
- tree.getItem(number);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.getItem(number), "No exception thrown for illegal index argument");
- try {
- tree.getItem(number+1);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.getItem(number+1), "No exception thrown for illegal index argument");
- try {
- tree.getItem(-1);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.getItem(-1), "No exception thrown for illegal index argument");
}
@Test
@@ -428,23 +388,13 @@ public void test_setItemCountI() {
assertEquals(4, tree.indexOf(tree.getItems()[4]));
tree.setItemCount(3);
assertEquals(3, tree.getItemCount());
- try {
- tree.getItem(4);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.getItem(4), "No exception thrown for illegal index argument");
tree.setItemCount(40);
assertEquals(40, tree.getItemCount());
tree.getItem(39);
tree.setItemCount(0);
assertEquals(0, tree.getItemCount());
- try {
- tree.getItem(39);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.getItem(39), "No exception thrown for illegal index argument");
}
@Test
@@ -484,12 +434,7 @@ public void test_setRedrawZ() {
assertArrayEquals(new TreeItem[] {}, tree.getSelection());
assertEquals(0, tree.getSelectionCount());
- try {
- tree.setSelection((TreeItem[]) null);
- fail("No exception thrown for items == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.setSelection((TreeItem[]) null), "No exception thrown for items == null");
tree.setSelection(new TreeItem[]{null});
assertEquals(0, tree.getSelectionCount());
@@ -565,12 +510,7 @@ public void test_setRedrawZ() {
assertArrayEquals(new TreeItem[] {}, tree.getSelection());
assertEquals(0, tree.getSelectionCount());
- try {
- tree.setSelection((TreeItem[]) null);
- fail("No exception thrown for items == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.setSelection((TreeItem[]) null), "No exception thrown for items == null");
tree.setSelection(new TreeItem[]{items[10]});
assertArrayEquals(new TreeItem[] {items[10]}, tree.getSelection());
@@ -641,11 +581,9 @@ public void test_setTopItemLorg_eclipse_swt_widgets_TreeItem() {
TreeItem top2 = tree.getTopItem();
shell.setVisible(false);
assertEquals(top, top2);
+ shell.setVisible(true);
try {
- shell.setVisible(true);
- tree.setTopItem(null);
- fail("No exception thrown for item == null");
- } catch (IllegalArgumentException e) {
+ assertThrows(IllegalArgumentException.class, () -> tree.setTopItem(null), "No exception thrown for item == null");
} finally {
shell.setVisible (false);
}
@@ -653,12 +591,7 @@ public void test_setTopItemLorg_eclipse_swt_widgets_TreeItem() {
@Test
public void test_showItemLorg_eclipse_swt_widgets_TreeItem() {
- try {
- tree.showItem(null);
- fail("No exception thrown for item == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> tree.showItem(null), "No exception thrown for item == null");
int number = 20;
TreeItem[] items = new TreeItem[number];
diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TreeColumn.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TreeColumn.java
index 5101938a1c0..db09106ff32 100644
--- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TreeColumn.java
+++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_TreeColumn.java
@@ -15,8 +15,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
import java.util.ArrayList;
@@ -50,46 +50,21 @@ public void setUp() {
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_TreeI() {
- try {
- new TreeColumn(null, SWT.NULL);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new TreeColumn(null, SWT.NULL), "No exception thrown for parent == null");
}
@Test
public void test_ConstructorLorg_eclipse_swt_widgets_TreeII() {
- try {
- new TreeColumn(null, SWT.NULL, 0);
- fail("No exception thrown for parent == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new TreeColumn(null, SWT.NULL, 0), "No exception thrown for parent == null");
- try {
- new TreeColumn(tree, SWT.NULL, -1);
- fail("No exception thrown for index == -1");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new TreeColumn(tree, SWT.NULL, -1), "No exception thrown for index == -1");
- try {
- new TreeColumn(tree, SWT.NULL, 2);
- fail("No exception thrown for illegal index argument");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> new TreeColumn(tree, SWT.NULL, 2), "No exception thrown for illegal index argument");
}
@Test
public void test_addSelectionListenerLorg_eclipse_swt_events_SelectionListener() {
- try {
- treeColumn.addSelectionListener(null);
- fail("No exception thrown for selectionListener == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> treeColumn.addSelectionListener(null), "No exception thrown for selectionListener == null");
}
@Test
@@ -142,12 +117,7 @@ public void test_removeSelectionListenerLorg_eclipse_swt_events_SelectionListene
treeColumn.removeSelectionListener(listener);
treeColumn.addSelectionListener(listener);
treeColumn.removeSelectionListener(listener);
- try {
- treeColumn.removeSelectionListener(null);
- fail("No exception thrown for selectionListener == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> treeColumn.removeSelectionListener(null), "No exception thrown for selectionListener == null");
}
@Test
@@ -200,12 +170,7 @@ public void test_setTextLjava_lang_String() {
treeColumn.setText("text");
assertEquals(treeColumn.getText(), "text");
- try {
- treeColumn.setText(null);
- fail("No exception thrown for column header == null");
- }
- catch (IllegalArgumentException e) {
- }
+ assertThrows(IllegalArgumentException.class, () -> treeColumn.setText(null), "No exception thrown for column header == null");
}
@Test
diff --git a/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Issue3522_CTabFolderDirtyIndicatorTextJump.java b/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Issue3522_CTabFolderDirtyIndicatorTextJump.java
new file mode 100644
index 00000000000..435bbf8da02
--- /dev/null
+++ b/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Issue3522_CTabFolderDirtyIndicatorTextJump.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2026 Vogella GmbH 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:
+ * Vogella GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.swt.tests.manual;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.custom.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Press the two buttons alternately: the text of the selected tab must look exactly the
+ * same, no matter whether the dirty tab is repainted along with it or not.
+ */
+public class Issue3522_CTabFolderDirtyIndicatorTextJump {
+
+ public static void main(String[] args) {
+ Display display = new Display();
+ Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(2, false));
+
+ CTabFolder folder = new CTabFolder(shell, SWT.BORDER | SWT.CLOSE);
+ folder.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
+ folder.setUnselectedCloseVisible(false);
+ folder.setDirtyIndicatorStyle(true);
+
+ CTabItem selectedItem = new CTabItem(folder, SWT.NONE);
+ selectedItem.setText("TestClass.java");
+ CTabItem dirtyItem = new CTabItem(folder, SWT.NONE);
+ dirtyItem.setText("module-info.java");
+ dirtyItem.setShowDirty(true);
+ folder.setSelection(selectedItem);
+
+ Button redrawAll = new Button(shell, SWT.PUSH);
+ redrawAll.setText("Repaint all tabs (dirty indicator is painted first)");
+ redrawAll.addListener(SWT.Selection, event -> {
+ folder.redraw();
+ folder.update();
+ });
+
+ Button redrawSelected = new Button(shell, SWT.PUSH);
+ redrawSelected.setText("Repaint selected tab only");
+ redrawSelected.addListener(SWT.Selection, event -> {
+ Rectangle bounds = selectedItem.getBounds();
+ folder.redraw(bounds.x, bounds.y, bounds.width, bounds.height, false);
+ folder.update();
+ });
+
+ shell.setSize(700, 200);
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+}