Repository navigation
Native operating system drag and drop, carrying the clipboard's own payload - #5662
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d480d757f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Compared 12 screenshots: 12 matched. |
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
|
Compared 151 screenshots: 151 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
Cloudflare Preview
|
|
Compared 181 screenshots: 181 matched. |
|
Compared 160 screenshots: 160 matched. Benchmark Results
Detailed Performance Metrics
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 739f5d94ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Compared 148 screenshots: 148 matched. Benchmark Results
Detailed Performance Metrics
|
|
Compared 144 screenshots: 144 matched. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7668b3794a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8c8190afaf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ee8afadae5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 945cc52052
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8c6e6b0377
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 281c900eec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ab88b4f47c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ab5dc154c9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
ab5dc15 to
737eb52
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 737eb52c73
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8ac7e4326c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
8ac7e43 to
25f144c
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 25f144c4eb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e819b12260
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4353c418cf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2452f1f542
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f67663b4cb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db0c0c034f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 005421dac8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… that answered for the wrong drag A window being hidden, minimized or disposed goes through cancelPendingInput, which clears the pressed component and the press token and never touched what the press had staged for the operating system. Only cancelPointerGesture did -- the other kind of cancellation, an overlay taking the pointer -- so a gesture staged on a window the user can no longer see was left for the next press that does not reach initDragAndDrop, or for the platform's own recognizer, to start a drag carrying that window's payload. It now goes the same way a form's does when the form is deinitialized, and by the same rule: only what belongs to this surface, so a window closing does not cancel a gesture staged somewhere still on screen. The marker for a drop still on its way to its target became a count last time, and a count answers "is anything pending" to a question that is always about one particular drag. A second drag that ended without a local drop of its own -- it was cancelled, or dropped into another application -- found the first drop still outstanding and skipped its own release, and since that first release names its own clip, nothing ever let go of the second one: its staged files stayed pinned until some later drag happened to take the slot. Kept by clip now, which is what the release beside it was already keyed by. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4c883311e2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ld outlive their exemption Target resolution walks outwards from the component under the pointer, so the innermost target wins -- that is what makes a move-only child inside a copy-capable parent work at all. Hit testing is what decides where the walk starts, and it promotes a focusable container over a child that is not focusable, which puts the start above the component the pointer is really over. The descent added for that ran only when the walk found nothing, so a focusable container that was *itself* a target simply took the drop meant for its child. The descent now runs first, inside what hit testing answered with, and the walk outwards follows it -- which is the order the rest of the resolution already assumes. An assembly was exempt from reclamation only while it was still growing, and its caller claims it afterwards. Between the two there is a gap, and a copy on Android's UI thread and a drag on the event dispatch thread assemble at the same time: one could finish and be waiting to be claimed while the other's staging triggered a reclamation that deleted its files, so the caller published, or dragged, a clip of dead URIs. Every assembly is now exempt until its caller has taken it over or given up on it, and the drag takes its hold before the assembly gives its exemption up, so there is no moment when neither holds it. And ACTION_DRAG_ENDED read the clip slot after queueing the completion. That listener runs on the event dispatch thread and may start the next drag, which claims the slot -- so the release let go of a drag that had only just begun. The ending session's clip is captured before anything is queued, and only that identity is released. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 26371a2df9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…swer The release that clears a drag's hold only when it is still that drag's compared under the lock and then cleared under a second one, and a completion listener on the event dispatch thread can start the next drag in between -- claiming the slot the comparison had just found safe to clear. The new drag's files were then reclaimable while it was still running. Both halves under one lock now. Nothing about the answer is worth reading if the thing it is about can change before it is used. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 82760494c6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The staging guard was keyed on the gesture having been offered to the platform, and UIKit begins its own drag from a long press that need never travel far enough for this framework to call it a drag at all -- so "offered" was still false at the moment the guard was there to cover. A second finger pressing another source in that window took the slot, and the session UIKit was about to begin exported that component's payload and reported its move against it. Keyed on the component instead. A press on the component that already owns the staging may always restage -- the drag is that component's either way, and that is what lets the next press inherit a gesture the platform dropped on the floor -- while a press on a different one leaves it alone, offered or not. The release guard beside it loses the same condition for the same reason, so the second finger's release no longer ends a gesture it never owned; the release that arrives with no press in progress still clears the slot, which is what keeps a staging from outliving every gesture on the surface. Inbound, a clip that named exactly one type and put its value in the item's text had that name thrown away: the value was published as text/plain, the type it was actually advertised under could not be satisfied from anything else, and it vanished -- so a target filtered to it accepted the hover and was refused the drop, and a paste got a bare string. The value now goes to the type the clip gave it, by the same reasoning the single unclaimed URI is paired with the single unsatisfied type. A clip that advertises text/plain, or more than one type, is read exactly as it was. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2f0f6cc20
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The staging guard was keyed on the component, and a component may hand out a different operation for every position -- createNativeDragOperation documents exactly that, for a list giving out the row under the finger. So a second finger elsewhere on the same component restaged a different payload, and the session the first finger's long press was about to become would have carried it. Keyed on the press token now, which is what tells two fingers apart on one component. That needed the one place where this framework dispatches a press twice for a single gesture to say so. A press that lands on a momentum-scrolling container is a "stop the glide" press, and Form defers it to the first drag packet, where it re-dispatches at *that* position: the re-dispatch mints a token of its own, so under a token rule it read as a foreign press and the guard kept the original staging -- with a drag origin two hundred pixels back, which made that very packet look like a drag and started one. The deferral now cancels what the original press staged before re-dispatching, which is what it means: the gesture is being decided again, from where it now is. Nothing is stranded by keying on the press. Every gesture ends in a release as far as this framework is concerned -- the iOS recognizer dispatches pointerReleased from touchesCancelled, and the other ports call gestureCancelled themselves -- so the press that owns a staging always gets to clear it. The test that pressed twice at one pixel with nothing in between now releases in between, which is what the ports actually deliver, and still asserts what it was written for: the second gesture carries its own payload. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 45dabd674b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A top level mints one press token and keeps only the newest, so when the first of two fingers is the one that lifts, its release arrives carrying the *second* finger's token. The staging guard added for the other direction then kept what the departed finger had staged, and the second finger's long press could become a session carrying it -- the payload of a gesture that was over. The position settles what the token cannot. A release lands where its own finger is, and a gesture that had travelled far enough to be somewhere else would have become a drag rather than sitting staged, so a release at the staged press's position is that press's release whatever token it carries. Within the same slop a press uses to become a drag, for the reason the drop's own recovery uses it. The pair now reads: a press may only take the slot its own press owns, and a release may only end the staging of the press that made it -- by token where the token still names it, by position where it cannot. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f828da68bf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The recovery for a target whose position moved reads the hover the drag left behind, and a drop that assembles after its session ended can arrive long after a *second* session has hovered the same surface. The release point then matched the newer hover, the newer session's target was still willing, and the older drop's payload was delivered to a component it was never dropped on. The hover now carries a generation, and a drop assembled later quotes back what it saw when the user released: while the number still matches, the hover is that drop's own, and the moment it does not the recovery is reading somebody else's. The iOS port takes it in performDrop and hands it to the commit, beside the action and the action mask it already takes there for exactly this reason -- and a port with nothing to quote passes NO_HOVER_GENERATION and gets what it always got. The iOS drag payload asked its URI list provider twice. declareDraggedUrls resolved the list off the content to split it into items, and the session's own memo -- which is what a receiver's later read goes through -- never saw that answer, so the provider ran again for the first receiver that asked. It now resolves through the session memo, which is the one place a drag is entitled to ask, and a provider that fails is remembered as having failed rather than being asked a second time. The first version of the test for the hover generation passed with the guard removed: the second session hovered somewhere else, so the release point never matched and the recovery was never reached. It now hovers where the first drop was released, which is the case the finding is about, and it fails without the guard. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3806e3f2cc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… operation retired mid-start The iOS drop budget deleted the oldest copies as soon as a newer drop committed, and a commit only *queues* the target's callback -- the payload is read inside it. Two large drops committing before the event dispatch thread has run the first callback, which happens when that thread is busy or when the callback itself sits in a nested event loop, had the first drop's copies deleted before its target ever opened them; on a local move the source then deleted the original too, and the payload was gone entirely. A drop is now owed to its target until the callback has returned, and reclamation skips what is owed rather than waiting for it -- the drops behind it may still be reclaimable. The port records the copies before the commit rather than after it, because the event dispatch thread can run that callback, and report the delivery finished, before the calling thread gets back; recorded afterwards, the report found nothing and the copies were owed for good. This is the same shape as the Android hold fixed earlier, in the other port's words: the release is queued behind the delivery it waits for, and named by the identity of the thing it releases. And startDrag read the operation's allowed actions before delivering the completion its previous session still owed. A listener may say anything about the operation it is being told about, including that nothing may be done with it any more, which is how a source retires an instance it reuses -- and the check that had already passed was about the session before. The port was then asked to start a session the operation's own contract says must not begin. Checked again after the completion, and the framework gives the session back rather than starting it, exactly as it does when the port refuses. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
build-macos failed compiling the translated application: two calls to virtual_java_lang_String_split were undeclared functions, which under -Werror=implicit-function-declaration is a build failure. ParparVM's java.lang.String has no split, and the iOS port's Java is translated by it -- the rest of this file has always split with com.codename1.io.Util for exactly that reason, five times over. Both of mine now do too. Nothing local catches this: the port compiles against a full JDK in the Ant and Maven builds, and it is the translation that has the smaller API. The other methods these additions use -- charAt, substring, trim, equalsIgnoreCase, Math.abs -- are all in vm/JavaAPI; split was the only one that is not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Seven jobs failed to link -- ios, ios-metal, ios-tv, ios-watch, native-ios,
macos and packaging -- on two undefined symbols: CN1UtiForMime and CN1MimeForUti,
referenced from the clipboard natives in IOSNative.m. Those natives are compiled
for every slice; the mapping they call sat below the #if that compiles out the
drag interaction on macOS, watchOS and tvOS, where there is no UIDragInteraction.
The mapping needs none of that -- it is Foundation and the type identifier
database -- so it now lives above the guard, with CoreServices where macOS keeps
what MobileCoreServices holds elsewhere, and availability spelled for all four
platforms rather than iOS alone.
CN1DropDeliveryFinished gets a stub in the guarded branch for the same reason: a
slice that cannot receive a drop has nothing owed to a target, but its native is
compiled all the same and the link needs the symbol.
Only the macOS build ever ran this far before -- the String.split error stopped
compilation short of the link, and fixing that let every one of these through to
it. Compiled and checked locally for all four slices this time, which is what I
should have been doing since the first of these symbols was exported:
for sdk in iphoneos macosx watchsimulator appletvsimulator; do
xcrun --sdk $sdk clang -c -fno-objc-arc -I. -isysroot "$(xcrun --sdk $sdk --show-sdk-path)" ...
nm -g CN1DragAndDrop.o | grep ' T _CN1'
done
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The chapter had its snippets but no entry under Samples/samples, which is where every other feature the guide documents keeps something you can actually run -- and for a feature about moving data between applications, running it is the only way to see it work at all. NativeDragAndDropSample drags text out under three types at once, so one gesture lands correctly in a rich text editor, a plain text field and a browser; promises a file that is written only when a receiver asks for it, which is the case the desktop exercises; and accepts drops into two zones, one that takes anything and reports what arrived -- the types, whether the drag came from this application, the action the system settled on -- and one filtered to files and to a copy, so a file manager offering a move is answered rather than refused. The hover callbacks light the zone up, since that is what a drop target uses to say it will take the drag. The chapter now points at it, the way In-Car-Experiences, Phone-Number-Verification and External-Surfaces point at theirs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous commit replaced Samples/samples/NativeDragAndDropSample wholesale on the belief that it was missing. It was not -- it went in with the feature and was revised once since -- so that commit deleted a hundred lines of working, reviewed sample and put a near-equivalent in its place. Restored verbatim. What stays is the one thing the chapter really lacked: a line pointing at the sample, the way In-Car-Experiences, Phone-Number-Verification and External-Surfaces point at theirs. Its wording now describes the sample that exists rather than the one I had written. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 254fa366a5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // still has the image to drag. | ||
| String[] files; | ||
| try { | ||
| files = content.getFiles(); |
There was a problem hiding this comment.
Resolve iOS file lists through the session memo
When the same ClipboardContent is being copied while UIKit starts a drag, this reads the content's shared LazyValue cache rather than the new ExportedDrag memo. The clipboard can therefore populate MIME_FILE after dragSessionStarted() resets it but before this read, causing the drag to reuse the clipboard transfer's generated temporary path instead of invoking the provider for its own session; conversely, the reset can make the concurrent copy invoke its provider twice. Resolve the file value through exported.produce(MIME_FILE) and normalize its String/String[] result, as the URI-list path already does.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 254fa366a5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| NSMutableDictionary* urlItem = | ||
| [NSMutableDictionary dictionaryWithObject:url forKey:@"public.url"]; |
There was a problem hiding this comment.
Publish iOS file entries as file URLs
When ClipboardContent.MIME_FILE is copied on iOS, every entry is published under public.url, even though this change maps the file representation to public.file-url and detects incoming files by conformance to that identifier in CN1DragAndDrop.m. Since public.file-url conforms to public.url rather than the reverse, file-only paste consumers do not see these items as files; select public.file-url for local file URLs while retaining public.url for web links.
Useful? React with 👍 / 👎.
|
Compared 217 screenshots: 217 matched. |
|
Compared 143 screenshots: 143 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 149 screenshots: 149 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
…needs (#5776) ByteCodeTranslator treated UniformTypeIdentifiers.framework as the macOS spelling of MobileCoreServices and linked it on that branch alone. It is not: MobileCoreServices carries only the deprecated C functions, while the UTType class lives in UniformTypeIdentifiers on every platform from iOS 14 / macOS 11 / watchOS 7 / tvOS 14. CN1DragAndDrop.m compiles that class into every slice -- its MIME-to-identifier mapping sits outside the UIKit guard because the clipboard natives need it too -- so an iOS application referenced _OBJC_CLASS_$_UTType with nothing defining it, and every device archive failed at the link. Link it on all slices, weakly: ios.deployment_target reaches back before the framework existed and a hard link against one the device lacks kills the process at launch, while the uses are already @available fenced. Classified in WatchNativeBuilder as linkable, verified present in both watch SDKs. Why no CI job caught it ----------------------- Every iOS job was green for five days, and structurally had to be. Nothing declared the framework there either -- the sample application supplies it by accident, three ways a plain application does not have: - a Swift autolink hint, since the sample has Swift in its app target and `import SwiftUI` stamps -framework UniformTypeIdentifiers into the object - CLANG_ENABLE_MODULES, which IPhoneBuilder turns on for the Metal build, so the same source links there and fails on the GL one - CocoaPods dependencies on the link line scripts/check-ios-framework-links.py closes that. It runs over the project build-ios-app.sh has already generated, compiles the port's natives with the project's own settings, and resolves their undefined symbols against the frameworks the project DECLARES -- never against an autolink hint, which is a load command rather than a definition and so cannot hide a symbol from nm. A native that fails to compile is fatal rather than skipped, and the SDK symbol index self-tests, because both of those failure modes report success. Verified: with the post-#5662 source injected into a project that does not declare the framework the gate fails naming UniformTypeIdentifiers.framework and _OBJC_CLASS_$_UTType; declaring it on the app target makes the gate pass. 79 of 79 port natives compile, 623 SDK symbols examined. The link itself was A/B'd with the real CN1DragAndDrop.m for arm64-apple-ios15.0: undefined without the framework, resolved with -weak_framework UniformTypeIdentifiers. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codename One's drag and drop has always been lightweight:
setDraggableandsetDropTargetmove a rendered image around inside one form. It never leaves the application, so it cannot drop a file on the desktop, cannot carry text into another application's window, and cannot receive anything from one.This adds the other half.
The idea
The payload is a
ClipboardContent-- the same object a copy publishes -- because a drag is a copy the user aims with the pointer. Whatever the application can already put on the clipboard it can already drag out, and whatever it can paste it can already accept as a drop. Offering several representations is what lets one drag land correctly in unrelated applications: a text editor takestext/html, a plain text field takestext/plain, and the desktop takes the file list.Core
ClipboardContentgains lazily built representations. That is what makes dragging a file out workable: the drag has to name the file when it starts, but the user may drop it nowhere, sosetDataProviderdeclares the representation without paying for it and the file is written at the moment a receiver reads it. It also gainssetFiles/getFiles-- which replaces theString-or-String[]duality every port was open-coding -- andtext/uri-list.NativeDragOperationcarries the payload, the allowed actions and the drag image.ACTION_MOVEmeans the receiver takes ownership and the source deletes its copy; the source only learns whether that happened once the platform has finished, so the outcome arrives through a completion listener rather than from the call that started the drag.New API, all in
com.codename1.ui:NativeDragAndDrop,NativeDragOperation,NativeDropEvent,ClipboardDataProvider, and onComponentthe drag-source and drop-target pairs. Orthogonal to the existingsetDraggable/setDropTarget, which are untouched.Threading
Drops arrive on the platform's own drag thread. The target is resolved there, from the accepted MIME types and actions alone, and the callbacks run on the event dispatch thread.
That is not fastidiousness. In the JavaSE port the event dispatch thread blocks on the AWT thread to blit every frame, so an AWT callback that waits on the event dispatch thread deadlocks on the first drag. The consequence is that a MIME filter is exact from the first drag event, while a decision made inside a callback reaches the cursor one event later -- a frame.
canAcceptNativeDropis the one method that runs off the event dispatch thread, and says so.Ports
DRAG_FLAG_GLOBALJavaSE goes through AWT's own drag machinery, so our own window is a drop target for our own drags too. The transferable that publishes a copy now publishes a drag as well; it derives its flavors from the MIME types alone rather than by reading values, which is what keeps a promised file unwritten until the drop.
Android shares the
ClipDataconversion the clipboard already had rather than growing a second one that would drift from it, including the file provider URIs that let the receiving application read generated bytes.iOS, iPadOS and Mac Catalyst use
UIDragInteraction/UIDropInteraction. UIKit owns the gesture -- its own recognizer decides a drag has begun and then asks what is being dragged -- so the framework stages the operation on the press and the native side announces the session afterwards. The payload is fetched at that later moment, so a drag offering a file the application has not written yet does not write it every time the user merely touches the component.Where the platform has none of this,
NativeDragAndDrop.isSupported()answers false, every call is a no-op, and the lightweight drag and drop is unaffected.Not covered: the JavaScript port and the native macOS, Windows and Linux ports.
Also fixed
A top level primes drag and drop twice per press -- once on the component under the pointer, once on its nearest draggable ancestor -- and the second pass discarded what the first had staged when the drag source sat between the two. Found while reviewing; covered by a regression test.
Verification
text/uri-list, target resolution and the action mapping.core-unittests,androidandios. Copyright, control-character, package-info, cast-semantics, native-signature and build-hint gates clean; Vale and LanguageTool clean on the guide.CN1DragAndDrop.mcompiles for real arm64 iOS, for Mac Catalyst and for the macOS stub branch. A full translation of the sample app confirms the new native sources ship and that all five Java callbacks survive dead-code elimination.Not verified: a physically driven operating system drag. Synthetic mouse input does not reach the window server on the machine this was built on, so a scripted drag proved nothing either way. Android and iOS are compile- and analysis-verified rather than device-run.
🤖 Generated with Claude Code