Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c
Original file line number Diff line number Diff line change
Expand Up @@ -2160,6 +2160,22 @@ JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1popover_1menu_1new_1from_1model_1full)
}
#endif

#ifndef NO_gtk_1popover_1menu_1add_1child
JNIEXPORT jboolean JNICALL GTK4_NATIVE(gtk_1popover_1menu_1add_1child)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1, jbyteArray arg2)
{
jbyte *lparg2=NULL;
jboolean rc = 0;
GTK4_NATIVE_ENTER(env, that, gtk_1popover_1menu_1add_1child_FUNC);
if (arg2) if ((lparg2 = (*env)->GetByteArrayElements(env, arg2, NULL)) == NULL) goto fail;
rc = (jboolean)gtk_popover_menu_add_child((GtkPopoverMenu *)arg0, (GtkWidget *)arg1, (const char *)lparg2);
fail:
if (arg2 && lparg2) (*env)->ReleaseByteArrayElements(env, arg2, lparg2, 0);
GTK4_NATIVE_EXIT(env, that, gtk_1popover_1menu_1add_1child_FUNC);
return rc;
}
#endif

#ifndef NO_gtk_1popover_1menu_1set_1menu_1model
JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1popover_1menu_1set_1menu_1model)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,13 @@ public class GTK4 {
/** @param popover cast=(GtkPopover *) */
public static final native void gtk_popover_set_has_arrow(long popover, boolean has_arrow);

/**
* @param popover cast=(GtkPopoverMenu *)
* @param child cast=(GtkWidget *)
* @param id cast=(const char *)
*/
public static final native boolean gtk_popover_menu_add_child(long popover, long child, byte[] id);

/* GtkPopoverMenuBar */
/** @param model cast=(GMenuModel *) */
public static final native long gtk_popover_menu_bar_new_from_model(long model);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ void printWidget (GC gc, long drawable, int depth, int x, int y) {
for (int i=children.length-1; i>=0; --i) {
Control child = children [i];
if (child.getVisible ()) {
Point location = child.getLocationInPixels ();
Point location = child.getLocation ();
child.printWidget (gc, drawable, depth, x + location.x, y + location.y);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1226,11 +1226,6 @@ int setBounds (int x, int y, int width, int height, boolean move, boolean resize
* </ul>
*/
public Point getLocation () {
checkWidget();
return getLocationInPixels();
}

Point getLocationInPixels () {
checkWidget();
long topHandle = topHandle ();
GtkAllocation allocation = new GtkAllocation ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public class MenuItem extends Item {
long modelHandle, actionHandle, shortcutHandle;
Section section;
String actionName;

/* GTK4 custom widget support for icons */
long buttonHandle; // Custom button widget for the menu item
String customId; // Unique ID for custom widget registration

/**
* Constructs a new instance of this class given its parent
Expand Down Expand Up @@ -300,6 +304,73 @@ void createHandle(int index) {
break;
}

/*
* GTK4: Create custom widgets for menu items to support icons.
* GTK4 PopoverMenu does not support icons via the standard GIO MenuItem API.
* We work around this by:
* 1. Setting a "custom" attribute on the GMenuItem model
* 2. Creating a custom widget (button with box containing image+label)
* 3. Registering the custom widget with the parent menu's PopoverMenu
*
* Note: This only works for POP_UP menus, as BAR and DROP_DOWN menus
* don't have a GtkPopoverMenu widget that we can register with.
*/
if ((style & SWT.SEPARATOR) == 0 && (parent.style & SWT.POP_UP) != 0) {
// Create unique ID for this menu item's custom widget
customId = "swt-item-" + this.hashCode();
byte[] idBytes = Converter.javaStringToCString(customId);

// Set "custom" attribute on the GMenuItem model
// Allocate native memory for the ID string
long idPtr = OS.g_malloc(idBytes.length);
C.memmove(idPtr, idBytes, idBytes.length);

byte[] customAttr = Converter.javaStringToCString("custom");
byte[] stringFormat = Converter.javaStringToCString("s");
OS.g_menu_item_set_attribute(handle, customAttr, stringFormat, idPtr);

// Note: Don't free idPtr yet, as the menu model may still reference it

// Create custom widget structure: Button -> Box -> [Image + Label]
buttonHandle = GTK.gtk_button_new();
if (buttonHandle == 0) error(SWT.ERROR_NO_HANDLES);

boxHandle = gtk_box_new(GTK.GTK_ORIENTATION_HORIZONTAL, false, 6);
if (boxHandle == 0) error(SWT.ERROR_NO_HANDLES);

// Create image handle (initially empty, will be populated by setImage)
imageHandle = GTK.gtk_image_new();
if (imageHandle == 0) error(SWT.ERROR_NO_HANDLES);
GTK4.gtk_box_append(boxHandle, imageHandle);

// Create label handle (will be populated by setText)
labelHandle = GTK.gtk_label_new_with_mnemonic(null);
if (labelHandle == 0) error(SWT.ERROR_NO_HANDLES);
GTK.gtk_label_set_xalign(labelHandle, 0);
GTK.gtk_widget_set_halign(labelHandle, GTK.GTK_ALIGN_FILL);
GTK4.gtk_box_append(boxHandle, labelHandle);

// Put the box into the button
GTK4.gtk_button_set_child(buttonHandle, boxHandle);

// Style the button to look like a menu item
byte[] modelClass = Converter.javaStringToCString("model");
byte[] flatClass = Converter.javaStringToCString("flat");
GTK.gtk_widget_add_css_class(buttonHandle, modelClass);
GTK.gtk_widget_add_css_class(buttonHandle, flatClass);

// Register custom widget with parent PopoverMenu
// Only POP_UP menus have a GtkPopoverMenu widget we can register with
if (parent.handle != 0) {
GTK4.gtk_popover_menu_add_child(parent.handle, buttonHandle, idBytes);
}

// Connect button click to action
if (actionHandle != 0) {
OS.g_signal_connect_closure(buttonHandle, OS.clicked, display.getClosure(CLICKED), false);
}
}


Section selectedSection = parent.sections.getLast();
for (Section section : parent.sections) {
Expand Down Expand Up @@ -1028,9 +1099,6 @@ public void setID (int id) {
*/
@Override
public void setImage (Image image) {
//TODO: GTK4 Menu images with text are no longer supported
if (GTK.GTK4) return;

checkWidget();
if (this.image == image) return;
if ((style & SWT.SEPARATOR) != 0) return;
Expand All @@ -1041,6 +1109,38 @@ public void setImage (Image image) {
}

private void _setImage (Image image) {
if (GTK.GTK4) {
// GTK4: Update the image in the custom widget
if (image != null) {
ImageList imageList = parent.imageList;
if (imageList == null) imageList = parent.imageList = new ImageList();
int imageIndex = imageList.indexOf(image);
if (imageIndex == -1) {
imageIndex = imageList.add(image);
} else {
imageList.put(imageIndex, image);
}

// Use paintable approach similar to ToolItem
long pixbuf = ImageList.createPixbuf(image);
long texture = GDK.gdk_texture_new_for_pixbuf(pixbuf);
OS.g_object_unref(pixbuf);

if (imageHandle != 0) {
GTK4.gtk_image_set_from_paintable(imageHandle, texture);
gtk_widget_show(imageHandle);
}
} else {
// Clear the image
if (imageHandle != 0) {
GTK4.gtk_image_clear(imageHandle);
gtk_widget_hide(imageHandle);
}
}
return;
}

// GTK3 implementation
if (image != null) {
ImageList imageList = parent.imageList;
if (imageList == null) imageList = parent.imageList = new ImageList ();
Expand Down Expand Up @@ -1268,6 +1368,10 @@ public void setText (String string) {

if (GTK.GTK4) {
OS.g_menu_item_set_label(handle, buffer);
// Update custom widget label if it exists
if (labelHandle != 0 && GTK.GTK_IS_LABEL(labelHandle)) {
GTK.gtk_label_set_text_with_mnemonic(labelHandle, buffer);
}
MaskKeysym maskKeysym = getMaskKeysym();
if (maskKeysym != null) {
OS.g_menu_item_set_attribute(handle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1270,7 +1270,7 @@ public boolean getFullScreen () {
}

@Override
Point getLocationInPixels () {
public Point getLocation() {
checkWidget ();
// Bug in GTK: when shell is moved and then hidden, its location does not get updated.
// Move it before getting its location.
Expand Down Expand Up @@ -3044,7 +3044,7 @@ public void setVisible (boolean visible) {
opened = true;
if (!moved) {
moved = true;
Point location = getLocationInPixels();
Point location = getLocation();
oldX = location.x;
oldY = location.y;
sendEvent (SWT.Move);
Expand Down Expand Up @@ -3495,15 +3495,15 @@ Point getWindowOrigin () {
* window trims etc. from the window manager. That's why getLocation ()
* is not safe to use for coordinate mappings after the shell has been made visible.
*/
return getLocationInPixels ();
return getLocation ();
}
return super.getWindowOrigin( );
}

@Override
Point getSurfaceOrigin () {
if (!mapped) {
return getLocationInPixels ();
return getLocation ();
}
return super.getSurfaceOrigin( );
}
Expand Down