diff --git a/ChangeLog b/ChangeLog index aebbcbab4..8f5cd0561 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +1999-07-29 Adam Fedor + + * Headers/gnustep/gui/NSEvent.h: Add AppKit dragging events. + * Headers/gnustep/gui/NSGraphicsContext.h: Added some internal drag + methods. + * Source/NSGraphicsContext.m (-_dragInfo): New method. + (-_postExternalEvent:): Likewise. + + * Headers/gnustep/gui/NSPasteboard.h: Added some internal mime type + conversions. + * Source/NSPasteboard.m (-_initMimeMappings): New method. + (-mimeTypeForPasteboardType:): Likewise. + (-pasteboardTypeForMimeType:): Likewise. + + * Headers/gnustep/gui/NSWindow.h: Added some drag ivars. + * Source/NSView.m (-dragImage...): Get the shared dragView and + call it. + * Source/NSWindow.m (-sendEvent:): For LeftMouseDown, send + mouseDown: to view if view is key (even if not first responder). + Handle AppKit dragging events. + + * Source/NSObjectProtocols.m: New file (Implement informal draggin + protocols). + 1999-07-27 Michael Hanni * Source/NSMenu.m: merge in all backend code. All that remains in diff --git a/Headers/gnustep/gui/NSEvent.h b/Headers/gnustep/gui/NSEvent.h index 52809504a..dfe38bb15 100644 --- a/Headers/gnustep/gui/NSEvent.h +++ b/Headers/gnustep/gui/NSEvent.h @@ -313,7 +313,13 @@ unsigned int NSEventMaskFromType(NSEventType type); #ifndef NO_GNUSTEP typedef enum { GSAppKitWindowMoved = 1, - GSAppKitWindowResized + GSAppKitWindowResized, + GSAppKitDraggingEnter, + GSAppKitDraggingUpdate, + GSAppKitDraggingStatus, + GSAppKitDraggingExit, + GSAppKitDraggingDrop, + GSAppKitDraggingFinished } GSAppKitSubtype; #endif diff --git a/Headers/gnustep/gui/NSGraphicsContext.h b/Headers/gnustep/gui/NSGraphicsContext.h index b31df053e..a8b2f8b4c 100644 --- a/Headers/gnustep/gui/NSGraphicsContext.h +++ b/Headers/gnustep/gui/NSGraphicsContext.h @@ -35,6 +35,7 @@ #include #include +#include @class NSDate; @class NSDictionary; @@ -138,6 +139,8 @@ NSGraphicsContext *GSCurrentContext(); - (BOOL) _addDragTypes: (NSArray*)types toWindow: (int)winNum; - (BOOL) _removeDragTypes: (NSArray*)types fromWindow: (int)winNum; - (NSCountedSet*) _dragTypesForWindow: (int)winNum; +- (id )_dragInfo; +- (void) _postExternalEvent: (NSEvent *)event; /* * Misc window management support. diff --git a/Headers/gnustep/gui/NSPasteboard.h b/Headers/gnustep/gui/NSPasteboard.h index cd9bc2233..4b9e8fe92 100644 --- a/Headers/gnustep/gui/NSPasteboard.h +++ b/Headers/gnustep/gui/NSPasteboard.h @@ -143,6 +143,9 @@ provideDataForType:(NSString *)type @end @interface NSPasteboard (GNUstepExtensions) ++ (NSString *) mimeTypeForPasteboardType: (NSString *)type; ++ (NSString *) pasteboardTypeForMimeType: (NSString *)mimeType; + - (void)setChangeCount: (int)changeCount; @end diff --git a/Headers/gnustep/gui/NSWindow.h b/Headers/gnustep/gui/NSWindow.h index 4533c6cd8..18f9df141 100644 --- a/Headers/gnustep/gui/NSWindow.h +++ b/Headers/gnustep/gui/NSWindow.h @@ -96,6 +96,7 @@ extern NSSize NSTokenSize; id original_responder; id delegate; id _fieldEditor; + id _lastDragView; int window_num; int gstate; NSColor *background_color; @@ -110,6 +111,7 @@ extern NSSize NSTokenSize; NSRect rectNeedingFlush; NSMutableArray *rectsBeingDrawn; + BOOL accepts_drag; BOOL is_one_shot; BOOL needs_display; BOOL needs_flush; diff --git a/Source/GNUmakefile b/Source/GNUmakefile index a720c10c9..dbb5b3fe0 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -85,6 +85,7 @@ NSMenuView.m \ NSMenuItem.m \ NSMenuItemCell.m \ NSOpenPanel.m \ +NSObjectProtocols.m \ NSPageLayout.m \ NSPanel.m \ NSParagraphStyle.m \ diff --git a/Source/NSGraphicsContext.m b/Source/NSGraphicsContext.m index 5b1c66a87..0a29e7ded 100644 --- a/Source/NSGraphicsContext.m +++ b/Source/NSGraphicsContext.m @@ -271,7 +271,7 @@ NSGraphicsContext *GSCurrentContext() { id o = [types objectAtIndex: i]; - [old removeObject: o]; + [old addObject: o]; } if ([old count] == originalCount) return NO; @@ -323,6 +323,17 @@ NSGraphicsContext *GSCurrentContext() return (NSCountedSet*)NSMapGet(drag_types, (void*)winNum); } +- (id )_dragInfo +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (void) _postExternalEvent: (NSEvent *)event; +{ + [self subclassResponsibility: _cmd]; +} + /* * Misc window management support. */ diff --git a/Source/NSPasteboard.m b/Source/NSPasteboard.m index 76ebca3fc..1794863bb 100644 --- a/Source/NSPasteboard.m +++ b/Source/NSPasteboard.m @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -65,7 +66,7 @@ static NSLock *dictionary_lock = nil; static NSMutableDictionary *pasteboards = nil; static id the_server = nil; - +static NSMapTable *mimeMap = NULL; // // Class methods @@ -731,6 +732,60 @@ static id the_server = nil; } NS_ENDHANDLER } + ++ (void) _initMimeMappings +{ + mimeMap = NSCreateMapTable(NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + NSMapInsert(mimeMap, (void *)NSStringPboardType, (void *)@"text/plain"); + NSMapInsert(mimeMap, (void *)NSFileContentsPboardType, + (void *)@"text/plain"); + NSMapInsert(mimeMap, (void *)NSFilenamesPboardType, + (void *)@"text/uri-list"); + NSMapInsert(mimeMap, (void *)NSPostScriptPboardType, + (void *)@"application/postscript"); + NSMapInsert(mimeMap, (void *)NSTabularTextPboardType, + (void *)@"text/tab-separated-values"); + NSMapInsert(mimeMap, (void *)NSRTFPboardType, (void *)@"text/richtext"); + NSMapInsert(mimeMap, (void *)NSTIFFPboardType, (void *)@"image/tiff"); + NSMapInsert(mimeMap, (void *)NSGeneralPboardType, (void *)@"text/plain"); +} + +/* Return the mapping for pasteboard->mime, or return the original pasteboard + type if no mapping is found */ ++ (NSString *) mimeTypeForPasteboardType: (NSString *)type +{ + NSString *mime; + if (mimeMap == NULL) + [self _initMimeMappings]; + mime = NSMapGet(mimeMap, (void *)type); + if (mime == nil) + mime = type; + return mime; +} + +/* Return the mapping for mime->pasteboard, or return the original pasteboard + type if no mapping is found. This method may not have a one-to-one + mapping */ ++ (NSString *) pasteboardTypeForMimeType: (NSString *)mimeType +{ + BOOL found; + NSString *type, *mime; + NSMapEnumerator enumerator; + + if (mimeMap == NULL) + [self _initMimeMappings]; + enumerator = NSEnumerateMapTable(mimeMap); + while ((found = NSNextMapEnumeratorPair(&enumerator, + (void **)(&type), (void **)(&mime)))) + if ([mimeType isEqual: mime]) + break; + + if (found == NO) + type = mimeType; + return type; +} + @end static NSString* contentsPrefix = @"NSTypedFileContentsPboardType: "; diff --git a/Source/NSView.m b/Source/NSView.m index ee66f5b04..f71b57064 100644 --- a/Source/NSView.m +++ b/Source/NSView.m @@ -2037,7 +2037,16 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level) pasteboard: (NSPasteboard*)pboard source: (id)sourceObject slideBack: (BOOL)slideFlag -{} +{ + NSView *dragView = (NSView *)[GSCurrentContext() _dragInfo]; + [dragView dragImage: anImage + at: viewLocation + offset: initialOffset + event: event + pasteboard: pboard + source: sourceObject + slideBack: slideFlag]; +} - (void) registerForDraggedTypes: (NSArray*)types { diff --git a/Source/NSWindow.m b/Source/NSWindow.m index 09764b2fd..2944f7191 100644 --- a/Source/NSWindow.m +++ b/Source/NSWindow.m @@ -54,7 +54,10 @@ #include #include #include +#include +#include +BOOL GSViewAcceptsDrag(NSView *v, id dragInfo); @interface GSWindowView : NSView { @@ -1405,7 +1408,7 @@ static NSRecursiveLock *windowsLock; if (first_responder != v) { [self makeFirstResponder: v]; - if ([v acceptsFirstMouse: theEvent] == YES) + if (is_key || [v acceptsFirstMouse: theEvent] == YES) [v mouseDown: theEvent]; } else @@ -1522,6 +1525,9 @@ static NSRecursiveLock *windowsLock; case NSAppKitDefined: { + id dragInfo; + int action; + NSEvent *e; GSAppKitSubtype sub = [theEvent subtype]; NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; @@ -1554,8 +1560,91 @@ static NSRecursiveLock *windowsLock; object: self]; break; - default: - break; +#define GSPerformDragSelector(view, sel, info, action) \ + if (view == content_view && delegate) \ + action = (int)[delegate performSelector: sel withObject: \ + info]; \ + else \ + action = (int)[view performSelector: sel withObject: info] +#define GSPerformVoidDragSelector(view, sel, info) \ + if (view == content_view && delegate) \ + [delegate performSelector: sel withObject: info]; \ + else \ + [view performSelector: sel withObject: info] + + case GSAppKitDraggingEnter: + case GSAppKitDraggingUpdate: + v = [content_view hitTest: [theEvent locationInWindow]]; + if (!v) + v = content_view; + dragInfo = [GSCurrentContext() _dragInfo]; + if (_lastDragView && _lastDragView != v && accepts_drag) + GSPerformVoidDragSelector(_lastDragView, + @selector(draggingExited:), dragInfo); + accepts_drag = GSViewAcceptsDrag(v, dragInfo); + if (_lastDragView != v && accepts_drag) + GSPerformDragSelector(v, @selector(draggingEntered:), + dragInfo, action); + else + GSPerformDragSelector(v, @selector(draggingUpdated:), + dragInfo, action); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: [theEvent locationInWindow] + modifierFlags: 0 + timestamp: 0 + windowNumber: [self windowNumber] + context: GSCurrentContext() + subtype: GSAppKitDraggingStatus + data1: [theEvent data1] + data2: action]; + [GSCurrentContext() _postExternalEvent: e]; + _lastDragView = v; + break; + + case GSAppKitDraggingStatus: + NSLog(@"Internal: dropped GSAppKitDraggingStatus event\n"); + break; + + case GSAppKitDraggingExit: + if (_lastDragView && accepts_drag) + GSPerformDragSelector(_lastDragView, + @selector(draggingExited:), dragInfo, + action); + break; + + case GSAppKitDraggingDrop: + if (_lastDragView && accepts_drag) + { + GSPerformDragSelector(_lastDragView, + @selector(prepareForDragOperation:), + dragInfo, action); + if (action) + GSPerformDragSelector(_lastDragView, + @selector(performDragOperation:), + dragInfo, action); + if (action) + GSPerformVoidDragSelector(_lastDragView, + @selector(concludeDragOperation:), + dragInfo); + } + e = [NSEvent otherEventWithType: NSAppKitDefined + location: [theEvent locationInWindow] + modifierFlags: 0 + timestamp: 0 + windowNumber: [self windowNumber] + context: GSCurrentContext() + subtype: GSAppKitDraggingFinished + data1: [theEvent data1] + data2: 0]; + [GSCurrentContext() _postExternalEvent: e]; + break; + + case GSAppKitDraggingFinished: + NSLog(@"Internal: dropped GSAppKitDraggingFinished event\n"); + break; + + default: + break; } } break; @@ -2056,3 +2145,12 @@ static NSRecursiveLock *windowsLock; } @end + +BOOL GSViewAcceptsDrag(NSView *v, id dragInfo) +{ + NSPasteboard *pb = [dragInfo draggingPasteBoard]; + if ([pb availableTypeFromArray: GSGetDragTypes(v)]) + return YES; + return NO; +} +