Drag-and-drop and deferred events

  • I'm trying to handle a drag-and-drop event from the main loop, and
    not from the inner run-loop created by the drag manager. I'm finding
    that sometimes things don't work 100% right while inside the drag
    manager's run-loop—e.g. when trying to move a bunch of items around
    in my outline view and re-select them in their new locations,
    sometimes not all of them actually end up selected when all is said
    and done. So I figured, OK, let's just do it from the main run-loop
    where it's always worked without any problems.

    So I'm doing something like this:

    - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id
    <NSDraggingInfo>)info item:(id)item childIndex:(int)childIndex {

        if (DropIsNoGood()) return NO; // pseudocode, you get the idea

        [self performSelector:@selector(sendDeferredDragEndEvent:)
                    withObject:[NSArray arrayWithObjects:treeView, info,
    item, [NSNumber numberWithInt:childIndex], NULL]
                    afterDelay:0.0
                      inModes:[NSArray
    arrayWithObject:NSDefaultRunLoopMode]];

        return YES;
    }

    However, inexplicably, sendDeferredDragEndEvent is still getting
    called from within the drag manager's run loop:

    #0    0x000f60f9 in -[MyTreeData sendDeferredDragEndEvent:] at
    MyTreeView.mm:307
    #1    0x9280d01b in __NSFireDelayedPerform
    #2    0x9082d782 in CFRunLoopRunSpecific
    #3    0x9082ca6e in CFRunLoopRunInMode
    #4    0x9282cd1a in -[NSRunLoop runMode:beforeDate:]
    #5    0x9287a8ec in -[NSRunLoop runUntilDate:]
    #6    0x935450e8 in NSCoreDragReceiveProc
    #7    0x917f917d in DoDropMessage
    #8    0x917f90ee in SendDropMessage
    #9    0x917f77ba in DragInApplication
    #10    0x917f60d3 in CoreDragStartDragging
    #11    0x9354ae2a in -[NSCoreDragManager _dragUntilMouseUp:accepted:]
    #12    0x9354a423 in -[NSCoreDragManager
    dragImage:fromWindow:at:offset:event:pasteboard:source:slideBack:]
    #13    0x93549e7b in -[NSWindow(NSDrag)
    dragImage:at:offset:event:pasteboard:source:slideBack:]
    #14    0x9354df4f in -[NSOutlineView
    dragImage:at:offset:event:pasteboard:source:slideBack:]
    #15    0x9354d250 in -[NSTableView
    _doImageDragUsingRowsWithIndexes:event:pasteboard:source:slideBack:]
    #16    0x933fae38 in -[NSTableView _performDragFromMouseDown:]
    #17    0x933f979e in -[NSTableView mouseDown:]
    #18    0x933f956f in -[NSOutlineView mouseDown:]
    #19    0x933723e3 in -[NSWindow sendEvent:]
    #20    0x93364384 in -[NSApplication sendEvent:]
    #21    0x9328ee1e in -[NSApplication run]
    #22    0x93282d4f in NSApplicationMain

    This seems like a bug in the frameworks to me. The core drag
    manager's run loop shouldn't be in the default run loop mode—it
    should be in the NSEventTrackingRunLoopMode mode. The way the docs
    spell it out, it could hardly be any clearer:

    > A run loop should be set to this mode when tracking events
    > modally, such as a mouse-dragging loop.

    Has anyone else had to deal with this and found a workaround? I've
    tried upping the delay to a very very small non-zero value, and that
    didn't fix it either. (And obviously it's no good to "play chicken"
    with it and keep increasing the delay value until it works—that's
    clearly a recipe for disaster.)

    FWIW I'm in Tiger right now. I haven't checked Leopard.
  • BTW, I've put this in as rdar://5686701 if any Apple employee is
    reading and feels like taking a quick look at this.
    If so, thanks for your help :)

    On Jan 14, 2008, at 10:18 AM, John Stiles wrote:

    > I'm trying to handle a drag-and-drop event from the main loop, and
    > not from the inner run-loop created by the drag manager. I'm
    > finding that sometimes things don't work 100% right while inside
    > the drag manager's run-loop—e.g. when trying to move a bunch of
    > items around in my outline view and re-select them in their new
    > locations, sometimes not all of them actually end up selected when
    > all is said and done. So I figured, OK, let's just do it from the
    > main run-loop where it's always worked without any problems.
    >
    > So I'm doing something like this:
    >
    > - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id
    > <NSDraggingInfo>)info item:(id)item childIndex:(int)childIndex {
    >
    > if (DropIsNoGood()) return NO; // pseudocode, you get the idea
    >
    > [self performSelector:@selector(sendDeferredDragEndEvent:)
    > withObject:[NSArray arrayWithObjects:treeView, info,
    > item, [NSNumber numberWithInt:childIndex], NULL]
    > afterDelay:0.0
    > inModes:[NSArray
    > arrayWithObject:NSDefaultRunLoopMode]];
    >
    > return YES;
    > }
    >
    > However, inexplicably, sendDeferredDragEndEvent is still getting
    > called from within the drag manager's run loop:
    >
    > #0    0x000f60f9 in -[MyTreeData sendDeferredDragEndEvent:] at
    > MyTreeView.mm:307
    > #1    0x9280d01b in __NSFireDelayedPerform
    > #2    0x9082d782 in CFRunLoopRunSpecific
    > #3    0x9082ca6e in CFRunLoopRunInMode
    > #4    0x9282cd1a in -[NSRunLoop runMode:beforeDate:]
    > #5    0x9287a8ec in -[NSRunLoop runUntilDate:]
    > #6    0x935450e8 in NSCoreDragReceiveProc
    > #7    0x917f917d in DoDropMessage
    > #8    0x917f90ee in SendDropMessage
    > #9    0x917f77ba in DragInApplication
    > #10    0x917f60d3 in CoreDragStartDragging
    > #11    0x9354ae2a in -[NSCoreDragManager _dragUntilMouseUp:accepted:]
    > #12    0x9354a423 in -[NSCoreDragManager
    > dragImage:fromWindow:at:offset:event:pasteboard:source:slideBack:]
    > #13    0x93549e7b in -[NSWindow(NSDrag)
    > dragImage:at:offset:event:pasteboard:source:slideBack:]
    > #14    0x9354df4f in -[NSOutlineView
    > dragImage:at:offset:event:pasteboard:source:slideBack:]
    > #15    0x9354d250 in -[NSTableView
    > _doImageDragUsingRowsWithIndexes:event:pasteboard:source:slideBack:]
    > #16    0x933fae38 in -[NSTableView _performDragFromMouseDown:]
    > #17    0x933f979e in -[NSTableView mouseDown:]
    > #18    0x933f956f in -[NSOutlineView mouseDown:]
    > #19    0x933723e3 in -[NSWindow sendEvent:]
    > #20    0x93364384 in -[NSApplication sendEvent:]
    > #21    0x9328ee1e in -[NSApplication run]
    > #22    0x93282d4f in NSApplicationMain
    >
    > This seems like a bug in the frameworks to me. The core drag
    > manager's run loop shouldn't be in the default run loop mode—it
    > should be in the NSEventTrackingRunLoopMode mode. The way the docs
    > spell it out, it could hardly be any clearer:
    >
    >> A run loop should be set to this mode when tracking events
    >> modally, such as a mouse-dragging loop.
    >
    >
    > Has anyone else had to deal with this and found a workaround? I've
    > tried upping the delay to a very very small non-zero value, and
    > that didn't fix it either. (And obviously it's no good to "play
    > chicken" with it and keep increasing the delay value until it works—
    > that's clearly a recipe for disaster.)
    >
    > FWIW I'm in Tiger right now. I haven't checked
    > Leopard.
  • I've checked this on Leopard and, sure enough, it's still happening there.
    So… no one's had to deal with this before? Really? :(

    John Stiles wrote:
    > BTW, I've put this in as rdar://5686701 if any Apple employee is
    > reading and feels like taking a quick look at this.
    > If so, thanks for your help :)
    >
    >
    > On Jan 14, 2008, at 10:18 AM, John Stiles wrote:
    >
    >> I'm trying to handle a drag-and-drop event from the main loop, and
    >> not from the inner run-loop created by the drag manager. I'm finding
    >> that sometimes things don't work 100% right while inside the drag
    >> manager's run-loop—e.g. when trying to move a bunch of items around
    >> in my outline view and re-select them in their new locations,
    >> sometimes not all of them actually end up selected when all is said
    >> and done. So I figured, OK, let's just do it from the main run-loop
    >> where it's always worked without any problems.
    >>
    >> So I'm doing something like this:
    >>
    >> - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id
    >> <NSDraggingInfo>)info item:(id)item childIndex:(int)childIndex {
    >>
    >> if (DropIsNoGood()) return NO; // pseudocode, you get the idea
    >>
    >> [self performSelector:@selector(sendDeferredDragEndEvent:)
    >> withObject:[NSArray arrayWithObjects:treeView, info,
    >> item, [NSNumber numberWithInt:childIndex], NULL]
    >> afterDelay:0.0
    >> inModes:[NSArray
    >> arrayWithObject:NSDefaultRunLoopMode]];
    >>
    >> return YES;
    >> }
    >>
    >> However, inexplicably, sendDeferredDragEndEvent is still getting
    >> called from within the drag manager's run loop:
    >>
    >> #0    0x000f60f9 in -[MyTreeData sendDeferredDragEndEvent:] at
    >> MyTreeView.mm:307
    >> #1    0x9280d01b in __NSFireDelayedPerform
    >> #2    0x9082d782 in CFRunLoopRunSpecific
    >> #3    0x9082ca6e in CFRunLoopRunInMode
    >> #4    0x9282cd1a in -[NSRunLoop runMode:beforeDate:]
    >> #5    0x9287a8ec in -[NSRunLoop runUntilDate:]
    >> #6    0x935450e8 in NSCoreDragReceiveProc
    >> #7    0x917f917d in DoDropMessage
    >> #8    0x917f90ee in SendDropMessage
    >> #9    0x917f77ba in DragInApplication
    >> #10    0x917f60d3 in CoreDragStartDragging
    >> #11    0x9354ae2a in -[NSCoreDragManager _dragUntilMouseUp:accepted:]
    >> #12    0x9354a423 in -[NSCoreDragManager
    >> dragImage:fromWindow:at:offset:event:pasteboard:source:slideBack:]
    >> #13    0x93549e7b in -[NSWindow(NSDrag)
    >> dragImage:at:offset:event:pasteboard:source:slideBack:]
    >> #14    0x9354df4f in -[NSOutlineView
    >> dragImage:at:offset:event:pasteboard:source:slideBack:]
    >> #15    0x9354d250 in -[NSTableView
    >> _doImageDragUsingRowsWithIndexes:event:pasteboard:source:slideBack:]
    >> #16    0x933fae38 in -[NSTableView _performDragFromMouseDown:]
    >> #17    0x933f979e in -[NSTableView mouseDown:]
    >> #18    0x933f956f in -[NSOutlineView mouseDown:]
    >> #19    0x933723e3 in -[NSWindow sendEvent:]
    >> #20    0x93364384 in -[NSApplication sendEvent:]
    >> #21    0x9328ee1e in -[NSApplication run]
    >> #22    0x93282d4f in NSApplicationMain
    >>
    >> This seems like a bug in the frameworks to me. The core drag
    >> manager's run loop shouldn't be in the default run loop mode—it
    >> should be in the NSEventTrackingRunLoopMode mode. The way the docs
    >> spell it out, it could hardly be any clearer:
    >>
    >>> A run loop should be set to this mode when tracking events
    >>> modally, such as a mouse-dragging loop.
    >>
    >>
    >> Has anyone else had to deal with this and found a workaround? I've
    >> tried upping the delay to a very very small non-zero value, and that
    >> didn't fix it either. (And obviously it's no good to "play chicken"
    >> with it and keep increasing the delay value until it works—that's
    >> clearly a recipe for disaster.)
    >>
    >> FWIW I'm in Tiger right now. I haven't checked
    >> Leopard.
    >
previous month january 2008 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today