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 c70707366f..23e74f61c6 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 @@ -1396,7 +1396,20 @@ void moveAbove (long child, long sibling) { long parentHandle = parentingHandle (); if (GTK.GTK4) { if (sibling == 0) { - GTK4.gtk_widget_insert_after(child, parentHandle, 0L); + /* + * True raise-to-top-of-paint-order, scoped to Shell-direct + * children (e.g. an overlay pane raised via moveAbove(null)). + * GTK4 has no per-widget GdkWindow, so this same native sibling + * list also backs Composite._getChildren(); other code already + * relies on today's insert_after(..., NULL) behaviour to keep + * getChildren() stable for non-Shell parents, so this is not + * changed generally. + */ + if (this instanceof Shell) { + GTK4.gtk_widget_insert_before(child, parentHandle, 0L); + } else { + GTK4.gtk_widget_insert_after(child, parentHandle, 0L); + } } else { GTK4.gtk_widget_insert_before(child, parentHandle, sibling); } @@ -1416,16 +1429,20 @@ void moveBelow (long child, long sibling) { * scrolled content instead. * * Not needed on GTK4: widgets have no per-widget GdkWindow, so paint order - * is simply the parent's child-list order (first = bottom, last = top), and - * the general branch below already appends the child to the end (top). + * is simply the parent's child-list order (first = bottom, last = top). */ if (!GTK.GTK4 && sibling == 0 && parentHandle == fixedHandle) { moveAbove (child, scrolledHandle != 0 ? scrolledHandle : handle); return; } if (GTK.GTK4) { + /* Mirror image of moveAbove - see the comment there. */ if (sibling == 0) { - GTK4.gtk_widget_insert_before(child, parentHandle, 0L); + if (this instanceof Shell) { + GTK4.gtk_widget_insert_after(child, parentHandle, 0L); + } else { + GTK4.gtk_widget_insert_before(child, parentHandle, 0L); + } } else { GTK4.gtk_widget_insert_after(child, parentHandle, sibling); } 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 9dc6083203..6671563a3c 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 @@ -815,7 +815,13 @@ void createWidget(int index) { checkBuffered(); showWidget(); setInitialBounds(); - setZOrder(null, false, false); + if (GTK.GTK4 && !(this instanceof Shell)) { + /* moveBelow(null) now sinks Shell-direct children to the back + * (see Composite.moveAbove) - guard against undoing that. */ + setZOrder(null, false, false, !(parent instanceof Shell)); + } else { + setZOrder(null, false, false); + } if (!GTK.GTK4) setRelations(); checkMirrored(); checkBorder(); @@ -4833,10 +4839,10 @@ void destroyWidget() { // GTK windows don't have a parent, so destroy it now GTK4.gtk_window_destroy(currHandle); } else if (parent != null) { - if (fixedHandle != 0) { - // Remove widget from hierarchy by removing it from parent container - OS.swt_fixed_remove(parent.parentingHandle(), fixedHandle); - } + /* Use currHandle, not fixedHandle alone - widgets without a + * separate fixedHandle wrapper were otherwise never actually + * unparented here, leaving them alive and rendered natively. */ + OS.swt_fixed_remove(parent.parentingHandle(), currHandle); } else { assert false : "widgets must have a parent or be a GtkWindow"; } @@ -5925,7 +5931,12 @@ public boolean setParent (Composite parent) { allocation.height = height; gtk_widget_size_allocate(topHandle, allocation, -1); this.parent = parent; - setZOrder (null, false, true); + if (GTK.GTK4 && !(this instanceof Shell)) { + /* See createWidget() re: guarding fixChildren on GTK4. */ + setZOrder (null, false, true, !(parent instanceof Shell)); + } else { + setZOrder (null, false, true); + } reskin (SWT.ALL); // restore focus to the last Control that had it, if focus is now gone if (focusControlBeforeReparent != null && !focusControlBeforeReparent.isDisposed() && display.getFocusControl() == null) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolBar.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolBar.java index 4a9782a213..fb63abb090 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolBar.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolBar.java @@ -309,8 +309,10 @@ public int getItemCount () { int itemCount = 0; if (GTK.GTK4) { + /* Must match _getItems(): a Menu's GtkPopover is also parented here + * as a native child and would otherwise count as a phantom item. */ for (long child = GTK4.gtk_widget_get_first_child(handle); child != 0; child = GTK4.gtk_widget_get_next_sibling(child)) { - itemCount++; + if (display.getWidget(child) instanceof ToolItem) itemCount++; } } else { long list = GTK3.gtk_container_get_children (handle); @@ -348,8 +350,9 @@ ToolItem[] _getItems () { ArrayList childrenList = new ArrayList<>(); for (long child = GTK4.gtk_widget_get_first_child(handle); child != 0; child = GTK4.gtk_widget_get_next_sibling(child)) { Widget childWidget = display.getWidget(child); - if (childWidget != null) { - childrenList.add((ToolItem)childWidget); + /* A Menu's GtkPopover is also a native child here; skip non-ToolItems. */ + if (childWidget instanceof ToolItem toolItem) { + childrenList.add(toolItem); } }