From c6313e392bee01c42a04e5a4fe2cfe723b93667f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Oct 2025 06:07:04 +0000
Subject: [PATCH 1/4] Initial plan
From 5aa3c474eb6a97e7d2a8610a76c59151696d9cf1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Oct 2025 06:22:25 +0000
Subject: [PATCH 2/4] Add Display.isHeadless() method and create headless
 widget implementations
Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com>
---
 .../org/eclipse/swt/widgets/Display.java      |  17 +
 .../gtk/org/eclipse/swt/widgets/Display.java  |  17 +
 .../org/eclipse/swt/widgets/Button.java       | 141 ++++
 .../org/eclipse/swt/widgets/Canvas.java       |  58 ++
 .../org/eclipse/swt/widgets/Composite.java    | 209 ++++++
 .../org/eclipse/swt/widgets/Control.java      | 349 ++++++++++
 .../org/eclipse/swt/widgets/Decorations.java  | 110 ++++
 .../org/eclipse/swt/widgets/Display.java      | 605 ++++++++++++++++++
 .../org/eclipse/swt/widgets/Label.java        |  83 +++
 .../org/eclipse/swt/widgets/Scrollable.java   |  48 ++
 .../org/eclipse/swt/widgets/Shell.java        | 329 ++++++++++
 .../org/eclipse/swt/widgets/Widget.java       | 345 ++++++++++
 .../org/eclipse/swt/widgets/Display.java      |  17 +
 13 files changed, 2328 insertions(+)
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Button.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Canvas.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Composite.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Control.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Decorations.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Display.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Label.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Scrollable.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Shell.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Widget.java
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 abd8b2446dc..f769e24efe0 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	
@@ -1774,6 +1774,23 @@ public static boolean isSystemDarkTheme () {
 	return OS.isSystemDarkAppearance();
 }
 
