summaryrefslogtreecommitdiffstats
path: root/macosx/macdnd.m
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/macdnd.m')
-rw-r--r--macosx/macdnd.m163
1 files changed, 110 insertions, 53 deletions
diff --git a/macosx/macdnd.m b/macosx/macdnd.m
index 060f215..d3d84b1 100644
--- a/macosx/macdnd.m
+++ b/macosx/macdnd.m
@@ -62,6 +62,7 @@ Tcl_Interp * TkDND_Interp(Tk_Window tkwin) {
NSPasteboard *sourcePasteBoard;
NSMutableArray *draggedtypes;
NSInteger tag;
+ NSEvent *lastMouseEvent;
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
@@ -102,19 +103,39 @@ TkWindow* TkMacOSXGetTkWindow(NSWindow *w) {
* added, and returned.
*/
DNDView* TkDND_GetDNDSubview(NSView *view, Tk_Window tkwin) {
- Rect bounds;
- NSRect frame;
+ NSRect frame, bounds;
DNDView* dnd_view = [view viewWithTag:TkDND_Tag];
- if (dnd_view != nil) return dnd_view;
- dnd_view = [[DNDView alloc] init];
- [dnd_view setTag:TkDND_Tag];
- if ([dnd_view superview] != view) {
- [view addSubview:dnd_view positioned:NSWindowBelow relativeTo:nil];
+ if (dnd_view == nil) {
+ dnd_view = [[DNDView alloc] init];
+ [dnd_view setTag:TkDND_Tag];
+ [dnd_view mouseDown:NULL];
+ if ([dnd_view superview] != view) {
+ [view addSubview:dnd_view positioned:NSWindowBelow relativeTo:nil];
+ }
+ [view setAutoresizesSubviews:true];
+ // Rect bnds;
+ // TkMacOSXWinBounds((TkWindow*)tkwin, &bnds);
+ // frame = NSMakeRect(bnds.left, bnds.top, 100000, 100000);
+ // frame.origin.y = 0;
+ // if (!NSEqualRects(frame, [dnd_view frame])) {
+ // [dnd_view setFrame:frame];
+ // }
}
+ if (dnd_view == nil) return dnd_view;
- TkMacOSXWinBounds((TkWindow*)tkwin, &bounds);
+ /* Ensure that we have the correct geometry... */
+ frame = [view frame];
+ if (!NSEqualRects(frame, [dnd_view frame])) {
+ [dnd_view setFrame:frame];
+ }
+ bounds = [view bounds];
+ if (!NSEqualRects(bounds, [dnd_view bounds])) {
+ [dnd_view setBounds:bounds];
+ }
+ return dnd_view;
+#if 0
/* Hack to make sure subview is set to take up entire geometry of window... */
frame = NSMakeRect(bounds.left, bounds.top, 100000, 100000);
frame.origin.y = 0;
@@ -122,9 +143,11 @@ DNDView* TkDND_GetDNDSubview(NSView *view, Tk_Window tkwin) {
[dnd_view setFrame:frame];
}
return dnd_view;
+#endif
}; /* TkDND_GetDNDSubview */
-/*Set flags for local DND operations, i.e. dragging within a single application window.*/
+/* Set flags for local DND operations, i.e. dragging within a single
+ application window.*/
- (int)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
if (isLocal) return NSDragOperationCopy;
return NSDragOperationCopy|NSDragOperationMove|NSDragOperationLink;
@@ -411,7 +434,7 @@ int TkDND_DoDragDropObjCmd(ClientData clientData, Tcl_Interp *interp,
Drawable d;
NSView *view;
DNDView *dragview;
- NSImage *dragicon;
+ NSImage *dragicon = NULL;
static char *DropTypes[] = {
"NSStringPboardType", "NSFilenamesPboardType",
(char *) NULL
@@ -428,14 +451,14 @@ int TkDND_DoDragDropObjCmd(ClientData clientData, Tcl_Interp *interp,
ActionCopy, ActionMove, ActionLink, ActionAsk, ActionPrivate,
refuse_drop, ActionDefault
};
- bool added_string = false, added_filenames = false;
+ bool added_string = false, added_filenames = false, perform_drag = false;
if (objc != 5) {
Tcl_WrongNumArgs(interp, 1, objv, "path actions types data");
return TCL_ERROR;
}
Tcl_ResetResult(interp);
-
+
/* Process drag actions. */
status = Tcl_ListObjGetElements(interp, objv[2], &elem_nu, &elem);
if (status != TCL_OK) return status;
@@ -466,12 +489,6 @@ int TkDND_DoDragDropObjCmd(ClientData clientData, Tcl_Interp *interp,
dragview = TkDND_GetDNDSubview(view, path);
if (dragview == NULL) return TCL_ERROR;
- /*
- * Get pasteboard. Make sure it is NSDragPboard; this will make data available
- * to drop targets via [sender draggingPasteboard]
- */
- NSPasteboard *dragpasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
-
/* Process drag types. */
status = Tcl_ListObjGetElements(interp, objv[3], &elem_nu, &elem);
if (status != TCL_OK) return status;
@@ -488,6 +505,7 @@ int TkDND_DoDragDropObjCmd(ClientData clientData, Tcl_Interp *interp,
if (!added_string) {
[draggedtypes addObject: NSStringPboardType];
added_string = true;
+ perform_drag = true;
}
break;
}
@@ -495,44 +513,59 @@ int TkDND_DoDragDropObjCmd(ClientData clientData, Tcl_Interp *interp,
if (!added_filenames) {
[draggedtypes addObject: NSFilenamesPboardType];
added_filenames = true;
+ perform_drag = true;
}
break;
}
}
}
- [dragpasteboard declareTypes:draggedtypes owner:nil];
-
-
- /*
- * We need an icon for the drag:
- * Interate over data types to process dragged data and display correct drag icon...
- */
+ if (!perform_drag) {
+ /* No need to start a drag, the clipboard will be empty... */
+ Tcl_SetResult(interp, "refuse_drop", TCL_STATIC);
+ return TCL_OK;
+ }
+
+ /*
+ * Get pasteboard. Make sure it is NSDragPboard; this will make data available
+ * to drop targets via [sender draggingPasteboard]
+ */
+ NSPasteboard *dragpasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ [dragpasteboard declareTypes:draggedtypes owner:dragview];
+ /*
+ * We need an icon for the drag:
+ * Interate over data types to process dragged data and display
+ * correct drag icon.
+ */
for (i = 0; i < elem_nu; i++) {
status = Tcl_GetIndexFromObj(interp, elem[i], (const char **) DropTypes,
"dropactions", 0, &index);
if (status == TCL_OK) {
switch ((enum droptypes) index) {
case TYPE_NSStringPboardType: {
- // Place the string in the clipboard
+ /* Place the string into the clipboard. */
NSString *datastring =
[NSString stringWithUTF8String:Tcl_GetString(objv[4])];
- [dragpasteboard setString:datastring forType:NSStringPboardType];
-
- //draw dragged string into drag icon, make sure icon is large enough to contain several lines of text
- dragicon = [[NSImage alloc] initWithSize:NSMakeSize(1000,1000)];
- [dragicon lockFocus];
- [[NSColor clearColor] set];
- NSRectFill(NSMakeRect(0, 0, 1000,1000));
- [datastring drawAtPoint: NSZeroPoint withAttributes: nil];
- [dragicon unlockFocus];
+ [dragpasteboard setString:datastring forType:NSStringPboardType];
+
+ /* Create a custom icon: draw dragged string into drag icon,
+ * make sure icon is large enough to contain several lines of text */
+ if (dragicon == NULL) {
+ dragicon = [[NSImage alloc]
+ initWithSize:NSMakeSize(Tk_Width(path), Tk_Height(path))];
+ [dragicon lockFocus];
+ [[NSColor clearColor] set];
+ NSRectFill(NSMakeRect(0, 0, 1000,1000));
+ [datastring drawAtPoint: NSZeroPoint withAttributes: nil];
+ [dragicon unlockFocus];
+ }
break;
}
case TYPE_NSFilenamesPboardType: {
NSMutableArray *filelist = [[NSMutableArray alloc] init];
-
- // Place the filenames in the clipboard
+
+ /* Place the filenames into the clipboard. */
status = Tcl_ListObjGetElements(interp, objv[4], &elem_nu, &elem);
if ( status == TCL_OK) {
for (i = 0; i < elem_nu; i++) {
@@ -542,20 +575,23 @@ int TkDND_DoDragDropObjCmd(ClientData clientData, Tcl_Interp *interp,
* and set pasteboard type */
NSString *filestring = [NSString stringWithUTF8String:filename];
[filelist addObject: filestring];
-
}
}
/* This successfully writes the file path data to the clipboard,
* and it is available to other non-Tk applications... */
[dragpasteboard setPropertyList:filelist forType:NSFilenamesPboardType];
-
- //set correct icon depending on whether single file [iconForFileType] or multiple files [NSImageNameMultipleDocuments]
- if ([filelist count] == 1) {
- NSString *pathtype = [[filelist objectAtIndex:0] pathExtension];
- dragicon = [[NSWorkspace sharedWorkspace] iconForFileType: pathtype];
- } else {
- dragicon = [NSImage imageNamed:NSImageNameMultipleDocuments];
- }
+
+ /* Set the correct icon depending on whether a single file
+ * [iconForFileType] or multiple files [NSImageNameMultipleDocuments]
+ * have been placed into the clipboard... */
+ if (dragicon == NULL) {
+ if ([filelist count] == 1) {
+ NSString *pathtype = [[filelist objectAtIndex:0] pathExtension];
+ dragicon = [[NSWorkspace sharedWorkspace] iconForFileType: pathtype];
+ } else {
+ dragicon = [NSImage imageNamed:NSImageNameMultipleDocuments];
+ }
+ }
break;
}
}
@@ -565,15 +601,35 @@ int TkDND_DoDragDropObjCmd(ClientData clientData, Tcl_Interp *interp,
}
/* Do drag & drop... */
-
- NSPoint p = NSMakePoint(0,0);
- NSSize s = NSMakeSize(0, 0);
-
+
+ /* Ensure that we always have a drag icon. If not, use a default one... */
+ if (dragicon == NULL) {
+ dragicon = [NSImage imageNamed:NSImageNameIconViewTemplate];
+ }
+
+ NSSize dragOffset = NSMakeSize(0.0, 0.0);
+
+ /* Get the mouse coordinates, so as the icon can slide back at the correct
+ * location, if the drag is cancelled. */
+ NSPoint global = [NSEvent mouseLocation];
+ NSPoint imageLocation = [[dragview window] convertScreenToBase:global];
+ NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseDragged
+ location:imageLocation
+ modifierFlags:NSLeftMouseDownMask
+ timestamp:0
+ windowNumber:[[dragview window] windowNumber]
+ context:NULL
+ eventNumber:0
+ clickCount:0
+ pressure:0
+ ];
+
+
/* Initiate the drag operation... */
[dragview dragImage:dragicon
- at:p
- offset:s
- event:NULL
+ at:imageLocation
+ offset:dragOffset
+ event:event
pasteboard:dragpasteboard
source:dragview
slideBack:YES];
@@ -678,6 +734,7 @@ int TkDND_UnregisterDragWidgetObjCmd(ClientData clientData, Tcl_Interp *ip,
DNDView *dropview = TkDND_GetDNDSubview(view, path);
if (dropview == NULL) return TCL_ERROR;
[dropview unregisterDraggedTypes];
+ [dropview mouseDown:NULL];
return TCL_OK;
}; /* TkDND_UnregisterDragWidgetObjCmd */