Skip to content

[Win32] Retrieving handle for cursor leads to non-disposed resource error #2355

Description

@HeikoKlare

Describe the bug
When retrieving a handle for a cursor that does not yet exist (because it is required for a different zoom), a non-disposed resource error is printed in case the non-disposed resource tracker is enabled.

This is caused by the Cursor#win32_getHandle() method creating a cursor instance just to extract the handle out of it. So it's actually intended that the cursor is not disposed, as that would also dispose the handle, but the implementation itself is strange as it should not be necessary to create such a dummy cursor at all:

Cursor newCursor = new Cursor(cursor.device, source, cursor.hotspotX, cursor.hotspotY);
cursor.setHandleForZoomLevel(newCursor.handle, zoom);

When taking a look at the issue, it should also be considered that for the hotspotX/hotspotY values no scaling is considered, i.e., for every zoomed version of the cursor the same hotspot coordinates are used even though the image data is at different scales. That seems to be wrong.

To Reproduce
The error can be produced with the following simple snippet executed on a Windows machine with a primary monitor zoom <= 150%:

	Cursor cursor = new Cursor(Display.getDefault(), new ImageData(1, 1, 24, new PaletteData(0xFF, 0xFF00, 0xFF0000)), 0, 0);
	Cursor.win32_getHandle(cursor, 200);
	System.gc();
	Thread.sleep(1000);

Note that the System.gc() call is just there to ensure that the dummy cursor is cleaned up by GC, which yields the error, and the Thread.sleep() ensures that the JVM has sufficient time to print the error (as otherwise it may stop before the printing is finished).

Expected behavior
No non-disposed resource should be created and tracked when retrieving cursor handles. Actually I would not expect a dummy cursor to be created just for the sake of getting a handle at all.

Environment:

  1. Select the platform(s) on which the behavior is seen:
    • All OS
    • Windows
    • Linux
    • macOS
  1. Additional OS info (e.g. OS version, Linux Desktop, etc)
    Any Windows version

  2. JRE/JDK version
    irrelevant

Version since
Eclipse 2024-12, precisely #1603

Workaround (or) Additional context
The error can just be ignored, there is no negative effect. It's just an irrelevant error that indicates a design flaw.

Activity

  1. ShahzaibIbrahim commented on Jul 30, 2025

    @ShahzaibIbrahim
    Contributor

    Problem

    Currently, when retrieving a handle for a specific zoom level via win32_getHandle, a new Cursor resource is internally created just to obtain the native handle. This leads to two major issues:

    • The temporary resource is never disposed, causing resource leaks.
    • We cannot safely return a handle from a previously disposed Cursor instance.

    Proposed Solution

    To fix this, the Cursor class should be refactored to manage zoom-level-specific handles more robustly and safely. The following changes are needed:

    1. Extract OS Handle Creation Logic
      Move the logic responsible for creating native OS handles out of the constructors and into a separate method. This allows win32_getHandle to lazily create and cache handles on demand.

    2. Always Initialize Default Zoom Handle
      Upon creation of a new Cursor, always initialize and store the handle for the default zoom level (100) immediately. This ensures that the cursor is usable right after construction.

    3. Remove handle Field
      Eliminate the dedicated handle field from the class. All handle accesses should go through the zoomLevelToHandle map, which now acts as the single source of truth for all zoom levels.

    4. Update All Related Methods
      Refactor all methods that previously relied on the handle field to instead use zoomLevelToHandle. This includes:

      • hashCode()
      • equals(Object obj)
      • isDisposed()
      • destroy()

    Benefits

    • Eliminates resource leaks by ensuring that all handles are properly tracked and owned by the cursor instance.
    • Enables safe, lazy creation of per-zoom handles when needed.
    • Ensures default usability by initializing the zoom=100 handle at construction time.
    • Simplifies and centralizes handle management logic for better maintainability.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions