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 0c1cebdd5a..5e090cebb2 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 @@ -558,6 +558,18 @@ void snapshotBackground (long handle, long snapshot) { Graphene.graphene_rect_free(rect); } +@Override +void snapshotToDraw (long handle, long snapshot) { + // Containers paint before children so SWT.Paint backgrounds appear behind child controls, + // matching GTK3 EXPOSE_EVENT_INVERSE (after=false) behavior. + snapshotPaint(handle, snapshot); +} + +@Override +void snapshotToDrawAfterChildren (long handle, long snapshot) { + // Suppress Control's after-children paint: Composite already painted before children above. +} + /** * Fills the interior of the rectangle specified by the arguments, 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 ca50225611..88f7a051de 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 @@ -524,6 +524,25 @@ boolean hooksPaint () { return hooks (SWT.Paint) || filters (SWT.Paint); } +@Override +void snapshotPaint (long handle, long snapshot) { + /* + * Guard against creating an empty Cairo render node when there are no paint + * listeners. gtk_snapshot_append_cairo() appends a node immediately; leaving it + * empty/unfinished causes it to obscure render nodes already in the snapshot + * (e.g. GtkTreeView content snapshotted before this call). + */ + if (!hooksPaint()) return; + super.snapshotPaint(handle, snapshot); +} + +@Override +void snapshotToDrawAfterChildren (long handle, long snapshot) { + // Leaf controls (Button, Label, etc.) paint after children so SWT.Paint listeners + // draw on top of the native widget appearance, matching GTK3 DRAW (after=true) behavior. + snapshotPaint(handle, snapshot); +} + @Override long hoverProc (long widget) { int[] x = new int[1], y = new int[1], mask = new int[1]; 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 77c7862072..149e873b9a 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 @@ -1720,7 +1720,7 @@ void snapshotDrawProc(long handle, long snapshot) { // Draw background before children so it appears behind them if (widget != null) widget.snapshotBackground(handle, snapshot); - // Draw SWT custom paint before children so child widgets remain visible. + // Paint before children (used by Composite subclasses for backgrounds) if (widget != null) widget.snapshotToDraw(handle, snapshot); long child = GTK4.gtk_widget_get_first_child(handle); @@ -1729,6 +1729,9 @@ void snapshotDrawProc(long handle, long snapshot) { GTK4.gtk_widget_snapshot_child(handle, child, snapshot); child = GTK4.gtk_widget_get_next_sibling(child); } + + // Paint after children (used by leaf controls for overlay/on-top drawing) + if (widget != null) widget.snapshotToDrawAfterChildren(handle, snapshot); } static long rendererGetPreferredWidthProc (long cell, long handle, long minimun_size, long natural_size) { 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 a72fb2f3a9..c416841785 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 @@ -4233,6 +4233,18 @@ private void gtk3_paintEvent(long cairo) { event.gc = null; } +@Override +void snapshotToDraw(long handle, long snapshot) { + // Table renders via native GTK children (GtkScrolledWindow > GtkTreeView). + // Like GTK3 where Table explicitly fires paint in EXPOSE_EVENT (after=true), + // GTK4 must paint after children so SWT.Paint overlays appear on top. +} + +@Override +void snapshotToDrawAfterChildren(long handle, long snapshot) { + snapshotPaint(handle, snapshot); +} + @Override public void dispose() { super.dispose(); 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 aa25c3203c..86089db002 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 @@ -4306,6 +4306,18 @@ private void gtk3_paintEvent(long cairo) { event.gc = null; } +@Override +void snapshotToDraw(long handle, long snapshot) { + // Tree renders via native GTK children (GtkScrolledWindow > GtkTreeView). + // Like GTK3 where Tree explicitly fires paint in EXPOSE_EVENT (after=true), + // GTK4 must paint after children so SWT.Paint overlays appear on top. +} + +@Override +void snapshotToDrawAfterChildren(long handle, long snapshot) { + snapshotPaint(handle, snapshot); +} + private void throwCannotRemoveItem(int i) { String message = "Cannot remove item with index " + i + "."; throw new SWTException(message); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java index 898bd7117e..9e1889f6d8 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java @@ -2292,12 +2292,10 @@ void snapshotBackground (long handle, long snapshot) { /** * Converts an incoming snapshot into a gtk_draw() call, complete with - * a Cairo context. - * - * @param handle the widget receiving the snapshot - * @param snapshot the actual GtkSnapshot + * a Cairo context. Used by subclasses to + * trigger painting at the appropriate point in the snapshot order. */ -void snapshotToDraw (long handle, long snapshot) { +void snapshotPaint (long handle, long snapshot) { GtkAllocation allocation = new GtkAllocation(); GTK.gtk_widget_get_allocation(handle, allocation); long rect = Graphene.graphene_rect_alloc(); @@ -2312,6 +2310,20 @@ void snapshotToDraw (long handle, long snapshot) { Graphene.graphene_rect_free(rect); } +/** + * Called before child widgets are snapshotted. Containers (Composite) override + * this to paint backgrounds behind their children. + */ +void snapshotToDraw (long handle, long snapshot) { +} + +/** + * Called after child widgets are snapshotted. Leaf controls (Button, Label, + * etc.) override this to paint on top of their native appearance. + */ +void snapshotToDrawAfterChildren (long handle, long snapshot) { +} + long gtk_widget_get_window (long widget){ GTK.gtk_widget_realize(widget); return GTK3.gtk_widget_get_window (widget);