+/**
+ * Returns true if SWT is running in headless mode, else
+ * returns false.
+ * 
+ * In headless mode, SWT widgets do not create native platform resources
+ * and operations are no-ops or return default values.
+ * 
+ *
+ * @return true if SWT is running in headless mode, else
+ *         returns false.
+ *
+ * @since 3.132
+ */
+public static boolean isHeadless () {
+	return false;
+}
+
 int getLastEventTime () {
 	NSEvent event = application != null ? application.currentEvent() : null;
 	if (event == null) return 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 5b52c106f48..5ae4b85a738 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	
@@ -2613,6 +2613,23 @@ public static boolean isSystemDarkTheme () {
 	return themeDark;
 }
 
+/**
+ * Returns true if SWT is running in headless mode, else
+ * returns false.
+ * 
+ * In headless mode, SWT widgets do not create native platform resources
+ * and operations are no-ops or return default values.
+ * 
+ *
+ * @return true if SWT is running in headless mode, else
+ *         returns false.
+ *
+ * @since 3.132
+ */
+public static boolean isHeadless () {
+	return false;
+}
+
 int getLastEventTime () {
 	return lastEventTime;
 }
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Button.java
new file mode 100644
index 00000000000..c835c8e73cf
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Button.java	
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Button for SWT.
+ */
+public class Button extends Control {
+	String text = "";
+	Image image;
+	boolean selected;
+	boolean grayed;
+	int alignment = SWT.CENTER;
+
+public Button(Composite parent, int style) {
+	super(parent, checkStyle(style));
+}
+
+static int checkStyle(int style) {
+	style = checkBits(style, SWT.PUSH, SWT.ARROW, SWT.CHECK, SWT.RADIO, SWT.TOGGLE, 0);
+	if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+		return checkBits(style, SWT.CENTER, SWT.LEFT, SWT.RIGHT, 0, 0, 0);
+	}
+	if ((style & (SWT.CHECK | SWT.RADIO)) != 0) {
+		return checkBits(style, SWT.LEFT, SWT.RIGHT, SWT.CENTER, 0, 0, 0);
+	}
+	if ((style & SWT.ARROW) != 0) {
+		style |= SWT.NO_FOCUS;
+		return checkBits(style, SWT.UP, SWT.DOWN, SWT.LEFT, SWT.RIGHT, 0, 0);
+	}
+	return style;
+}
+
+public void addSelectionListener(SelectionListener listener) {
+	checkWidget();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	TypedListener typedListener = new TypedListener(listener);
+	addListener(SWT.Selection, typedListener);
+	addListener(SWT.DefaultSelection, typedListener);
+}
+
+public int getAlignment() {
+	checkWidget();
+	if ((style & SWT.ARROW) != 0) {
+		if ((style & SWT.UP) != 0) return SWT.UP;
+		if ((style & SWT.DOWN) != 0) return SWT.DOWN;
+		if ((style & SWT.LEFT) != 0) return SWT.LEFT;
+		if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
+		return SWT.UP;
+	}
+	return alignment;
+}
+
+public boolean getGrayed() {
+	checkWidget();
+	if ((style & SWT.CHECK) == 0) return false;
+	return grayed;
+}
+
+public Image getImage() {
+	checkWidget();
+	return image;
+}
+
+public boolean getSelection() {
+	checkWidget();
+	if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return false;
+	return selected;
+}
+
+public String getText() {
+	checkWidget();
+	return text;
+}
+
+public void removeSelectionListener(SelectionListener listener) {
+	checkWidget();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (eventTable == null) return;
+	eventTable.unhook(SWT.Selection, listener);
+	eventTable.unhook(SWT.DefaultSelection, listener);
+}
+
+public void setAlignment(int alignment) {
+	checkWidget();
+	if ((style & SWT.ARROW) != 0) {
+		if ((style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) == 0) return;
+		style &= ~(SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
+		style |= alignment & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
+		return;
+	}
+	if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
+	this.alignment = alignment;
+}
+
+public void setGrayed(boolean grayed) {
+	checkWidget();
+	if ((style & SWT.CHECK) == 0) return;
+	this.grayed = grayed;
+}
+
+public void setImage(Image image) {
+	checkWidget();
+	if ((style & SWT.ARROW) != 0) return;
+	this.image = image;
+}
+
+public void setSelection(boolean selected) {
+	checkWidget();
+	if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return;
+	this.selected = selected;
+}
+
+public void setText(String string) {
+	checkWidget();
+	if (string == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if ((style & SWT.ARROW) != 0) return;
+	text = string;
+}
+
+@Override
+String getNameText() {
+	return getText();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Canvas.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Canvas.java
new file mode 100644
index 00000000000..853c01f8c2e
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Canvas.java	
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Canvas for SWT.
+ */
+public class Canvas extends Composite {
+	Caret caret;
+
+public Canvas() {
+	// No-op
+}
+
+public Canvas(Display display, int style) {
+	super(null, style);
+	this.display = display;
+}
+
+public Canvas(Composite parent, int style) {
+	super(parent, style);
+}
+
+public void drawBackground(GC gc, int x, int y, int width, int height) {
+	checkWidget();
+	// No-op in headless mode
+}
+
+public Caret getCaret() {
+	checkWidget();
+	return caret;
+}
+
+public void scroll(int destX, int destY, int x, int y, int width, int height, boolean all) {
+	checkWidget();
+	// No-op in headless mode
+}
+
+public void setCaret(Caret caret) {
+	checkWidget();
+	this.caret = caret;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Composite.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Composite.java
new file mode 100644
index 00000000000..dd93791edf6
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Composite.java	
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import java.util.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Composite for SWT.
+ */
+public class Composite extends Scrollable {
+	Layout layout;
+	Control[] tabList;
+	int layoutCount, backgroundMode;
+	List children = new ArrayList<>();
+
+public Composite() {
+	// No-op
+}
+
+public Composite(Composite parent, int style) {
+	super(parent, checkStyle(style));
+}
+
+static int checkStyle(int style) {
+	style &= ~SWT.TRANSPARENT;
+	return style;
+}
+
+void addChild(Control control) {
+	children.add(control);
+}
+
+void removeChild(Control control) {
+	children.remove(control);
+}
+
+public Control[] getChildren() {
+	checkWidget();
+	return children.toArray(new Control[children.size()]);
+}
+
+public int getBackgroundMode() {
+	checkWidget();
+	return backgroundMode;
+}
+
+public Layout getLayout() {
+	checkWidget();
+	return layout;
+}
+
+public boolean getLayoutDeferred() {
+	checkWidget();
+	return layoutCount > 0;
+}
+
+public Control[] getTabList() {
+	checkWidget();
+	if (tabList != null) return tabList;
+	int count = 0;
+	Control[] list = getChildren();
+	for (Control child : list) {
+		if (child.isTabGroup()) count++;
+	}
+	Control[] result = new Control[count];
+	int index = 0;
+	for (Control child : list) {
+		if (child.isTabGroup()) {
+			result[index++] = child;
+		}
+	}
+	return result;
+}
+
+public boolean isLayoutDeferred() {
+	checkWidget();
+	return findDeferredControl() != null;
+}
+
+Composite findDeferredControl() {
+	return layoutCount > 0 ? this : (parent != null ? parent.findDeferredControl() : null);
+}
+
+public void layout() {
+	checkWidget();
+	layout(true);
+}
+
+public void layout(boolean changed) {
+	checkWidget();
+	layout(changed, false);
+}
+
+public void layout(boolean changed, boolean all) {
+	checkWidget();
+	if (layout == null) return;
+	if (layoutCount == 0) {
+		layout.layout(this, changed);
+		if (all) {
+			for (Control child : children) {
+				if (child instanceof Composite) {
+					((Composite) child).layout(changed, all);
+				}
+			}
+		}
+	}
+}
+
+public void layout(Control[] changed) {
+	checkWidget();
+	if (changed == null) error(SWT.ERROR_INVALID_ARGUMENT);
+	layout(changed, SWT.NONE);
+}
+
+public void layout(Control[] changed, int flags) {
+	checkWidget();
+	if (changed != null) {
+		for (Control child : changed) {
+			if (child == null) error(SWT.ERROR_INVALID_ARGUMENT);
+			if (child.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+			if (child.parent != this) error(SWT.ERROR_INVALID_PARENT);
+		}
+	}
+	if (layout == null) return;
+	if ((flags & SWT.DEFER) != 0) {
+		setLayoutDeferred(true);
+		return;
+	}
+	layout.layout(this, (flags & SWT.CHANGED) != 0);
+}
+
+public void setBackgroundMode(int mode) {
+	checkWidget();
+	backgroundMode = mode;
+}
+
+public void setLayout(Layout layout) {
+	checkWidget();
+	this.layout = layout;
+}
+
+public void setLayoutDeferred(boolean defer) {
+	if (!defer) {
+		if (--layoutCount == 0) {
+			if ((state & LAYOUT_CHILD) != 0 || (state & LAYOUT_NEEDED) != 0) {
+				updateLayout(true);
+			}
+		}
+	} else {
+		layoutCount++;
+	}
+}
+
+void updateLayout(boolean all) {
+	Composite parent = findDeferredControl();
+	if (parent != null) {
+		parent.state |= LAYOUT_CHILD;
+		return;
+	}
+	if ((state & LAYOUT_NEEDED) != 0) {
+		boolean changed = (state & LAYOUT_CHANGED) != 0;
+		state &= ~(LAYOUT_NEEDED | LAYOUT_CHANGED);
+		layout(changed, all);
+	}
+	if (all) {
+		state &= ~LAYOUT_CHILD;
+		for (Control child : children) {
+			if (child instanceof Composite) {
+				((Composite) child).updateLayout(all);
+			}
+		}
+	}
+}
+
+public void setTabList(Control[] tabList) {
+	checkWidget();
+	if (tabList != null) {
+		for (Control control : tabList) {
+			if (control == null) error(SWT.ERROR_INVALID_ARGUMENT);
+			if (control.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+			if (control.parent != this) error(SWT.ERROR_INVALID_PARENT);
+		}
+		Control[] newList = new Control[tabList.length];
+		System.arraycopy(tabList, 0, newList, 0, tabList.length);
+		tabList = newList;
+	}
+	this.tabList = tabList;
+}
+
+@Override
+protected void checkSubclass() {
+	// Allow subclassing
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Control.java
new file mode 100644
index 00000000000..624864e71f3
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Control.java	
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Control for SWT.
+ */
+public abstract class Control extends Widget implements Drawable {
+	Composite parent;
+	String toolTipText;
+	Object layoutData;
+	Menu menu;
+	Cursor cursor;
+	Font font;
+	Color foreground, background;
+	Image backgroundImage;
+	boolean enabled = true;
+	boolean visible = true;
+	int x, y, width, height;
+
+public Control() {
+	// No-op
+}
+
+public Control(Composite parent, int style) {
+	super(parent, style);
+	this.parent = parent;
+	if (parent != null) {
+		parent.addChild(this);
+	}
+	width = DEFAULT_WIDTH;
+	height = DEFAULT_HEIGHT;
+}
+
+public Point computeSize(int wHint, int hHint) {
+	return computeSize(wHint, hHint, true);
+}
+
+public Point computeSize(int wHint, int hHint, boolean changed) {
+	checkWidget();
+	int width = DEFAULT_WIDTH;
+	int height = DEFAULT_HEIGHT;
+	if (wHint != SWT.DEFAULT) width = wHint;
+	if (hHint != SWT.DEFAULT) height = hHint;
+	return new Point(width, height);
+}
+
+public boolean forceFocus() {
+	checkWidget();
+	return false;
+}
+
+public Color getBackground() {
+	checkWidget();
+	if (background != null) return background;
+	return display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+}
+
+public Image getBackgroundImage() {
+	checkWidget();
+	return backgroundImage;
+}
+
+public Rectangle getBounds() {
+	checkWidget();
+	return new Rectangle(x, y, width, height);
+}
+
+public Cursor getCursor() {
+	checkWidget();
+	return cursor;
+}
+
+public boolean getEnabled() {
+	checkWidget();
+	return enabled;
+}
+
+public Font getFont() {
+	checkWidget();
+	if (font != null) return font;
+	return parent != null ? parent.getFont() : display.getSystemFont();
+}
+
+public Color getForeground() {
+	checkWidget();
+	if (foreground != null) return foreground;
+	return display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND);
+}
+
+public Object getLayoutData() {
+	checkWidget();
+	return layoutData;
+}
+
+public Point getLocation() {
+	checkWidget();
+	return new Point(x, y);
+}
+
+public Menu getMenu() {
+	checkWidget();
+	return menu;
+}
+
+public Composite getParent() {
+	checkWidget();
+	return parent;
+}
+
+public Shell getShell() {
+	checkWidget();
+	return parent != null ? parent.getShell() : null;
+}
+
+public Point getSize() {
+	checkWidget();
+	return new Point(width, height);
+}
+
+public String getToolTipText() {
+	checkWidget();
+	return toolTipText;
+}
+
+public boolean getVisible() {
+	checkWidget();
+	return visible;
+}
+
+@Override
+public boolean isEnabled() {
+	checkWidget();
+	return getEnabled() && (parent != null ? parent.isEnabled() : true);
+}
+
+public boolean isFocusControl() {
+	checkWidget();
+	return display.focusControl == this;
+}
+
+public boolean isVisible() {
+	checkWidget();
+	return getVisible() && (parent != null ? parent.isVisible() : true);
+}
+
+public boolean isReparentable() {
+	checkWidget();
+	return true;
+}
+
+boolean isTabGroup() {
+	Control[] tabList = parent.tabList;
+	if (tabList != null) {
+		for (Control control : tabList) {
+			if (control == this) return true;
+		}
+	}
+	int bits = SWT.NONE;
+	return (bits & style) != 0;
+}
+
+public void moveAbove(Control control) {
+	checkWidget();
+	// No-op in headless mode
+}
+
+public void moveBelow(Control control) {
+	checkWidget();
+	// No-op in headless mode
+}
+
+public void pack() {
+	pack(true);
+}
+
+public void pack(boolean changed) {
+	checkWidget();
+	setSize(computeSize(SWT.DEFAULT, SWT.DEFAULT, changed));
+}
+
+public void redraw() {
+	checkWidget();
+	// No-op in headless mode
+}
+
+public void redraw(int x, int y, int width, int height, boolean all) {
+	checkWidget();
+	// No-op in headless mode
+}
+
+@Override
+void releaseParent() {
+	if (parent != null) parent.removeChild(this);
+}
+
+public boolean setFocus() {
+	checkWidget();
+	if (!isEnabled() || !isVisible()) return false;
+	display.focusControl = this;
+	return true;
+}
+
+public void setBackground(Color color) {
+	checkWidget();
+	background = color;
+}
+
+public void setBackgroundImage(Image image) {
+	checkWidget();
+	backgroundImage = image;
+}
+
+public void setBounds(int x, int y, int width, int height) {
+	checkWidget();
+	this.x = x;
+	this.y = y;
+	this.width = width;
+	this.height = height;
+}
+
+public void setBounds(Rectangle rect) {
+	checkWidget();
+	if (rect == null) error(SWT.ERROR_NULL_ARGUMENT);
+	setBounds(rect.x, rect.y, rect.width, rect.height);
+}
+
+public void setCursor(Cursor cursor) {
+	checkWidget();
+	this.cursor = cursor;
+}
+
+public void setEnabled(boolean enabled) {
+	checkWidget();
+	this.enabled = enabled;
+}
+
+public void setFont(Font font) {
+	checkWidget();
+	this.font = font;
+}
+
+public void setForeground(Color color) {
+	checkWidget();
+	foreground = color;
+}
+
+public void setLayoutData(Object layoutData) {
+	checkWidget();
+	this.layoutData = layoutData;
+}
+
+public void setLocation(int x, int y) {
+	checkWidget();
+	this.x = x;
+	this.y = y;
+}
+
+public void setLocation(Point location) {
+	checkWidget();
+	if (location == null) error(SWT.ERROR_NULL_ARGUMENT);
+	setLocation(location.x, location.y);
+}
+
+public void setMenu(Menu menu) {
+	checkWidget();
+	this.menu = menu;
+}
+
+public boolean setParent(Composite parent) {
+	checkWidget();
+	if (parent == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (parent.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+	if (this.parent == parent) return true;
+	if (this.parent != null) this.parent.removeChild(this);
+	this.parent = parent;
+	parent.addChild(this);
+	return true;
+}
+
+public void setSize(int width, int height) {
+	checkWidget();
+	this.width = width;
+	this.height = height;
+}
+
+public void setSize(Point size) {
+	checkWidget();
+	if (size == null) error(SWT.ERROR_NULL_ARGUMENT);
+	setSize(size.x, size.y);
+}
+
+public void setToolTipText(String string) {
+	checkWidget();
+	toolTipText = string;
+}
+
+public void setVisible(boolean visible) {
+	checkWidget();
+	this.visible = visible;
+}
+
+public Point toControl(int x, int y) {
+	checkWidget();
+	return new Point(x - this.x, y - this.y);
+}
+
+public Point toControl(Point point) {
+	checkWidget();
+	if (point == null) error(SWT.ERROR_NULL_ARGUMENT);
+	return toControl(point.x, point.y);
+}
+
+public Point toDisplay(int x, int y) {
+	checkWidget();
+	return new Point(x + this.x, y + this.y);
+}
+
+public Point toDisplay(Point point) {
+	checkWidget();
+	if (point == null) error(SWT.ERROR_NULL_ARGUMENT);
+	return toDisplay(point.x, point.y);
+}
+
+public void update() {
+	checkWidget();
+	// No-op in headless mode
+}
+
+@Override
+public boolean isAutoScalable() {
+	return true;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Decorations.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Decorations.java
new file mode 100644
index 00000000000..695358e194b
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Decorations.java	
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Decorations for SWT.
+ */
+public class Decorations extends Canvas {
+	String text = "";
+	Image image;
+	Image[] images = new Image[0];
+	Menu menuBar;
+	Button defaultButton, saveDefault;
+
+public Decorations() {
+	// No-op
+}
+
+public Decorations(Display display, int style) {
+	super(display, style);
+}
+
+public Decorations(Composite parent, int style) {
+	super(parent, style);
+}
+
+public Button getDefaultButton() {
+	checkWidget();
+	return defaultButton;
+}
+
+public Image getImage() {
+	checkWidget();
+	return image;
+}
+
+public Image[] getImages() {
+	checkWidget();
+	if (images == null) return new Image[0];
+	Image[] result = new Image[images.length];
+	System.arraycopy(images, 0, result, 0, images.length);
+	return result;
+}
+
+public Menu getMenuBar() {
+	checkWidget();
+	return menuBar;
+}
+
+public String getText() {
+	checkWidget();
+	return text;
+}
+
+public void setDefaultButton(Button button) {
+	checkWidget();
+	if (button != null) {
+		if (button.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+		if (button.getShell() != this) error(SWT.ERROR_INVALID_PARENT);
+		if ((button.style & SWT.PUSH) == 0) error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	defaultButton = button;
+}
+
+public void setImage(Image image) {
+	checkWidget();
+	this.image = image;
+}
+
+public void setImages(Image[] images) {
+	checkWidget();
+	if (images != null) {
+		this.images = new Image[images.length];
+		System.arraycopy(images, 0, this.images, 0, images.length);
+	} else {
+		this.images = new Image[0];
+	}
+}
+
+public void setMenuBar(Menu menu) {
+	checkWidget();
+	if (menuBar == menu) return;
+	if (menu != null) {
+		if ((menu.style & SWT.BAR) == 0) error(SWT.ERROR_MENU_NOT_BAR);
+		if (menu.parent != this) error(SWT.ERROR_INVALID_PARENT);
+	}
+	menuBar = menu;
+}
+
+public void setText(String string) {
+	checkWidget();
+	if (string == null) error(SWT.ERROR_NULL_ARGUMENT);
+	text = string;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Display.java
new file mode 100644
index 00000000000..0d0ed884998
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Display.java	
@@ -0,0 +1,605 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.function.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Display for SWT.
+ * This implementation provides no-op or default implementations
+ * for running SWT code in a headless environment.
+ */
+public class Display extends Device implements Executor {
+	
+	static Display Default;
+	static String APP_NAME = "SWT";
+	static String APP_VERSION = "";
+	
+	/* Widget Table */
+	Widget[] widgetTable;
+	int freeSlot;
+	static final int GROW_SIZE = 1024;
+	
+	/* Synchronization */
+	Synchronizer synchronizer = new Synchronizer(this);
+	Consumer runtimeExceptionHandler = DefaultExceptionHandler.RUNTIME_EXCEPTION_HANDLER;
+	Consumer errorHandler = DefaultExceptionHandler.RUNTIME_ERROR_HANDLER;
+	Thread thread;
+	
+	/* Shells */
+	Shell[] shells = new Shell[0];
+	Shell activeShell;
+	
+	/* Modality */
+	Shell[] modalShells;
+	
+	/* Disposal */
+	Runnable[] disposeList;
+	
+	/* Event Handling */
+	EventTable eventTable, filterTable;
+	Event[] eventQueue;
+	
+	/* Timers */
+	int[] timerIds;
+	Runnable[] timerList;
+	int nextTimerId = 1;
+	
+	/* Deferred Layout */
+	Composite[] layoutDeferred;
+	int layoutDeferredCount;
+	
+	/* System Resources */
+	Font systemFont;
+	
+	/* Focus */
+	Control focusControl;
+	
+	/* Disposed flag */
+	boolean disposed;
+	
+	/* Package prefix */
+	static final String PACKAGE_PREFIX = "org.eclipse.swt.widgets.";
+
+public Display() {
+	this(null);
+}
+
+public Display(DeviceData data) {
+	super(data);
+	thread = Thread.currentThread();
+	synchronized (Device.class) {
+		if (Default == null) Default = this;
+	}
+	widgetTable = new Widget[GROW_SIZE];
+}
+
+@Override
+protected void create(DeviceData data) {
+	checkSubclass();
+	synchronizer = new Synchronizer(this);
+	systemFont = new Font(this, new FontData("Sans", 10, SWT.NORMAL));
+}
+
+@Override
+protected void init() {
+	super.init();
+}
+
+public void addFilter(int eventType, Listener listener) {
+	checkDevice();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (filterTable == null) filterTable = new EventTable();
+	filterTable.hook(eventType, listener);
+}
+
+public void addListener(int eventType, Listener listener) {
+	checkDevice();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (eventTable == null) eventTable = new EventTable();
+	eventTable.hook(eventType, listener);
+}
+
+public void asyncExec(Runnable runnable) {
+	synchronized (Device.class) {
+		if (isDisposed()) error(SWT.ERROR_DEVICE_DISPOSED);
+		synchronizer.asyncExec(runnable);
+	}
+}
+
+@Override
+public void execute(Runnable runnable) {
+	Objects.requireNonNull(runnable);
+	if (thread == Thread.currentThread()) {
+		runnable.run();
+	} else {
+		syncExec(runnable);
+	}
+}
+
+public void beep() {
+	checkDevice();
+	// No-op in headless mode
+}
+
+@Override
+public void close() {
+	checkDevice();
+	Event event = new Event();
+	sendEvent(SWT.Close, event);
+	if (event.doit) dispose();
+}
+
+@Override
+protected void destroy() {
+	if (disposed) return;
+	disposed = true;
+	Shell[] shells = getShells();
+	for (Shell shell : shells) {
+		if (!shell.isDisposed()) shell.dispose();
+	}
+}
+
+public void disposeExec(Runnable runnable) {
+	checkDevice();
+	if (disposeList == null) disposeList = new Runnable[4];
+	for (int i = 0; i < disposeList.length; i++) {
+		if (disposeList[i] == null) {
+			disposeList[i] = runnable;
+			return;
+		}
+	}
+	Runnable[] newList = new Runnable[disposeList.length + 4];
+	System.arraycopy(disposeList, 0, newList, 0, disposeList.length);
+	newList[disposeList.length] = runnable;
+	disposeList = newList;
+}
+
+public static Display findDisplay(Thread thread) {
+	synchronized (Device.class) {
+		if (Default != null && Default.thread == thread) {
+			return Default;
+		}
+		return null;
+	}
+}
+
+public Widget findWidget(long handle) {
+	checkDevice();
+	return null;
+}
+
+public Widget findWidget(long handle, long id) {
+	checkDevice();
+	return null;
+}
+
+public Widget findWidget(Widget widget, long id) {
+	checkDevice();
+	return null;
+}
+
+public Shell getActiveShell() {
+	checkDevice();
+	return activeShell;
+}
+
+public static String getAppName() {
+	return APP_NAME;
+}
+
+public static String getAppVersion() {
+	return APP_VERSION;
+}
+
+public Rectangle getBounds() {
+	checkDevice();
+	return new Rectangle(0, 0, 1024, 768);
+}
+
+public Rectangle getClientArea() {
+	checkDevice();
+	return new Rectangle(0, 0, 1024, 768);
+}
+
+public static Display getCurrent() {
+	return findDisplay(Thread.currentThread());
+}
+
+public Control getCursorControl() {
+	checkDevice();
+	return null;
+}
+
+public Point getCursorLocation() {
+	checkDevice();
+	return new Point(0, 0);
+}
+
+public Point[] getCursorSizes() {
+	checkDevice();
+	return new Point[] { new Point(16, 16), new Point(32, 32) };
+}
+
+public Object getData(String key) {
+	checkDevice();
+	if (key == null) error(SWT.ERROR_NULL_ARGUMENT);
+	return super.getData(key);
+}
+
+public Object getData() {
+	checkDevice();
+	return super.getData();
+}
+
+public static Display getDefault() {
+	synchronized (Device.class) {
+		if (Default == null) Default = new Display();
+		return Default;
+	}
+}
+
+public int getDismissalAlignment() {
+	checkDevice();
+	return SWT.LEFT;
+}
+
+public int getDoubleClickTime() {
+	checkDevice();
+	return 500;
+}
+
+public Control getFocusControl() {
+	checkDevice();
+	return focusControl;
+}
+
+public boolean getHighContrast() {
+	checkDevice();
+	return false;
+}
+
+public int getDepth() {
+	return 24;
+}
+
+public int getIconDepth() {
+	return 24;
+}
+
+public Point[] getIconSizes() {
+	checkDevice();
+	return new Point[] { new Point(16, 16), new Point(32, 32) };
+}
+
+public Menu getMenuBar() {
+	checkDevice();
+	return null;
+}
+
+public Monitor[] getMonitors() {
+	checkDevice();
+	Monitor monitor = new Monitor();
+	Rectangle bounds = new Rectangle(0, 0, 1024, 768);
+	monitor.handle = 0;
+	monitor.x = bounds.x;
+	monitor.y = bounds.y;
+	monitor.width = bounds.width;
+	monitor.height = bounds.height;
+	monitor.clientX = bounds.x;
+	monitor.clientY = bounds.y;
+	monitor.clientWidth = bounds.width;
+	monitor.clientHeight = bounds.height;
+	monitor.zoom = 100;
+	return new Monitor[] { monitor };
+}
+
+public Monitor getPrimaryMonitor() {
+	checkDevice();
+	return getMonitors()[0];
+}
+
+public Shell[] getShells() {
+	checkDevice();
+	return shells;
+}
+
+public Thread getSyncThread() {
+	synchronized (Device.class) {
+		if (isDisposed()) error(SWT.ERROR_DEVICE_DISPOSED);
+		return synchronizer.syncThread;
+	}
+}
+
+@Override
+public Font getSystemFont() {
+	checkDevice();
+	return systemFont;
+}
+
+public Thread getThread() {
+	synchronized (Device.class) {
+		if (isDisposed()) error(SWT.ERROR_DEVICE_DISPOSED);
+		return thread;
+	}
+}
+
+public static boolean isSystemDarkTheme() {
+	return false;
+}
+
+public static boolean isHeadless() {
+	return true;
+}
+
+public boolean readAndDispatch() {
+	checkDevice();
+	return runAsyncMessages(false);
+}
+
+@Override
+protected void release() {
+	sendEvent(SWT.Dispose, new Event());
+	Shell[] shells = getShells();
+	for (Shell shell : shells) {
+		if (!shell.isDisposed()) shell.dispose();
+	}
+	if (eventTable != null) eventTable.unhook(SWT.Dispose, null);
+	super.release();
+	releaseDisplay();
+}
+
+void releaseDisplay() {
+	if (disposeList != null) {
+		for (Runnable runnable : disposeList) {
+			if (runnable != null) {
+				try {
+					runnable.run();
+				} catch (RuntimeException exception) {
+					runtimeExceptionHandler.accept(exception);
+				} catch (Error error) {
+					errorHandler.accept(error);
+				}
+			}
+		}
+	}
+	disposeList = null;
+	synchronizer.releaseSynchronizer();
+	synchronizer = null;
+	thread = null;
+	widgetTable = null;
+}
+
+void removeWidget(long handle) {
+	// No-op in headless mode
+}
+
+public void removeFilter(int eventType, Listener listener) {
+	checkDevice();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (filterTable == null) return;
+	filterTable.unhook(eventType, listener);
+	if (filterTable.size() == 0) filterTable = null;
+}
+
+public void removeListener(int eventType, Listener listener) {
+	checkDevice();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (eventTable == null) return;
+	eventTable.unhook(eventType, listener);
+}
+
+boolean runAsyncMessages(boolean all) {
+	return synchronizer.runAsyncMessages(all);
+}
+
+boolean runDeferredLayouts() {
+	if (layoutDeferredCount != 0) {
+		Composite[] temp = layoutDeferred;
+		int count = layoutDeferredCount;
+		layoutDeferred = null;
+		layoutDeferredCount = 0;
+		for (int i = 0; i < count; i++) {
+			Composite comp = temp[i];
+			if (!comp.isDisposed()) comp.setLayoutDeferred(false);
+		}
+		return true;
+	}
+	return false;
+}
+
+boolean runDeferredEvents() {
+	boolean run = false;
+	if (runDeferredLayouts()) run = true;
+	return run;
+}
+
+void sendEvent(int eventType, Event event) {
+	if (eventTable == null && filterTable == null) return;
+	if (event == null) event = new Event();
+	event.display = this;
+	event.type = eventType;
+	if (event.time == 0) event.time = (int) System.currentTimeMillis();
+	if (filterTable != null) filterTable.sendEvent(event);
+	if (eventTable != null) eventTable.sendEvent(event);
+}
+
+public static void setAppName(String name) {
+	APP_NAME = name;
+}
+
+public static void setAppVersion(String version) {
+	APP_VERSION = version;
+}
+
+public void setData(String key, Object value) {
+	checkDevice();
+	if (key == null) error(SWT.ERROR_NULL_ARGUMENT);
+	super.setData(key, value);
+}
+
+public void setData(Object data) {
+	checkDevice();
+	super.setData(data);
+}
+
+public void setRuntimeExceptionHandler(Consumer handler) {
+	checkDevice();
+	if (handler == null) error(SWT.ERROR_NULL_ARGUMENT);
+	runtimeExceptionHandler = handler;
+}
+
+public void setErrorHandler(Consumer handler) {
+	checkDevice();
+	if (handler == null) error(SWT.ERROR_NULL_ARGUMENT);
+	errorHandler = handler;
+}
+
+public boolean sleep() {
+	checkDevice();
+	return runAsyncMessages(false) || runDeferredEvents();
+}
+
+public void syncExec(Runnable runnable) {
+	synchronized (Device.class) {
+		if (isDisposed()) error(SWT.ERROR_DEVICE_DISPOSED);
+		synchronizer.syncExec(runnable);
+	}
+}
+
+public int timerExec(int milliseconds, Runnable runnable) {
+	checkDevice();
+	if (runnable == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (timerList == null) {
+		timerList = new Runnable[4];
+		timerIds = new int[4];
+	}
+	int timerId = nextTimerId++;
+	int index = 0;
+	while (index < timerList.length) {
+		if (timerList[index] == null) break;
+		index++;
+	}
+	if (index == timerList.length) {
+		Runnable[] newTimerList = new Runnable[timerList.length + 4];
+		System.arraycopy(timerList, 0, newTimerList, 0, timerList.length);
+		timerList = newTimerList;
+		int[] newTimerIds = new int[timerIds.length + 4];
+		System.arraycopy(timerIds, 0, newTimerIds, 0, timerIds.length);
+		timerIds = newTimerIds;
+	}
+	timerList[index] = runnable;
+	timerIds[index] = timerId;
+	
+	// Schedule the timer to run
+	new Timer().schedule(new TimerTask() {
+		@Override
+		public void run() {
+			asyncExec(runnable);
+		}
+	}, milliseconds);
+	
+	return timerId;
+}
+
+public void wake() {
+	synchronized (Device.class) {
+		if (isDisposed()) error(SWT.ERROR_DEVICE_DISPOSED);
+		// No-op in headless mode
+	}
+}
+
+void addShell(Shell shell) {
+	int length = shells.length;
+	Shell[] newShells = new Shell[length + 1];
+	System.arraycopy(shells, 0, newShells, 0, length);
+	newShells[length] = shell;
+	shells = newShells;
+}
+
+void removeShell(Shell shell) {
+	int length = shells.length;
+	for (int i = 0; i < length; i++) {
+		if (shells[i] == shell) {
+			Shell[] newShells = new Shell[length - 1];
+			System.arraycopy(shells, 0, newShells, 0, i);
+			System.arraycopy(shells, i + 1, newShells, i, length - i - 1);
+			shells = newShells;
+			break;
+		}
+	}
+}
+
+void addLayoutDeferred(Composite comp) {
+	if (layoutDeferred == null) layoutDeferred = new Composite[64];
+	if (layoutDeferredCount == layoutDeferred.length) {
+		Composite[] temp = new Composite[layoutDeferred.length + 64];
+		System.arraycopy(layoutDeferred, 0, temp, 0, layoutDeferred.length);
+		layoutDeferred = temp;
+	}
+	layoutDeferred[layoutDeferredCount++] = comp;
+}
+
+void removeLayoutDeferred(Composite comp) {
+	if (layoutDeferred == null) return;
+	for (int i = 0; i < layoutDeferredCount; i++) {
+		if (layoutDeferred[i] == comp) {
+			layoutDeferredCount--;
+			System.arraycopy(layoutDeferred, i + 1, layoutDeferred, i, layoutDeferredCount - i);
+			layoutDeferred[layoutDeferredCount] = null;
+			break;
+		}
+	}
+}
+
+boolean filterEvent(Event event) {
+	if (filterTable != null) {
+		filterTable.sendEvent(event);
+	}
+	return false;
+}
+
+boolean filters(int eventType) {
+	if (filterTable == null) return false;
+	return filterTable.hooks(eventType);
+}
+
+void postEvent(Event event) {
+	if (eventQueue == null) eventQueue = new Event[4];
+	int index = 0;
+	int length = eventQueue.length;
+	while (index < length) {
+		if (eventQueue[index] == null) break;
+		index++;
+	}
+	if (index == length) {
+		Event[] newQueue = new Event[length + 4];
+		System.arraycopy(eventQueue, 0, newQueue, 0, length);
+		eventQueue = newQueue;
+	}
+	eventQueue[index] = event;
+}
+
+static boolean isValidClass(Class> clazz) {
+	String name = clazz.getName();
+	int index = name.lastIndexOf('.');
+	return name.substring(0, index + 1).equals(PACKAGE_PREFIX);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Label.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Label.java
new file mode 100644
index 00000000000..b8a14659b83
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Label.java	
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Label for SWT.
+ */
+public class Label extends Control {
+	String text = "";
+	Image image;
+	int alignment = SWT.LEFT;
+
+public Label(Composite parent, int style) {
+	super(parent, checkStyle(style));
+}
+
+static int checkStyle(int style) {
+	style |= SWT.NO_FOCUS;
+	if ((style & SWT.SEPARATOR) != 0) {
+		style = checkBits(style, SWT.VERTICAL, SWT.HORIZONTAL, 0, 0, 0, 0);
+		return checkBits(style, SWT.SHADOW_OUT, SWT.SHADOW_IN, SWT.SHADOW_NONE, 0, 0, 0);
+	}
+	return checkBits(style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
+}
+
+public int getAlignment() {
+	checkWidget();
+	if ((style & SWT.SEPARATOR) != 0) return 0;
+	return alignment;
+}
+
+public Image getImage() {
+	checkWidget();
+	return image;
+}
+
+public String getText() {
+	checkWidget();
+	return text;
+}
+
+public void setAlignment(int alignment) {
+	checkWidget();
+	if ((style & SWT.SEPARATOR) != 0) return;
+	if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
+	this.alignment = alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
+}
+
+public void setImage(Image image) {
+	checkWidget();
+	if ((style & SWT.SEPARATOR) != 0) return;
+	this.image = image;
+	this.text = "";
+}
+
+public void setText(String string) {
+	checkWidget();
+	if (string == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if ((style & SWT.SEPARATOR) != 0) return;
+	text = string;
+	this.image = null;
+}
+
+@Override
+String getNameText() {
+	return getText();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Scrollable.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Scrollable.java
new file mode 100644
index 00000000000..d81382dfda8
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Scrollable.java	
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Scrollable for SWT.
+ */
+public abstract class Scrollable extends Control {
+	ScrollBar horizontalBar, verticalBar;
+
+public Scrollable() {
+	// No-op
+}
+
+public Scrollable(Composite parent, int style) {
+	super(parent, style);
+}
+
+public Rectangle getClientArea() {
+	checkWidget();
+	return new Rectangle(0, 0, width, height);
+}
+
+public ScrollBar getHorizontalBar() {
+	checkWidget();
+	return horizontalBar;
+}
+
+public ScrollBar getVerticalBar() {
+	checkWidget();
+	return verticalBar;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Shell.java
new file mode 100644
index 00000000000..465fe127ba4
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Shell.java	
@@ -0,0 +1,329 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Shell for SWT.
+ */
+public class Shell extends Decorations {
+	boolean opened;
+	String text = "";
+	Image image;
+	Image[] images = new Image[0];
+	int alpha = 255;
+	Region region;
+	int minWidth = 0, minHeight = 0;
+	int maxWidth = Integer.MAX_VALUE, maxHeight = Integer.MAX_VALUE;
+	boolean modified;
+	boolean fullScreen;
+
+public Shell() {
+	this((Display) null, SWT.SHELL_TRIM);
+}
+
+public Shell(int style) {
+	this((Display) null, style);
+}
+
+public Shell(Display display) {
+	this(display, SWT.SHELL_TRIM);
+}
+
+public Shell(Display display, int style) {
+	super(display, checkStyle(display, style));
+	if (display == null) display = Display.getCurrent();
+	if (display == null) display = Display.getDefault();
+	this.display = display;
+	createWidget();
+}
+
+public Shell(Shell parent) {
+	this(parent, SWT.DIALOG_TRIM);
+}
+
+public Shell(Shell parent, int style) {
+	super(parent, checkStyle(parent, style));
+	if (parent != null) {
+		this.display = parent.display;
+		if (this.parent == null) this.parent = parent;
+	}
+	createWidget();
+}
+
+void createWidget() {
+	display.addShell(this);
+	width = 200;
+	height = 200;
+}
+
+static int checkStyle(Display display, int style) {
+	style = checkBits(style, SWT.ON_TOP, SWT.TOOL, SWT.NO_TRIM, 0, 0, 0);
+	if ((style & (SWT.ON_TOP | SWT.TOOL)) != 0) {
+		if ((style & SWT.CLOSE) != 0) style |= SWT.TITLE;
+	}
+	if ((style & SWT.NO_TRIM) != 0) {
+		return style & ~(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX | SWT.RESIZE | SWT.BORDER);
+	}
+	if ((style & (SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX | SWT.RESIZE | SWT.BORDER)) == 0) {
+		style |= SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX | SWT.RESIZE | SWT.BORDER;
+	}
+	return style;
+}
+
+static int checkStyle(Shell parent, int style) {
+	if ((style & SWT.ON_TOP) != 0) style &= ~SWT.SHELL_TRIM;
+	int mask = SWT.SYSTEM_MODAL | SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL;
+	if ((style & SWT.SHEET) != 0) {
+		style &= ~SWT.SHEET;
+		style |= (parent != null) ? SWT.DIALOG_TRIM : SWT.NONE;
+		if ((style & mask) == 0) {
+			style |= (parent != null) ? SWT.APPLICATION_MODAL : SWT.NONE;
+		}
+	}
+	int bits = style & ~mask;
+	if ((style & SWT.SYSTEM_MODAL) != 0) return bits | SWT.SYSTEM_MODAL;
+	if ((style & SWT.APPLICATION_MODAL) != 0) return bits | SWT.APPLICATION_MODAL;
+	if ((style & SWT.PRIMARY_MODAL) != 0) return bits | SWT.PRIMARY_MODAL;
+	return bits;
+}
+
+public void addShellListener(ShellListener listener) {
+	checkWidget();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	TypedListener typedListener = new TypedListener(listener);
+	addListener(SWT.Close, typedListener);
+	addListener(SWT.Iconify, typedListener);
+	addListener(SWT.Deiconify, typedListener);
+	addListener(SWT.Activate, typedListener);
+	addListener(SWT.Deactivate, typedListener);
+}
+
+public void close() {
+	checkWidget();
+	Event event = new Event();
+	sendEvent(SWT.Close, event);
+	if (event.doit && !isDisposed()) dispose();
+}
+
+public void dispose() {
+	if (isDisposed()) return;
+	display.removeShell(this);
+	super.dispose();
+}
+
+public int getAlpha() {
+	checkWidget();
+	return alpha;
+}
+
+public Rectangle getBounds() {
+	checkWidget();
+	return new Rectangle(x, y, width, height);
+}
+
+public boolean getFullScreen() {
+	checkWidget();
+	return fullScreen;
+}
+
+public Image getImage() {
+	checkWidget();
+	return image;
+}
+
+public Image[] getImages() {
+	checkWidget();
+	if (images == null) return new Image[0];
+	Image[] result = new Image[images.length];
+	System.arraycopy(images, 0, result, 0, images.length);
+	return result;
+}
+
+public boolean getMaximized() {
+	checkWidget();
+	return false;
+}
+
+public Point getMaximumSize() {
+	checkWidget();
+	return new Point(maxWidth, maxHeight);
+}
+
+public boolean getMinimized() {
+	checkWidget();
+	return false;
+}
+
+public Point getMinimumSize() {
+	checkWidget();
+	return new Point(minWidth, minHeight);
+}
+
+public boolean getModified() {
+	checkWidget();
+	return modified;
+}
+
+public Region getRegion() {
+	checkWidget();
+	return region;
+}
+
+@Override
+public Shell getShell() {
+	checkWidget();
+	return this;
+}
+
+public Shell[] getShells() {
+	checkWidget();
+	int count = 0;
+	Shell[] allShells = display.getShells();
+	for (Shell shell : allShells) {
+		Control control = shell;
+		while (control != null && control != this) {
+			control = control.parent;
+		}
+		if (control == this) count++;
+	}
+	int index = 0;
+	Shell[] result = new Shell[count];
+	for (Shell shell : allShells) {
+		Control control = shell;
+		while (control != null && control != this) {
+			control = control.parent;
+		}
+		if (control == this) {
+			result[index++] = shell;
+		}
+	}
+	return result;
+}
+
+public String getText() {
+	checkWidget();
+	return text;
+}
+
+public void open() {
+	checkWidget();
+	setVisible(true);
+	opened = true;
+}
+
+public void removeShellListener(ShellListener listener) {
+	checkWidget();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (eventTable == null) return;
+	eventTable.unhook(SWT.Close, listener);
+	eventTable.unhook(SWT.Iconify, listener);
+	eventTable.unhook(SWT.Deiconify, listener);
+	eventTable.unhook(SWT.Activate, listener);
+	eventTable.unhook(SWT.Deactivate, listener);
+}
+
+public void setActive() {
+	checkWidget();
+	display.activeShell = this;
+}
+
+public void setAlpha(int alpha) {
+	checkWidget();
+	this.alpha = alpha;
+}
+
+public void setEnabled(boolean enabled) {
+	checkWidget();
+	this.enabled = enabled;
+}
+
+public void setFullScreen(boolean fullScreen) {
+	checkWidget();
+	this.fullScreen = fullScreen;
+}
+
+public void setImage(Image image) {
+	checkWidget();
+	this.image = image;
+}
+
+public void setImages(Image[] images) {
+	checkWidget();
+	if (images != null) {
+		this.images = new Image[images.length];
+		System.arraycopy(images, 0, this.images, 0, images.length);
+	} else {
+		this.images = new Image[0];
+	}
+}
+
+public void setMaximized(boolean maximized) {
+	checkWidget();
+	// No-op in headless mode
+}
+
+public void setMaximumSize(int width, int height) {
+	checkWidget();
+	maxWidth = width;
+	maxHeight = height;
+}
+
+public void setMaximumSize(Point size) {
+	checkWidget();
+	if (size == null) error(SWT.ERROR_NULL_ARGUMENT);
+	setMaximumSize(size.x, size.y);
+}
+
+public void setMinimized(boolean minimized) {
+	checkWidget();
+	// No-op in headless mode
+}
+
+public void setMinimumSize(int width, int height) {
+	checkWidget();
+	minWidth = width;
+	minHeight = height;
+}
+
+public void setMinimumSize(Point size) {
+	checkWidget();
+	if (size == null) error(SWT.ERROR_NULL_ARGUMENT);
+	setMinimumSize(size.x, size.y);
+}
+
+public void setModified(boolean modified) {
+	checkWidget();
+	this.modified = modified;
+}
+
+public void setRegion(Region region) {
+	checkWidget();
+	this.region = region;
+}
+
+public void setText(String string) {
+	checkWidget();
+	if (string == null) error(SWT.ERROR_NULL_ARGUMENT);
+	text = string;
+}
+
+@Override
+protected void checkSubclass() {
+	// Allow subclassing
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Widget.java
new file mode 100644
index 00000000000..fd6a5c15a9f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Widget.java	
@@ -0,0 +1,345 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Widget for SWT.
+ */
+public abstract class Widget {
+	public long handle;
+	int style, state;
+	Display display;
+	EventTable eventTable;
+	Object data;
+	
+	/* Global state flags */
+	static final int DISPOSED = 1<<0;
+	static final int CANVAS = 1<<1;
+	static final int KEYED_DATA = 1<<2;
+	static final int HANDLE = 1<<3;
+	static final int DISABLED = 1<<4;
+	static final int MENU = 1<<5;
+	static final int OBSCURED = 1<<6;
+	static final int MOVED = 1<<7;
+	static final int RESIZED = 1<<8;
+	static final int ZERO_WIDTH = 1<<9;
+	static final int ZERO_HEIGHT = 1<<10;
+	static final int HIDDEN = 1<<11;
+	static final int FOREGROUND = 1<<12;
+	static final int BACKGROUND = 1<<13;
+	static final int FONT = 1<<14;
+	static final int PARENT_BACKGROUND = 1<<15;
+	static final int THEME_BACKGROUND = 1<<16;
+	static final int LAYOUT_NEEDED = 1<<17;
+	static final int LAYOUT_CHANGED = 1<<18;
+	static final int LAYOUT_CHILD = 1<<19;
+	static final int RELEASED = 1<<20;
+	static final int DISPOSE_SENT = 1<<21;
+	static final int FOREIGN_HANDLE = 1<<22;
+	static final int DRAG_DETECT = 1<<23;
+	static final int SKIN_NEEDED = 1<<24;
+	
+	/* Default sizes */
+	static final int DEFAULT_WIDTH = 64;
+	static final int DEFAULT_HEIGHT = 64;
+
+public Widget() {
+	// No-op
+}
+
+public Widget(Widget parent, int style) {
+	checkSubclass();
+	checkParent(parent);
+	this.style = style;
+	display = parent.display;
+}
+
+protected void checkSubclass() {
+	if (!isValidSubclass()) error(SWT.ERROR_INVALID_SUBCLASS);
+}
+
+protected void checkParent(Widget parent) {
+	if (parent == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (parent.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+	if (parent.display != display) error(SWT.ERROR_INVALID_PARENT);
+}
+
+protected void checkWidget() {
+	Display display = this.display;
+	if (display == null) error(SWT.ERROR_WIDGET_DISPOSED);
+	if (display.thread != Thread.currentThread()) error(SWT.ERROR_THREAD_INVALID_ACCESS);
+	if ((state & DISPOSED) != 0) error(SWT.ERROR_WIDGET_DISPOSED);
+}
+
+static int checkBits(int style, int int0, int int1, int int2, int int3, int int4, int int5) {
+	int mask = int0 | int1 | int2 | int3 | int4 | int5;
+	if ((style & mask) == 0) style |= int0;
+	if ((style & int0) != 0) style = (style & ~mask) | int0;
+	if ((style & int1) != 0) style = (style & ~mask) | int1;
+	if ((style & int2) != 0) style = (style & ~mask) | int2;
+	if ((style & int3) != 0) style = (style & ~mask) | int3;
+	if ((style & int4) != 0) style = (style & ~mask) | int4;
+	if ((style & int5) != 0) style = (style & ~mask) | int5;
+	return style;
+}
+
+public void addListener(int eventType, Listener listener) {
+	checkWidget();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	_addListener(eventType, listener);
+}
+
+void _addListener(int eventType, Listener listener) {
+	if (eventTable == null) eventTable = new EventTable();
+	eventTable.hook(eventType, listener);
+}
+
+public void addDisposeListener(DisposeListener listener) {
+	checkWidget();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	TypedListener typedListener = new TypedListener(listener);
+	addListener(SWT.Dispose, typedListener);
+}
+
+public void dispose() {
+	if (isDisposed()) return;
+	if (!isValidThread()) error(SWT.ERROR_THREAD_INVALID_ACCESS);
+	release(true);
+}
+
+void error(int code) {
+	SWT.error(code);
+}
+
+public Object getData() {
+	checkWidget();
+	return (state & KEYED_DATA) != 0 ? ((Object[]) data)[0] : data;
+}
+
+public Object getData(String key) {
+	checkWidget();
+	if (key == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if ((state & KEYED_DATA) != 0) {
+		Object[] table = (Object[]) data;
+		for (int i = 1; i < table.length; i += 2) {
+			if (key.equals(table[i])) return table[i + 1];
+		}
+	}
+	return null;
+}
+
+public Display getDisplay() {
+	Display display = this.display;
+	if (display == null) error(SWT.ERROR_WIDGET_DISPOSED);
+	return display;
+}
+
+public int getStyle() {
+	checkWidget();
+	return style;
+}
+
+public boolean isDisposed() {
+	return (state & DISPOSED) != 0;
+}
+
+public boolean isListening(int eventType) {
+	checkWidget();
+	return eventTable != null && eventTable.hooks(eventType);
+}
+
+boolean isValidSubclass() {
+	return Display.isValidClass(getClass());
+}
+
+boolean isValidThread() {
+	return getDisplay().thread == Thread.currentThread();
+}
+
+public void notifyListeners(int eventType, Event event) {
+	checkWidget();
+	if (event == null) event = new Event();
+	sendEvent(eventType, event);
+}
+
+void postEvent(int eventType) {
+	sendEvent(eventType, null, false);
+}
+
+void postEvent(int eventType, Event event) {
+	sendEvent(eventType, event, false);
+}
+
+void release(boolean destroy) {
+	if ((state & DISPOSE_SENT) == 0) {
+		state |= DISPOSE_SENT;
+		sendEvent(SWT.Dispose);
+	}
+	if ((state & DISPOSED) == 0) {
+		releaseChildren(destroy);
+	}
+	if ((state & RELEASED) == 0) {
+		state |= RELEASED;
+		if (destroy) {
+			releaseParent();
+			releaseWidget();
+		}
+	}
+}
+
+void releaseChildren(boolean destroy) {
+	// No-op
+}
+
+void releaseHandle() {
+	handle = 0;
+	state |= DISPOSED;
+}
+
+void releaseParent() {
+	// No-op
+}
+
+void releaseWidget() {
+	eventTable = null;
+	data = null;
+}
+
+public void removeListener(int eventType, Listener listener) {
+	checkWidget();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (eventTable == null) return;
+	eventTable.unhook(eventType, listener);
+}
+
+public void removeDisposeListener(DisposeListener listener) {
+	checkWidget();
+	if (listener == null) error(SWT.ERROR_NULL_ARGUMENT);
+	if (eventTable == null) return;
+	eventTable.unhook(SWT.Dispose, listener);
+}
+
+void sendEvent(Event event) {
+	Display display = event.display = this.display;
+	if (!display.filterEvent(event)) {
+		if (eventTable != null) eventTable.sendEvent(event);
+	}
+}
+
+void sendEvent(int eventType) {
+	sendEvent(eventType, null, true);
+}
+
+void sendEvent(int eventType, Event event) {
+	sendEvent(eventType, event, true);
+}
+
+void sendEvent(int eventType, Event event, boolean send) {
+	if (eventTable == null && !display.filters(eventType)) {
+		return;
+	}
+	if (event == null) event = new Event();
+	event.type = eventType;
+	event.display = display;
+	event.widget = this;
+	if (event.time == 0) {
+		event.time = (int) System.currentTimeMillis();
+	}
+	if (send) {
+		sendEvent(event);
+	} else {
+		display.postEvent(event);
+	}
+}
+
+public void setData(Object data) {
+	checkWidget();
+	if ((state & KEYED_DATA) != 0) {
+		((Object[]) this.data)[0] = data;
+	} else {
+		this.data = data;
+	}
+}
+
+public void setData(String key, Object value) {
+	checkWidget();
+	if (key == null) error(SWT.ERROR_NULL_ARGUMENT);
+	int index = 1;
+	Object[] table = null;
+	if ((state & KEYED_DATA) != 0) {
+		table = (Object[]) data;
+		while (index < table.length) {
+			if (key.equals(table[index])) break;
+			index += 2;
+		}
+	}
+	if (value != null) {
+		if ((state & KEYED_DATA) != 0) {
+			if (index == table.length) {
+				Object[] newTable = new Object[table.length + 2];
+				System.arraycopy(table, 0, newTable, 0, table.length);
+				data = table = newTable;
+			}
+		} else {
+			table = new Object[3];
+			table[0] = data;
+			data = table;
+			state |= KEYED_DATA;
+		}
+		table[index] = key;
+		table[index + 1] = value;
+	} else {
+		if ((state & KEYED_DATA) != 0) {
+			if (index != table.length) {
+				int length = table.length - 2;
+				if (length == 1) {
+					data = table[0];
+					state &= ~KEYED_DATA;
+				} else {
+					Object[] newTable = new Object[length];
+					System.arraycopy(table, 0, newTable, 0, index);
+					System.arraycopy(table, index + 2, newTable, index, length - index);
+					data = newTable;
+				}
+			}
+		}
+	}
+}
+
+@Override
+public String toString() {
+	String string = "*Disposed*";
+	if (!isDisposed()) {
+		string = "*Wrong Thread*";
+		if (isValidThread()) string = getNameText();
+	}
+	return getName() + " {" + string + "}";
+}
+
+String getName() {
+	String string = getClass().getName();
+	int index = string.lastIndexOf('.');
+	if (index == -1) return string;
+	return string.substring(index + 1, string.length());
+}
+
+String getNameText() {
+	return "";
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java
index 12ed1c2f9d5..5f04b065275 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java	
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java	
@@ -2187,6 +2187,23 @@ public static boolean isSystemDarkTheme () {
 	return isDarkTheme;
 }
 
+/**
+ * Returns true if SWT is running in headless mode, else
+ * returns false.
+ * 
+ * In headless mode, SWT widgets do not create native platform resources
+ * and operations are no-ops or return default values.
+ * 
+ *
+ * @return true if SWT is running in headless mode, else
+ *         returns false.
+ *
+ * @since 3.132
+ */
+public static boolean isHeadless () {
+	return false;
+}
+
 int getLastEventTime () {
 	return OS.GetMessageTime ();
 }
From d2ec7b0dddc3f17fd594b6899b67c29ce1cb67c3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Oct 2025 06:26:07 +0000
Subject: [PATCH 3/4] Create org.eclipse.swt.headless fragment and supporting
 classes
Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com>
---
 binaries/org.eclipse.swt.headless/.project    |  87 ++++++++
 .../META-INF/MANIFEST.MF                      |  25 +++
 binaries/org.eclipse.swt.headless/README.md   | 211 ++++++++++++++++++
 .../org.eclipse.swt.headless/build.properties |  29 +++
 .../forceQualifierUpdate.txt                  |   2 +
 .../fragment.properties                       |  12 +
 binaries/pom.xml                              |   1 +
 .../org/eclipse/swt/widgets/Caret.java        | 129 +++++++++++
 .../org/eclipse/swt/widgets/Item.java         |  56 +++++
 .../org/eclipse/swt/widgets/Menu.java         | 148 ++++++++++++
 .../org/eclipse/swt/widgets/MenuItem.java     | 115 ++++++++++
 .../org/eclipse/swt/widgets/ScrollBar.java    | 164 ++++++++++++++
 12 files changed, 979 insertions(+)
 create mode 100644 binaries/org.eclipse.swt.headless/.project
 create mode 100644 binaries/org.eclipse.swt.headless/META-INF/MANIFEST.MF
 create mode 100644 binaries/org.eclipse.swt.headless/README.md
 create mode 100644 binaries/org.eclipse.swt.headless/build.properties
 create mode 100644 binaries/org.eclipse.swt.headless/forceQualifierUpdate.txt
 create mode 100644 binaries/org.eclipse.swt.headless/fragment.properties
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Caret.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Item.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Menu.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/MenuItem.java
 create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/ScrollBar.java
diff --git a/binaries/org.eclipse.swt.headless/.project b/binaries/org.eclipse.swt.headless/.project
new file mode 100644
index 00000000000..7fe95cb6c47
--- /dev/null
+++ b/binaries/org.eclipse.swt.headless/.project
@@ -0,0 +1,87 @@
+
+
+	org.eclipse.swt.headless
+	
+	
+	
+	
+		
+			org.eclipse.jdt.core.javabuilder
+			
+			
+		
+		
+			org.eclipse.pde.ManifestBuilder
+			
+			
+		
+		
+			org.eclipse.pde.SchemaBuilder
+			
+			
+		
+		
+			org.eclipse.pde.api.tools.apiAnalysisBuilder
+			
+			
+		
+	
+	
+		org.eclipse.jdt.core.javanature
+		org.eclipse.pde.PluginNature
+		org.eclipse.pde.api.tools.apiAnalysisNature
+	
+	
+		
+			Eclipse SWT
+			2
+			SWT_HOST_PLUGIN/Eclipse%20SWT
+		
+		
+			Eclipse SWT Accessibility
+			2
+			SWT_HOST_PLUGIN/Eclipse%20SWT%20Accessibility
+		
+		
+			Eclipse SWT AWT
+			2
+			SWT_HOST_PLUGIN/Eclipse%20SWT%20AWT
+		
+		
+			Eclipse SWT Browser
+			2
+			SWT_HOST_PLUGIN/Eclipse%20SWT%20Browser
+		
+		
+			Eclipse SWT Custom Widgets
+			2
+			SWT_HOST_PLUGIN/Eclipse%20SWT%20Custom%20Widgets
+		
+		
+			Eclipse SWT Drag and Drop
+			2
+			SWT_HOST_PLUGIN/Eclipse%20SWT%20Drag%20and%20Drop
+		
+		
+			Eclipse SWT OpenGL
+			2
+			SWT_HOST_PLUGIN/Eclipse%20SWT%20OpenGL
+		
+		
+			Eclipse SWT Printing
+			2
+			SWT_HOST_PLUGIN/Eclipse%20SWT%20Printing
+		
+		
+			Eclipse SWT Program
+			2
+			SWT_HOST_PLUGIN/Eclipse%20SWT%20Program
+		
+	
+	
+		
+			SWT_HOST_PLUGIN
+			$%7BPARENT-2-PROJECT_LOC%7D/bundles/org.eclipse.swt
+		
+	
+
diff --git a/binaries/org.eclipse.swt.headless/META-INF/MANIFEST.MF b/binaries/org.eclipse.swt.headless/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..5362e503eb7
--- /dev/null
+++ b/binaries/org.eclipse.swt.headless/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Fragment-Host: org.eclipse.swt;bundle-version="[3.128.0,4.0.0)"
+Bundle-Name: %fragmentName
+Bundle-Vendor: %providerName
+Bundle-SymbolicName: org.eclipse.swt.headless; singleton:=true
+Bundle-Version: 3.132.0.qualifier
+Bundle-ManifestVersion: 2
+Bundle-Localization: fragment
+Export-Package: 
+ org.eclipse.swt,
+ org.eclipse.swt.accessibility,
+ org.eclipse.swt.awt,
+ org.eclipse.swt.browser,
+ org.eclipse.swt.custom,
+ org.eclipse.swt.dnd,
+ org.eclipse.swt.events,
+ org.eclipse.swt.graphics,
+ org.eclipse.swt.layout,
+ org.eclipse.swt.opengl,
+ org.eclipse.swt.printing,
+ org.eclipse.swt.program,
+ org.eclipse.swt.widgets,
+ org.eclipse.swt.internal; x-friends:="org.eclipse.ui",
+ org.eclipse.swt.internal.image; x-internal:=true
+Automatic-Module-Name: org.eclipse.swt.headless
diff --git a/binaries/org.eclipse.swt.headless/README.md b/binaries/org.eclipse.swt.headless/README.md
new file mode 100644
index 00000000000..c66dcc66456
--- /dev/null
+++ b/binaries/org.eclipse.swt.headless/README.md
@@ -0,0 +1,211 @@
+# SWT Headless Fragment
+
+## Overview
+
+The `org.eclipse.swt.headless` fragment provides a headless implementation of SWT (Standard Widget Toolkit) that allows applications to run without requiring a native windowing system or display. This is similar to Java AWT's headless mode (`java.awt.headless`).
+
+## Purpose
+
+The headless fragment is useful for:
+
+- **Server-side applications** that need to reference UI code but don't display a UI
+- **Testing** UI applications without requiring a display
+- **Continuous Integration** environments where no display is available
+- **Headless rendering** of UI layouts for documentation or screenshots
+- **Command-line tools** that use SWT libraries but don't require actual UI display
+
+## Key Features
+
+### Detection
+
+You can check if SWT is running in headless mode:
+
+```java
+if (Display.isHeadless()) {
+    // Running in headless mode
+}
+```
+
+### Behavior
+
+In headless mode:
+
+- **Widget creation**: Widgets can be created and configured normally
+- **State management**: Widget properties (text, selection, bounds, etc.) are stored and can be retrieved
+- **Layout**: Layout managers work normally and calculate sizes
+- **Parent-child relationships**: Composite widgets maintain their child lists correctly
+- **Events**: Event listeners can be registered (though events are not automatically triggered)
+- **No rendering**: No actual native widgets are created, no drawing occurs
+- **No user interaction**: Mouse and keyboard events don't occur naturally
+
+## Supported Widgets
+
+The headless implementation provides the following core widgets:
+
+### Containers
+- `Display` - The main display object
+- `Shell` - Top-level window
+- `Composite` - Container for other controls
+- `Canvas` - Drawing surface (no actual drawing)
+- `Decorations` - Base for decorated containers
+
+### Controls
+- `Button` - Push button, checkbox, radio, toggle, arrow
+- `Label` - Text or image label
+- `Control` - Base class for all controls
+
+### Supporting Classes
+- `Widget` - Base class for all widgets
+- `Scrollable` - Base for scrollable controls
+- `Menu` - Menu bar and popup menus
+- `MenuItem` - Individual menu items
+- `Item` - Base for items
+- `Caret` - Text cursor
+- `ScrollBar` - Scrollbar widget
+
+## Limitations
+
+The headless implementation has the following limitations:
+
+### Not Implemented
+
+The following features are **not** currently implemented:
+
+1. **Native rendering**: No actual drawing to screen or images
+2. **User input**: No keyboard or mouse events
+3. **System integration**: 
+   - No system tray
+   - No clipboard
+   - No drag and drop
+   - No native file/color/font dialogs
+4. **Advanced widgets**: Many complex widgets are not yet implemented:
+   - Table, Tree, List
+   - Text, StyledText
+   - Browser
+   - And many others
+5. **Graphics operations**: GC (Graphics Context) drawing operations are no-ops
+6. **Images**: Image loading and manipulation is limited
+7. **Fonts and colors**: System fonts and colors return defaults
+
+### Default Behavior
+
+- `Display.getDefault()` creates a headless display
+- `Display.isHeadless()` returns `true`
+- Widget methods that can't be implemented return default values:
+  - `computeSize()` returns reasonable defaults (64x64 or based on content)
+  - `getBounds()` returns stored bounds
+  - System queries return sensible defaults
+- Operations that require native resources are no-ops:
+  - `redraw()` does nothing
+  - `update()` does nothing
+  - Event loops don't wait for user input
+
+## Usage Example
+
+```java
+// Create a headless display
+Display display = new Display();
+System.out.println("Headless: " + Display.isHeadless()); // true
+
+// Create a shell
+Shell shell = new Shell(display);
+shell.setText("Test Shell");
+shell.setSize(400, 300);
+
+// Create controls
+Composite composite = new Composite(shell, SWT.NONE);
+composite.setLayout(new FillLayout());
+
+Button button = new Button(composite, SWT.PUSH);
+button.setText("Click Me");
+
+Label label = new Label(composite, SWT.NONE);
+label.setText("Hello Headless SWT!");
+
+// Layout works normally
+shell.layout();
+
+// Can query widget properties
+System.out.println("Button text: " + button.getText());
+System.out.println("Label text: " + label.getText());
+System.out.println("Shell size: " + shell.getSize());
+
+// Cleanup
+shell.dispose();
+display.dispose();
+```
+
+## Installation
+
+The headless fragment is automatically available when:
+
+1. The `org.eclipse.swt` bundle is present
+2. The `org.eclipse.swt.headless` fragment is in the classpath
+3. No platform-specific fragment (gtk, cocoa, win32) is available
+
+The OSGi framework will automatically select the headless fragment when no native platform is available.
+
+## Building
+
+The headless fragment is built as part of the normal SWT build process:
+
+```bash
+mvn clean install
+```
+
+The fragment is located in `binaries/org.eclipse.swt.headless/`.
+
+## Contributing
+
+When extending the headless implementation:
+
+1. **Keep it simple**: Headless implementations should be minimal
+2. **Store and return**: Store values set via setters, return them from getters
+3. **No-op when necessary**: Operations that require native resources should be no-ops
+4. **Parent-child tracking**: Maintain widget hierarchies properly
+5. **Follow patterns**: Look at existing headless widgets for consistency
+
+### Adding New Widgets
+
+To add a new widget to the headless implementation:
+
+1. Create the widget class in `bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/`
+2. Implement the public API from the platform-specific versions
+3. Store state in private fields
+4. Handle parent-child relationships for Composite widgets
+5. Return sensible defaults for queries
+
+## Testing
+
+The headless implementation can be tested using JUnit tests that don't require a display:
+
+```java
+@Test
+public void testHeadlessButton() {
+    Display display = new Display();
+    assertTrue(Display.isHeadless());
+    
+    Shell shell = new Shell(display);
+    Button button = new Button(shell, SWT.PUSH);
+    button.setText("Test");
+    
+    assertEquals("Test", button.getText());
+    assertFalse(button.getSelection());
+    
+    button.setSelection(true);
+    assertTrue(button.getSelection());
+    
+    shell.dispose();
+    display.dispose();
+}
+```
+
+## See Also
+
+- [Java AWT Headless Mode](https://www.oracle.com/technical-resources/articles/javase/headless.html)
+- [SWT API Documentation](https://help.eclipse.org/latest/index.jsp)
+- [Eclipse SWT Project](https://www.eclipse.org/swt/)
+
+## License
+
+Eclipse Public License 2.0 (EPL-2.0)
diff --git a/binaries/org.eclipse.swt.headless/build.properties b/binaries/org.eclipse.swt.headless/build.properties
new file mode 100644
index 00000000000..cd19887ad25
--- /dev/null
+++ b/binaries/org.eclipse.swt.headless/build.properties
@@ -0,0 +1,29 @@
+###############################################################################
+# Copyright (c) 2025 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+custom = true
+bin.includes = .,fragment.properties
+source.. = \
+	../../bundles/org.eclipse.swt/Eclipse SWT/headless,\
+	../../bundles/org.eclipse.swt/Eclipse SWT/common,\
+	../../bundles/org.eclipse.swt/Eclipse SWT/emulated/bidi,\
+	../../bundles/org.eclipse.swt/Eclipse SWT/emulated/coolbar,\
+	../../bundles/org.eclipse.swt/Eclipse SWT/emulated/taskbar,\
+	../../bundles/org.eclipse.swt/Eclipse SWT/emulated/tooltip,\
+	../../bundles/org.eclipse.swt/Eclipse SWT/emulated/expand,\
+	../../bundles/org.eclipse.swt/Eclipse SWT Accessibility/common,\
+	../../bundles/org.eclipse.swt/Eclipse SWT AWT/common,\
+	../../bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/common,\
+	../../bundles/org.eclipse.swt/Eclipse SWT Printing/common,\
+	../../bundles/org.eclipse.swt/Eclipse SWT Program/common,\
+	../../bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common,\
+	../../bundles/org.eclipse.swt/Eclipse SWT Browser/common,\
+	../../bundles/org.eclipse.swt/Eclipse SWT OpenGL/common
+output.. = bin/
diff --git a/binaries/org.eclipse.swt.headless/forceQualifierUpdate.txt b/binaries/org.eclipse.swt.headless/forceQualifierUpdate.txt
new file mode 100644
index 00000000000..c656da0edbc
--- /dev/null
+++ b/binaries/org.eclipse.swt.headless/forceQualifierUpdate.txt
@@ -0,0 +1,2 @@
+# To force a version qualifier update add the bug here
+Bug 577498 - Initial headless implementation
diff --git a/binaries/org.eclipse.swt.headless/fragment.properties b/binaries/org.eclipse.swt.headless/fragment.properties
new file mode 100644
index 00000000000..33896261db6
--- /dev/null
+++ b/binaries/org.eclipse.swt.headless/fragment.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2025 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+fragmentName = Standard Widget Toolkit Headless Implementation
+providerName = Eclipse.org
diff --git a/binaries/pom.xml b/binaries/pom.xml
index 78946f0f1b8..09d839e6372 100644
--- a/binaries/pom.xml
+++ b/binaries/pom.xml
@@ -40,6 +40,7 @@
 		org.eclipse.swt.gtk.linux.x86_64
 		org.eclipse.swt.win32.win32.aarch64
 		org.eclipse.swt.win32.win32.x86_64
+		org.eclipse.swt.headless
 	
 
 	
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Caret.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Caret.java
new file mode 100644
index 00000000000..226f6470d75
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Caret.java	
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Caret for SWT.
+ */
+public class Caret extends Widget {
+	Canvas parent;
+	Image image;
+	Font font;
+	int x, y, width, height;
+	boolean visible;
+
+public Caret(Canvas parent, int style) {
+	super(parent, style);
+	this.parent = parent;
+	width = 1;
+	height = 10;
+}
+
+public Rectangle getBounds() {
+	checkWidget();
+	return new Rectangle(x, y, width, height);
+}
+
+public Font getFont() {
+	checkWidget();
+	return font;
+}
+
+public Image getImage() {
+	checkWidget();
+	return image;
+}
+
+public Point getLocation() {
+	checkWidget();
+	return new Point(x, y);
+}
+
+public Canvas getParent() {
+	checkWidget();
+	return parent;
+}
+
+public Point getSize() {
+	checkWidget();
+	return new Point(width, height);
+}
+
+public boolean getVisible() {
+	checkWidget();
+	return visible;
+}
+
+public boolean isVisible() {
+	checkWidget();
+	return visible && parent.isVisible();
+}
+
+public void setBounds(int x, int y, int width, int height) {
+	checkWidget();
+	this.x = x;
+	this.y = y;
+	this.width = width;
+	this.height = height;
+}
+
+public void setBounds(Rectangle rect) {
+	checkWidget();
+	if (rect == null) error(SWT.ERROR_NULL_ARGUMENT);
+	setBounds(rect.x, rect.y, rect.width, rect.height);
+}
+
+public void setFont(Font font) {
+	checkWidget();
+	this.font = font;
+}
+
+public void setImage(Image image) {
+	checkWidget();
+	this.image = image;
+}
+
+public void setLocation(int x, int y) {
+	checkWidget();
+	this.x = x;
+	this.y = y;
+}
+
+public void setLocation(Point location) {
+	checkWidget();
+	if (location == null) error(SWT.ERROR_NULL_ARGUMENT);
+	setLocation(location.x, location.y);
+}
+
+public void setSize(int width, int height) {
+	checkWidget();
+	this.width = width;
+	this.height = height;
+}
+
+public void setSize(Point size) {
+	checkWidget();
+	if (size == null) error(SWT.ERROR_NULL_ARGUMENT);
+	setSize(size.x, size.y);
+}
+
+public void setVisible(boolean visible) {
+	checkWidget();
+	this.visible = visible;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Item.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Item.java
new file mode 100644
index 00000000000..552791f9071
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Item.java	
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Headless implementation of Item for SWT.
+ */
+public abstract class Item extends Widget {
+	String text = "";
+	Image image;
+
+public Item(Widget parent, int style) {
+	super(parent, style);
+}
+
+public Image getImage() {
+	checkWidget();
+	return image;
+}
+
+public String getText() {
+	checkWidget();
+	return text;
+}
+
+public void setImage(Image image) {
+	checkWidget();
+	this.image = image;
+}
+
+public void setText(String string) {
+	checkWidget();
+	if (string == null) error(SWT.ERROR_NULL_ARGUMENT);
+	text = string;
+}
+
+@Override
+String getNameText() {
+	return getText();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Menu.java
new file mode 100644
index 00000000000..ee5c3fd12c8
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/headless/org/eclipse/swt/widgets/Menu.java	
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.widgets;
+
+import org.eclipse.swt.*;
+import java.util.*;
+
+/**
+ * Headless implementation of Menu for SWT.
+ */
+public class Menu extends Widget {
+	Decorations parent;
+	MenuItem[] items = new MenuItem[0];
+	int x, y;
+	boolean visible;
+
+public Menu(Control parent) {
+	this(parent, SWT.POP_UP);
+}
+
+public Menu(Control parent, int style) {
+	super(parent, checkStyle(style));
+}
+
+public Menu(Decorations parent, int style) {
+	super(parent, checkStyle(style));
+	this.parent = parent;
+}
+
+public Menu(Menu parentMenu) {
+	this(parentMenu, SWT.DROP_DOWN);
+}
+
+public Menu(Menu parentMenu, int style) {
+	super(parentMenu, checkStyle(style));
+}
+
+public Menu(MenuItem parentItem) {
+	this(parentItem.parent, SWT.DROP_DOWN);
+}
+
+static int checkStyle(int style) {
+	return checkBits(style, SWT.POP_UP, SWT.BAR, SWT.DROP_DOWN, 0, 0, 0);
+}
+
+public int getItemCount() {
+	checkWidget();
+	return items.length;
+}
+
+public MenuItem getItem(int index) {
+	checkWidget();
+	if (index < 0 || index >= items.length) error(SWT.ERROR_INVALID_RANGE);
+	return items[index];
+}
+
+public MenuItem[] getItems() {
+	checkWidget();
+	MenuItem[] result = new MenuItem[items.length];
+	System.arraycopy(items, 0, result, 0, items.length);
+	return result;
+}
+
+public Decorations getParent() {
+	checkWidget();
+	return parent;
+}
+
+public Shell getShell() {
+	checkWidget();
+	return parent != null ? parent.getShell() : null;
+}
+
+public boolean getVisible() {
+	checkWidget();
+	return visible;
+}
+
+public int indexOf(MenuItem item) {
+	checkWidget();
+	if (item == null) error(SWT.ERROR_NULL_ARGUMENT);
+	for (int i = 0; i < items.length; i++) {
+		if (items[i] == item) return i;
+	}
+	return -1;
+}
+
+public boolean isEnabled() {
+	checkWidget();
+	return (state & DISABLED) == 0;
+}
+
+public boolean isVisible() {
+	checkWidget();
+	return getVisible();
+}
+
+public void setEnabled(boolean enabled) {
+	checkWidget();
+	if (enabled) {
+		state &= ~DISABLED;
+	} else {
+		state |= DISABLED;
+	}
+}
+
+public void setLocation(int x, int y) {
+	checkWidget();
+	this.x = x;
+	this.y = y;
+}
+
+public void setLocation(org.eclipse.swt.graphics.Point location) {
+	checkWidget();
+	if (location == null) error(SWT.ERROR_NULL_ARGUMENT);
+	setLocation(location.x, location.y);
+}
+
+public void setVisible(boolean visible) {
+	checkWidget();
+	this.visible = visible;
+}
+
+void addItem(MenuItem item) {
+	MenuItem[] newItems = new MenuItem[items.length + 1];
+	System.arraycopy(items, 0, newItems, 0, items.length);
+	newItems[items.length] = item;
+	items = newItems;
+}
+
+void removeItem(MenuItem item) {
+	List