Skip to content

DropTargetContext: get the target actions from the peer - #72

Open
duncanmcqueen wants to merge 1 commit into
ingelabs:masterfrom
duncanmcqueen:fix-dtc-target-actions
Open

duncanmcqueen wants to merge 1 commit into
ingelabs:masterfrom
duncanmcqueen:fix-dtc-target-actions

Conversation

@duncanmcqueen

Copy link
Copy Markdown
Contributor

Split from #57.

Problem and fix

DropTargetContext.getTargetActions() returns a field that only setTargetActions() sets, and nothing calls setTargetActions() during a drag. Thus the field is 0, and DropTargetDragEvent.getDropAction() and DropTargetDropEvent.getDropAction() always return ACTION_NONE.

As in the JDK, getTargetActions() now asks the peer, and setTargetActions() also gives the actions to the peer. Without a peer, getTargetActions() returns the default actions of the drop target. I found this bug when I wrote an AWT toolkit for Haiku, which supplies drag and drop peers.

How to reproduce

The method is protected, so the test calls it with reflection. It tests the context without a peer, and then with a peer that has the target action ACTION_COPY (StubDropPeer, below).

javac StubDropPeer.java DropContextActions.java
java DropContextActions
DropContextActions.java
import java.awt.*;
import java.awt.dnd.*;
import java.lang.reflect.Method;

/**
 * DropTargetContext.getTargetActions() must return the actions of its
 * peer, or the default actions of the drop target when it has no peer.
 * DropTargetDragEvent.getDropAction() and DropTargetDropEvent.getDropAction()
 * use it. The method is protected, so the test calls it with reflection.
 */
public class DropContextActions
{
  static boolean failed;

  static void check(String what, int got, int expected)
  {
    System.out.println((got == expected ? "PASS " : "FAIL ") + what + " = "
                       + got + ", expected " + expected);
    failed |= got != expected;
  }

  public static void main(String[] args) throws Exception
  {
    DropTarget dt = new DropTarget(new Canvas(), DnDConstants.ACTION_COPY_OR_MOVE,
                                   new DropTargetAdapter()
      {
        public void drop(DropTargetDropEvent e) {}
      });
    DropTargetContext dtc = dt.getDropTargetContext();
    Method m = DropTargetContext.class.getDeclaredMethod("getTargetActions");
    m.setAccessible(true);
    check("getTargetActions() without a peer", (Integer) m.invoke(dtc),
          DnDConstants.ACTION_COPY_OR_MOVE);
    dtc.addNotify(new StubDropPeer(dt, DnDConstants.ACTION_COPY));
    check("getTargetActions() with a peer", (Integer) m.invoke(dtc),
          DnDConstants.ACTION_COPY);
    System.exit(failed ? 1 : 0);
  }
}
StubDropPeer.java
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.dnd.peer.DropTargetContextPeer;

/** A DropTargetContextPeer that offers text and the given target actions. */
public class StubDropPeer implements DropTargetContextPeer
{
  int actions;
  DropTarget target;

  StubDropPeer(DropTarget target, int actions)
  {
    this.target = target;
    this.actions = actions;
  }

  public void setTargetActions(int a) { actions = a; }
  public int getTargetActions() { return actions; }
  public DropTarget getDropTarget() { return target; }
  public DataFlavor[] getTransferDataFlavors()
  {
    return new DataFlavor[] { DataFlavor.stringFlavor };
  }
  public Transferable getTransferable() { return new StringSelection("text"); }
  public boolean isTransferableJVMLocal() { return true; }
  public void acceptDrag(int a) {}
  public void rejectDrag() {}
  public void acceptDrop(int a) {}
  public void rejectDrop() {}
  public void dropComplete(boolean ok) {}
}

Results

Linux x86_64, ingelabs/classpath master (0406074), JamVM master, javac from JDK 8, autoconf 2.73, automake 1.19, the configure options of the CI Linux job, out-of-tree build. "Before" is master. "After" is master with this commit.

Before:
FAIL getTargetActions() without a peer = 0, expected 3
FAIL getTargetActions() with a peer = 0, expected 1

After:
PASS getTargetActions() without a peer = 3, expected 3
PASS getTargetActions() with a peer = 1, expected 1

JDK 8 (1.8.0_504) gives the "After" result.

Platforms

Not specific to Haiku. The problem is in java.awt.dnd and occurs with all toolkits. I reproduced it on Linux.

AI assistance

An AI model (Claude Code, by Anthropic) wrote this change, the test and this text. The repository owner directed the work and checked the results. Please review it as you review other contributions.

🤖 Generated with Claude Code

getTargetActions() returned a field that only setTargetActions() set,
and nothing calls setTargetActions() during a drag. Thus the field was
0, and DropTargetDragEvent.getDropAction() and
DropTargetDropEvent.getDropAction() always returned ACTION_NONE.

As in the JDK, ask the peer for the target actions, and give
setTargetActions() to the peer. Without a peer, use the drop target's
default actions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: duncanmcqueen <206344294+duncanmcqueen@users.noreply.github.com>
@duncanmcqueen
duncanmcqueen marked this pull request as ready for review October 14, 2026 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant