Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,36 @@ class DropTarget: NSView {
init(frame frameRect: NSRect, channel: FlutterMethodChannel) {
self.channel = channel
super.init(frame: frameRect)
self.wantsLayer = true
self.layer?.backgroundColor = NSColor.clear.cgColor
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func hitTest(_ point: NSPoint) -> NSView? {
if !isDragging {
return nil
}
if NSApp.currentEvent?.type == .leftMouseDragged ||
NSApp.currentEvent?.type == .rightMouseDragged {
return super.hitTest(point)
}
return nil
}
Comment on lines +95 to +104
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hitTest(_:) returns nil whenever isDragging is false, but isDragging is only set to true inside draggingEntered. On macOS, AppKit typically determines the drag destination view via hit-testing; if this view never hit-tests positive at the start of a drag, draggingEntered may never be delivered and drag & drop can stop working entirely. Consider allowing hit-testing for drag sessions regardless of isDragging (e.g., base the decision solely on the current drag event / dragging session), then use isDragging only to control subsequent event handling/state.

Copilot uses AI. Check for mistakes.

private var isDragging = false

private func isDragEvent(_ event: NSEvent?) -> Bool {
guard let event = event else { return false }
return event.type == .leftMouseDragged ||
event.type == .rightMouseDragged ||
event.type == .otherMouseDragged
}
Comment on lines +95 to +113
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isDragEvent(_:) treats .otherMouseDragged as a drag event, but hitTest(_:) only checks .leftMouseDragged/.rightMouseDragged. This inconsistency can cause different behavior depending on which mouse button initiates the drag. Consider aligning hitTest(_:) with isDragEvent(_:) (or consolidating the logic) so drag detection is consistent.

Copilot uses AI. Check for mistakes.

override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
isDragging = true
channel.invokeMethod("entered", arguments: convertPoint(sender.draggingLocation))
return .copy
}
Expand All @@ -101,9 +124,14 @@ class DropTarget: NSView {
}

override func draggingExited(_ sender: NSDraggingInfo?) {
isDragging = false
channel.invokeMethod("exited", arguments: nil)
}

override func draggingEnded(_ sender: NSDraggingInfo) {
isDragging = false
}

/// Create a per-drop destination for promised files (avoids name collisions).
private func uniqueDropDestination() -> URL {
let base = FileManager.default.temporaryDirectory.appendingPathComponent("Drops", isDirectory: true)
Expand Down Expand Up @@ -193,10 +221,59 @@ class DropTarget: NSView {
group.notify(queue: .main) {
self.channel.invokeMethod("performOperation_macos", arguments: items)
}
isDragging = false
return true
}

func convertPoint(_ location: NSPoint) -> [CGFloat] {
return [location.x, bounds.height - location.y]
}

override func mouseDown(with event: NSEvent) {
if !isDragging && !isDragEvent(event) {
nextResponder?.mouseDown(with: event)
} else {
super.mouseDown(with: event)
}
}

override func mouseUp(with event: NSEvent) {
if !isDragging && !isDragEvent(event) {
nextResponder?.mouseUp(with: event)
} else {
super.mouseUp(with: event)
}
}

override func mouseDragged(with event: NSEvent) {
if !isDragging && !isDragEvent(event) {
nextResponder?.mouseDragged(with: event)
} else {
super.mouseDragged(with: event)
}
}

override func mouseMoved(with event: NSEvent) {
if !isDragging && !isDragEvent(event) {
nextResponder?.mouseMoved(with: event)
} else {
super.mouseMoved(with: event)
}
}

override func rightMouseDown(with event: NSEvent) {
if !isDragging && !isDragEvent(event) {
nextResponder?.rightMouseDown(with: event)
} else {
super.rightMouseDown(with: event)
}
}

override func rightMouseUp(with event: NSEvent) {
if !isDragging && !isDragEvent(event) {
nextResponder?.rightMouseUp(with: event)
} else {
super.rightMouseUp(with: event)
}
}
Comment on lines +232 to +278
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mouse event overrides forward to nextResponder, but nextResponder is typically the superview/window—not the actual view under the cursor—so this doesn’t reliably deliver events to underlying PlatformView instances. Also, when hitTest(_:) returns nil (the non-dragging case), these handlers generally won’t be called anyway, making them misleading. Prefer relying on hitTest pass-through alone, or explicitly forwarding to the view returned by window?.contentView?.hitTest(...) if you need manual forwarding.

Copilot uses AI. Check for mistakes.
}
Loading