diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/internal/ImageListTests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/internal/ImageListTests.java index e6959bef316..aa470f735b7 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/internal/ImageListTests.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/internal/ImageListTests.java @@ -132,4 +132,158 @@ public void testIsFittingForDistinguishesSize() { } } + @Test + public void testAddReturnsConsecutiveIndicesForConsecutiveImages() { + ImageList list = new ImageList(SWT.NONE, 16, 16, 100); + Image[] images = createImages(3); + try { + assertEquals(0, list.add(images[0])); + assertEquals(1, list.add(images[1])); + assertEquals(2, list.add(images[2])); + } finally { + disposeAll(list, images); + } + } + + @Test + public void testAddReusesSlotOfRemovedImage() { + ImageList list = new ImageList(SWT.NONE, 16, 16, 100); + Image[] images = createImages(3); + try { + list.add(images[0]); + list.add(images[1]); + list.put(0, null); + + assertEquals(0, list.add(images[2])); + assertSame(images[2], list.get(0)); + } finally { + disposeAll(list, images); + } + } + + @Test + public void testPutAppendsImageAtEndOfList() { + ImageList list = new ImageList(SWT.NONE, 16, 16, 100); + Image[] images = createImages(2); + try { + list.add(images[0]); + + list.put(1, images[1]); + + assertSame(images[1], list.get(1)); + assertEquals(2, list.size()); + } finally { + disposeAll(list, images); + } + } + + @Test + public void testPutReplacesImageInsideList() { + ImageList list = new ImageList(SWT.NONE, 16, 16, 100); + Image[] images = createImages(3); + try { + list.add(images[0]); + list.add(images[1]); + + list.put(0, images[2]); + + assertSame(images[2], list.get(0)); + assertEquals(2, list.size()); + } finally { + disposeAll(list, images); + } + } + + @Test + public void testPutWithoutImageClearsSlotInsideList() { + ImageList list = new ImageList(SWT.NONE, 16, 16, 100); + Image[] images = createImages(2); + try { + list.add(images[0]); + list.add(images[1]); + + list.put(0, null); + + assertNull(list.get(0)); + assertSame(images[1], list.get(1)); + assertEquals(1, list.size()); + } finally { + disposeAll(list, images); + } + } + + @Test + public void testPutBeyondEndOfListIsIgnored() { + ImageList list = new ImageList(SWT.NONE, 16, 16, 100); + Image[] images = createImages(2); + try { + list.add(images[0]); + + list.put(2, images[1]); + + assertEquals(1, list.size()); + } finally { + disposeAll(list, images); + } + } + + @Test + public void testPutNegativeIndexIsIgnored() { + ImageList list = new ImageList(SWT.NONE, 16, 16, 100); + Image[] images = createImages(2); + try { + list.add(images[0]); + + list.put(-1, images[1]); + + assertSame(images[0], list.get(0)); + assertEquals(1, list.size()); + } finally { + disposeAll(list, images); + } + } + + /** + * Tool bars address their normal, hot and disabled image list with a single + * index per item, so an image must be storable at a given index instead of at + * whatever slot the individual list happens to have free. + */ + @Test + public void testPutKeepsListsAlignedWhenTheirFreeSlotsDiffer() { + ImageList list = new ImageList(SWT.NONE, 16, 16, 100); + ImageList hotList = new ImageList(SWT.NONE, 16, 16, 100); + Image[] images = createImages(4); + try { + list.add(images[0]); + hotList.add(images[1]); + // only the first list has a free slot from here on + list.put(0, null); + + int index = list.add(images[2]); + hotList.put(index, images[3]); + + assertEquals(0, index); + assertSame(images[2], list.get(index)); + assertSame(images[3], hotList.get(index)); + } finally { + hotList.dispose(); + disposeAll(list, images); + } + } + + private static Image[] createImages(int count) { + Image[] images = new Image[count]; + for (int i = 0; i < count; i++) { + images[i] = new Image(Display.getDefault(), 16, 16); + } + return images; + } + + private static void disposeAll(ImageList list, Image[] images) { + list.dispose(); + for (Image image : images) { + image.dispose(); + } + } + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/ImageList.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/ImageList.java index c32726acb1b..fb7dd9ded6f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/ImageList.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/ImageList.java @@ -55,6 +55,11 @@ public int add (Image image) { if (imageAtIndex == null) break; index++; } + put (index, image); + return index; +} + +private void append (int index, Image image, int count) { if (count == 0) { Rectangle bounds = image.getBounds(); width = bounds.width; @@ -68,7 +73,6 @@ public int add (Image image) { images = newImages; } images [index] = image; - return index; } private Image getOrClearIfDisposed(int index) { @@ -386,9 +390,19 @@ public int indexOf (Image image) { return -1; } +/** + * Stores the given image at the given index, replacing whatever is stored at that index. Passing + * no image clears the index. The index may also address the slot right after the last one, in + * which case a new slot is appended for the given image. Nothing happens for any other index + * outside the list's current size. + */ public void put (int index, Image image) { if ((0 <= index && index < images.length) && (images [index] == image)) return; int count = OS.ImageList_GetImageCount (handle); + if (index == count && image != null) { + append (index, image, count); + return; + } if (!(0 <= index && index < count)) return; if (image != null) setForAllHandles(index, image, count); images [index] = image; diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java index 68e839fcefe..703dd50c7db 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBar.java @@ -55,7 +55,8 @@ public class ToolBar extends Composite { ToolItem [] items; ToolItem [] tabItemList; boolean ignoreResize, ignoreMouse; - ImageList imageList, disabledImageList, hotImageList; + private ToolBarImageLists imageLists; + static final long ToolBarProc; static final TCHAR ToolBarClass = new TCHAR (OS.TOOLBARCLASSNAME, true); static { @@ -143,6 +144,21 @@ public ToolBar (Composite parent, int style) { } } +/* + * The given image bounds are the bounds of the tool item's image and determine which shared image + * lists are used. They are intentionally not derived from the images actually added: for a disabled + * item with CHECK or RADIO style, those are the disabled images, which may have different bounds. + * Note that the icon size of an image list is defined by the first image added to it. + */ +int addImage(Rectangle imageBounds, Image image, Image hotImage, Image disabledImage) { + if (imageLists == null) { + imageLists = createImageLists(imageBounds.width, imageBounds.height); + } + int index = imageLists.add(image, hotImage, disabledImage); + refreshImageLists(true); + return index; +} + @Override long callWindowProc (long hwnd, int msg, long wParam, long lParam) { if (handle == 0) return 0; @@ -199,6 +215,23 @@ public void layout (boolean changed) { super.layout(changed); } +private void clearAndReleaseImageLists() { + if (imageLists != null) { + // the image lists must be unset before refreshing, so that they are detached from the tool + // bar, and they must only be released once the tool bar does not reference them anymore + ToolBarImageLists releasedImageLists = imageLists; + imageLists = null; + refreshImageLists(false); + releasedImageLists.release(); + } +} + +void clearImage(int index) { + if (imageLists != null) { + imageLists.clear(index); + } +} + void clearSizeCache(boolean changed) { // If changed, discard the cached layout information if (changed) { @@ -375,6 +408,10 @@ void createHandle () { OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, bits); } +private ToolBarImageLists createImageLists(int width, int height) { + return ToolBarImageLists.create(display, style & SWT.RIGHT_TO_LEFT, width, height, getAutoscalingZoom()); +} + void createItem (ToolItem item, int index) { int count = (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE); @@ -440,9 +477,9 @@ void destroyItem (ToolItem item) { * an image and one is never assigned, this is not a problem. */ if ((info.fsStyle & OS.BTNS_SEP) == 0 && info.iImage != OS.I_IMAGENONE) { - if (imageList != null) imageList.put (info.iImage, null); - if (hotImageList != null) hotImageList.put (info.iImage, null); - if (disabledImageList != null) disabledImageList.put (info.iImage, null); + if (imageLists != null) { + imageLists.clear(info.iImage); + } } OS.SendMessage (handle, OS.TB_DELETEBUTTON, index, 0); if (item.id == lastFocusId) lastFocusId = -1; @@ -452,19 +489,7 @@ void destroyItem (ToolItem item) { item.id = -1; int count = (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); if (count == 0) { - if (imageList != null) { - OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0); - display.releaseToolImageList (imageList); - } - if (hotImageList != null) { - OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0); - display.releaseToolHotImageList (hotImageList); - } - if (disabledImageList != null) { - OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0); - display.releaseToolDisabledImageList (disabledImageList); - } - imageList = hotImageList = disabledImageList = null; + clearAndReleaseImageLists(); items = new ToolItem [4]; } if ((style & SWT.VERTICAL) != 0) setRowCount (count - 1); @@ -495,18 +520,6 @@ void enableWidget (boolean enabled) { } } -ImageList getDisabledImageList () { - return disabledImageList; -} - -ImageList getHotImageList () { - return hotImageList; -} - -ImageList getImageList () { - return imageList; -} - /** * Returns the item at the given, zero-relative index in the * receiver. Throws an exception if the index is out of range. @@ -869,6 +882,49 @@ boolean mnemonicMatch (char ch) { return findMnemonic (items [id [0]].text) != '\0'; } +void putImage(int index, Image image, Image hotImage, Image disabledImage) { + if (imageLists != null) { + imageLists.put(index, image, hotImage, disabledImage); + } +} + +private void refreshImageLists(boolean itemsChanged) { + long imageListHandle = 0, hotImageListHandle = 0, disabledImageListHandle = 0; + if (imageLists != null) { + int zoom = getAutoscalingZoom(); + imageListHandle = imageLists.getImageListHandle(zoom); + hotImageListHandle = imageLists.getHotImageListHandle(zoom); + disabledImageListHandle = imageLists.getDisabledImageListHandle(zoom); + } + boolean imageListOutdated = isImageListOutdated(OS.TB_GETIMAGELIST, imageListHandle); + boolean hotImageListOutdated = isImageListOutdated(OS.TB_GETHOTIMAGELIST, hotImageListHandle); + boolean disabledImageListOutdated = isImageListOutdated(OS.TB_GETDISABLEDIMAGELIST, disabledImageListHandle); + if (!imageListOutdated && !hotImageListOutdated && !disabledImageListOutdated) { + return; + } + // clear the BTNS_DROPDOWN bits while the image lists are exchanged, see + // setDropDownItems() + if (itemsChanged) { + setDropDownItems(false); + } + if (imageListOutdated) { + OS.SendMessage(handle, OS.TB_SETIMAGELIST, 0, imageListHandle); + } + if (hotImageListOutdated) { + OS.SendMessage(handle, OS.TB_SETHOTIMAGELIST, 0, hotImageListHandle); + } + if (disabledImageListOutdated) { + OS.SendMessage(handle, OS.TB_SETDISABLEDIMAGELIST, 0, disabledImageListHandle); + } + if (itemsChanged) { + setDropDownItems(true); + } +} + +private boolean isImageListOutdated(int getMessageCode, long expectedHandle) { + return OS.SendMessage(handle, getMessageCode, 0, 0) != expectedHandle; +} + @Override void releaseChildren (boolean destroy) { if (items != null) { @@ -885,19 +941,7 @@ void releaseChildren (boolean destroy) { @Override void releaseWidget () { super.releaseWidget (); - if (imageList != null) { - OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0); - display.releaseToolImageList (imageList); - } - if (hotImageList != null) { - OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0); - display.releaseToolHotImageList (hotImageList); - } - if (disabledImageList != null) { - OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0); - display.releaseToolDisabledImageList (disabledImageList); - } - imageList = hotImageList = disabledImageList = null; + clearAndReleaseImageLists(); } @Override @@ -1000,19 +1044,6 @@ void setDropDownItems (boolean set) { } } -void setDisabledImageList (ImageList imageList) { - long hImageList = 0; - if ((disabledImageList = imageList) != null) { - hImageList = OS.SendMessage(handle, OS.TB_GETDISABLEDIMAGELIST, 0, 0); - long newImageList = disabledImageList.getHandle(getAutoscalingZoom()); - if (hImageList == newImageList) return; - hImageList = newImageList; - } - setDropDownItems (false); - OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, hImageList); - setDropDownItems (true); -} - @Override public void setFont (Font font) { checkWidget (); @@ -1039,32 +1070,6 @@ public void setFont (Font font) { layoutItems (); } -void setHotImageList (ImageList imageList) { - long hImageList = 0; - if ((hotImageList = imageList) != null) { - hImageList = OS.SendMessage(handle, OS.TB_GETHOTIMAGELIST, 0, 0); - long newImageList = hotImageList.getHandle(getAutoscalingZoom()); - if (hImageList == newImageList) return; - hImageList = newImageList; - } - setDropDownItems (false); - OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, hImageList); - setDropDownItems (true); -} - -void setImageList (ImageList imageList) { - long hImageList = 0; - if ((this.imageList = imageList) != null) { - hImageList = OS.SendMessage(handle, OS.TB_GETIMAGELIST, 0, 0); - long newImageList = imageList.getHandle(getAutoscalingZoom()); - if (hImageList == newImageList) return; - hImageList = newImageList; - } - setDropDownItems (false); - OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, hImageList); - setDropDownItems (true); -} - @Override public boolean setParent (Composite parent) { checkWidget (); @@ -1224,11 +1229,10 @@ String toolTipText (NMTTDISPINFO hdr) { @Override void updateOrientation () { super.updateOrientation (); - if (imageList != null) { - Point sizeInPoints = imageList.getImageSize(); - ImageList newImageList = display.getImageListToolBar (style & SWT.RIGHT_TO_LEFT, sizeInPoints.x, sizeInPoints.y, getAutoscalingZoom()); - ImageList newHotImageList = display.getImageListToolBarHot (style & SWT.RIGHT_TO_LEFT, sizeInPoints.x, sizeInPoints.y, getAutoscalingZoom()); - ImageList newDisabledImageList = display.getImageListToolBarDisabled (style & SWT.RIGHT_TO_LEFT, sizeInPoints.x, sizeInPoints.y, getAutoscalingZoom()); + if (imageLists != null) { + Point size = imageLists.getImageSize(); + ToolBarImageLists oldImageLists = imageLists; + imageLists = createImageLists(size.x, size.y); TBBUTTONINFO info = new TBBUTTONINFO (); info.cbSize = TBBUTTONINFO.sizeof; info.dwMask = OS.TBIF_IMAGE; @@ -1239,27 +1243,12 @@ void updateOrientation () { if (item.image == null) continue; OS.SendMessage (handle, OS.TB_GETBUTTONINFO, item.id, info); if (info.iImage != OS.I_IMAGENONE) { - Image image = imageList.get(info.iImage); - Image hot = hotImageList.get(info.iImage); - Image disabled = disabledImageList.get(info.iImage); - imageList.put(info.iImage, null); - hotImageList.put(info.iImage, null); - disabledImageList.put(info.iImage, null); - info.iImage = newImageList.add(image); - newHotImageList.add(hot); - newDisabledImageList.add(disabled); + info.iImage = imageLists.moveFrom(oldImageLists, info.iImage); OS.SendMessage (handle, OS.TB_SETBUTTONINFO, item.id, info); } } - display.releaseToolImageList (imageList); - display.releaseToolHotImageList (hotImageList); - display.releaseToolDisabledImageList (disabledImageList); - OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, newImageList.getHandle(getAutoscalingZoom())); - OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, newHotImageList.getHandle(getAutoscalingZoom())); - OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, newDisabledImageList.getHandle(getAutoscalingZoom())); - imageList = newImageList; - hotImageList = newHotImageList; - disabledImageList = newDisabledImageList; + refreshImageLists(false); + oldImageLists.release(); OS.InvalidateRect (handle, null, true); } } @@ -1744,9 +1733,7 @@ record ToolItemData(ToolItem toolItem, TBBUTTON button) { } } // Refresh the image lists so the image list for the correct zoom is used - setImageList(getImageList()); - setDisabledImageList(getDisabledImageList()); - setHotImageList(getHotImageList()); + refreshImageLists(true); boolean toolBarEnabled = getEnabled(); for (int i = 0; i < itemCount; i++) { ToolItem item = toolItems[i]; diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBarImageLists.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBarImageLists.java new file mode 100644 index 00000000000..ed77c748c5a --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolBarImageLists.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2026 Vector Informatik GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.*; + +/** + * Owns the normal, hot and disabled image lists of a tool bar as a single unit. + * The three lists are always created, filled, cleared and released together, so + * they are of equal image size and the index returned when adding an item's + * images addresses that item in all three of them. + *

+ * Synchronizing the image lists with the native tool bar is up to the owning + * tool bar, which retrieves the handles to set via + * {@link #getImageListHandle(int)} and its hot and disabled counterparts. + */ +class ToolBarImageLists { + private final Display display; + + private final ImageList imageList, disabledImageList, hotImageList; + + private ToolBarImageLists(Display display, ImageList imageList, ImageList hotImageList, + ImageList disabledImageList) { + this.display = display; + this.imageList = imageList; + this.hotImageList = hotImageList; + this.disabledImageList = disabledImageList; + } + + static ToolBarImageLists create(Display display, int style, int width, int height, int zoom) { + ImageList imageList = display.getImageListToolBar(style, width, height, zoom); + ImageList hotImageList = display.getImageListToolBarHot(style, width, height, zoom); + ImageList disabledImageList = display.getImageListToolBarDisabled(style, width, height, zoom); + return new ToolBarImageLists(display, imageList, hotImageList, disabledImageList); + } + + void clear(int index) { + imageList.put(index, null); + hotImageList.put(index, null); + disabledImageList.put(index, null); + } + + void release() { + display.releaseToolImageList(imageList); + display.releaseToolHotImageList(hotImageList); + display.releaseToolDisabledImageList(disabledImageList); + } + + int add(Image image, Image hotImage, Image disabledImage) { + int index = imageList.add(image); + // Use the slot index from the normal image list as authoritative source + // for the image ordering and reuse it for the hot and disabled lists + // instead of letting each of them scan for its own free slot, so all + // three stay index-aligned. + hotImageList.put(index, hotImage); + disabledImageList.put(index, disabledImage); + return index; + } + + void put(int index, Image image, Image hotImage, Image disabledImage) { + imageList.put(index, image); + hotImageList.put(index, hotImage); + disabledImageList.put(index, disabledImage); + } + + int moveFrom(ToolBarImageLists source, int index) { + Image image = source.imageList.get(index); + Image hotImage = source.hotImageList.get(index); + Image disabledImage = source.disabledImageList.get(index); + source.clear(index); + return add(image, hotImage, disabledImage); + } + + long getImageListHandle(int zoom) { + return imageList.getHandle(zoom); + } + + long getHotImageListHandle(int zoom) { + return hotImageList.getHandle(zoom); + } + + long getDisabledImageListHandle(int zoom) { + return disabledImageList.getHandle(zoom); + } + + Point getImageSize() { + return imageList.getImageSize(); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java index 94b020a5a77..4d62213d857 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/ToolItem.java @@ -535,12 +535,7 @@ void releaseImages () { * an image and one is never assigned, this is not a problem. */ if ((info.fsStyle & OS.BTNS_SEP) == 0 && info.iImage != OS.I_IMAGENONE) { - ImageList imageList = parent.getImageList (); - ImageList hotImageList = parent.getHotImageList (); - ImageList disabledImageList = parent.getDisabledImageList(); - if (imageList != null) imageList.put (info.iImage, null); - if (hotImageList != null) hotImageList.put (info.iImage, null); - if (disabledImageList != null) disabledImageList.put (info.iImage, null); + parent.clearImage(info.iImage); } } @@ -1099,21 +1094,7 @@ void updateImages (boolean enabled) { info.dwMask = OS.TBIF_IMAGE; OS.SendMessage (hwnd, OS.TB_GETBUTTONINFO, id, info); if (info.iImage == OS.I_IMAGENONE && image == null) return; - ImageList imageList = parent.getImageList (); - ImageList hotImageList = parent.getHotImageList (); - ImageList disabledImageList = parent.getDisabledImageList(); if (info.iImage == OS.I_IMAGENONE) { - Rectangle boundsInPoints = image.getBounds(); - int listStyle = parent.style & SWT.RIGHT_TO_LEFT; - if (imageList == null) { - imageList = display.getImageListToolBar (listStyle, boundsInPoints.width, boundsInPoints.height, getAutoscalingZoom()); - } - if (disabledImageList == null) { - disabledImageList = display.getImageListToolBarDisabled (listStyle, boundsInPoints.width, boundsInPoints.height, getAutoscalingZoom()); - } - if (hotImageList == null) { - hotImageList = display.getImageListToolBarHot (listStyle, boundsInPoints.width, boundsInPoints.height, getAutoscalingZoom()); - } Image disabled = disabledImage; if (disabledImage == null) { if (disabledImage2 != null) disabledImage2.dispose (); @@ -1134,27 +1115,19 @@ void updateImages (boolean enabled) { if ((style & (SWT.CHECK | SWT.RADIO)) != 0) { if (!enabled) image2 = hot = disabled; } - info.iImage = imageList.add (image2); - disabledImageList.add (disabled); - hotImageList.add (hot != null ? hot : image2); - parent.setImageList (imageList); - parent.setDisabledImageList (disabledImageList); - parent.setHotImageList (hotImageList); + info.iImage = parent.addImage(image.getBounds(), image2, hot != null ? hot : image2, disabled); } else { Image disabled = null; - if (disabledImageList != null) { - if (image != null) { - if (disabledImage2 != null) disabledImage2.dispose (); - disabledImage2 = null; - disabled = disabledImage; - if (disabledImage == null) { - disabled = image; - if (!enabled) { - disabled = disabledImage2 = new Image (display, image, SWT.IMAGE_DISABLE); - } + if (image != null) { + if (disabledImage2 != null) disabledImage2.dispose (); + disabledImage2 = null; + disabled = disabledImage; + if (disabledImage == null) { + disabled = image; + if (!enabled) { + disabled = disabledImage2 = new Image (display, image, SWT.IMAGE_DISABLE); } } - disabledImageList.put (info.iImage, disabled); } /* * Bug in Windows. When a tool item with the style @@ -1167,12 +1140,14 @@ void updateImages (boolean enabled) { if ((style & (SWT.CHECK | SWT.RADIO)) != 0) { if (!enabled) image2 = hot = disabled; } - if (imageList != null) { - imageList.put (info.iImage, image2); - } - if (hotImageList != null) { - hotImageList.put (info.iImage, hot != null ? hot : image2); - } + + /* + * When the normal image is cleared (image2 == null) the button stops + * referencing this slot (iImage becomes I_IMAGENONE below), so the hot + * image must be freed too instead of leaving the old hot image behind + * for a later item that reuses this slot. + */ + parent.putImage(info.iImage, image2, image2 != null ? (hot != null ? hot : image2) : null, disabled); if (image == null) info.iImage = OS.I_IMAGENONE; }