From a967db2efb4a6f45d4bdbee431069d201c670229 Mon Sep 17 00:00:00 2001 From: richard Date: Tue, 15 Jun 1999 09:23:39 +0000 Subject: [PATCH] Update front-end support for registering dnd types. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@4407 72102866-910b-0410-8b05-ffd578937521 --- Headers/gnustep/gui/GSDragManager.h | 37 ------- Headers/gnustep/gui/NSGraphicsContext.h | 10 ++ Headers/gnustep/gui/NSView.h | 4 + Source/GNUmakefile | 2 - Source/GSDragManager.m | 75 -------------- Source/NSGraphicsContext.m | 87 ++++++++++++++++ Source/NSView.m | 130 +++++++++++++++++++++++- Source/NSWindow.m | 21 ++-- 8 files changed, 240 insertions(+), 126 deletions(-) delete mode 100644 Headers/gnustep/gui/GSDragManager.h delete mode 100644 Source/GSDragManager.m diff --git a/Headers/gnustep/gui/GSDragManager.h b/Headers/gnustep/gui/GSDragManager.h deleted file mode 100644 index ea4af9b9e..000000000 --- a/Headers/gnustep/gui/GSDragManager.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - GSDragManager.h - - Copyright (C) 1999 Free Software Foundation, Inc. - - Author: Richard Frith-Macdonald - Date: June 1999 - - This file is part of the GNUstep GUI Library. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. - If not, write to the Free Software Foundation, - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#ifndef _GNUstep_H_GSDragManager -#define _GNUstep_H_GSDragManager - -#include - -NSArray *GSGetDragTypes(id obj); -void GSRegisterDragTypes(id obj, NSArray *types); -void GSUnregisterDragTypes(id obj); - -#endif - diff --git a/Headers/gnustep/gui/NSGraphicsContext.h b/Headers/gnustep/gui/NSGraphicsContext.h index 408825fb3..78443a796 100644 --- a/Headers/gnustep/gui/NSGraphicsContext.h +++ b/Headers/gnustep/gui/NSGraphicsContext.h @@ -31,6 +31,8 @@ #include #include +#include +#include #include @@ -100,6 +102,7 @@ typedef enum _NSWindowOrderingMode NSMutableData *context_data; NSMutableArray *focus_stack; NSMutableArray *event_queue; + NSMapTable *drag_types; } + (NSGraphicsContext*) currentContext; @@ -129,6 +132,13 @@ NSGraphicsContext *GSCurrentContext(); - (void) lockFocusView: (NSView*)aView inRect: (NSRect)rect; - (void) unlockFocusView: (NSView*)aView needsFlush: (BOOL)flush; +/* + * Drag and drop support + */ +- (BOOL) _addDragTypes: (NSArray*)types toWindow: (int)winNum; +- (BOOL) _removeDragTypes: (NSArray*)types fromWindow: (int)winNum; +- (NSCountedSet*) _dragTypesForWindow: (int)winNum; + @end #endif diff --git a/Headers/gnustep/gui/NSView.h b/Headers/gnustep/gui/NSView.h index 8f9cfb65d..5e655c9ea 100644 --- a/Headers/gnustep/gui/NSView.h +++ b/Headers/gnustep/gui/NSView.h @@ -378,6 +378,10 @@ enum { @end #endif +/* + * GNUstep specific function to determine the drag types registered for a view. + */ +extern NSArray *GSGetDragTypes(NSView* aView); /* Notifications */ extern NSString *NSViewFrameDidChangeNotification; diff --git a/Source/GNUmakefile b/Source/GNUmakefile index d89494426..42e36ddaf 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -109,7 +109,6 @@ NSView.m \ NSWindow.m \ NSWorkspace.m \ GSTrackingRect.m \ -GSDragManager.m \ GSServicesManager.m \ tiff.m \ externs.m @@ -213,7 +212,6 @@ AppKit/GSMethodTable.h \ AppKit/DPSOperators.h \ AppKit/PSOperators.h \ AppKit/GSPasteboardServer.h \ -AppKit/GSDragManager.h \ AppKit/GSServicesManager.h -include GNUmakefile.preamble diff --git a/Source/GSDragManager.m b/Source/GSDragManager.m deleted file mode 100644 index 74a128c08..000000000 --- a/Source/GSDragManager.m +++ /dev/null @@ -1,75 +0,0 @@ -/* - GSDragManager.m - - Copyright (C) 1999 Free Software Foundation, Inc. - - Author: Richard Frith-Macdonald - Date: June 1999 - - This file is part of the GNUstep GUI Library. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. - If not, write to the Free Software Foundation, - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include - -#include -#include - -/* - * Stuff to maintain a map table so we know what windows and views are - * registered for drag and drop. - * FIXME - may need locks for thread safety? - */ -static NSMapTable *typesMap = 0; - -static inline void -GSSetupDragTypes() -{ - if (typesMap == 0) - { - typesMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, - NSObjectMapValueCallBacks, 0); - } -} - -NSArray* -GSGetDragTypes(id obj) -{ - GSSetupDragTypes(); - return NSMapGet(typesMap, (void*)(gsaddr)obj); -} - -void -GSRegisterDragTypes(id obj, NSArray *types) -{ - NSArray *m = [types mutableCopy]; - NSArray *t = [m copy]; - - RELEASE(m); - GSSetupDragTypes(); - NSMapInsert(typesMap, (void*)(gsaddr)obj, (void*)(gsaddr)t); - RELEASE(t); -} - -void -GSUnregisterDragTypes(id obj) -{ - GSSetupDragTypes(); - NSMapRemove(typesMap, (void*)(gsaddr)obj); -} - - diff --git a/Source/NSGraphicsContext.m b/Source/NSGraphicsContext.m index f06d3e3b6..6585e3957 100644 --- a/Source/NSGraphicsContext.m +++ b/Source/NSGraphicsContext.m @@ -155,6 +155,7 @@ struct NSWindow_struct DESTROY(context_data); DESTROY(context_info); DESTROY(event_queue); + NSFreeMapTable(drag_types); [super dealloc]; } @@ -182,6 +183,8 @@ struct NSWindow_struct initWithCapacity: 1]; event_queue = [[NSMutableArray allocWithZone: [self zone]] initWithCapacity: 32]; + drag_types = NSCreateMapTable(NSIntMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); /* * The classMethodTable dictionary and the list of all contexts must both @@ -263,6 +266,90 @@ struct NSWindow_struct [focus_stack removeLastObject]; } +/* + * Drag and drop support + */ + +/* + * Add (increment count by 1) each drag type to those registered + * for the window. If this results in a change to the types registered + * in the counted set, return YES, otherwise return NO. + * Subclasses should override this method, call 'super' and take + * appropriate action if the method returns 'YES'. + */ +- (BOOL) _addDragTypes: (NSArray*)types toWindow: (int)winNum +{ + NSCountedSet *old = (NSCountedSet*)NSMapGet(drag_types, winNum); + unsigned originalCount; + unsigned i = [types count]; + + /* + * Make sure the set exists. + */ + if (old == nil) + { + old = [NSCountedSet new]; + NSMapInsert(drag_types, (void*)winNum, (void*)(gsaddr)old); + RELEASE(old); + } + originalCount = [old count]; + + while (i-- > 0) + { + id o = [types objectAtIndex: i]; + + [old removeObject: o]; + } + if ([old count] == originalCount) + return NO; + return YES; +} + +/* + * Remove (decrement count by 1) each drag type from those registered + * for the window. If this results in a change to the types registered + * in the counted set, return YES, otherwise return NO. + * If given 'nil' as the array of types, remove ALL. + * Subclasses should override this method, call 'super' and take + * appropriate action if the method returns 'YES'. + */ +- (BOOL) _removeDragTypes: (NSArray*)types fromWindow: (int)winNum +{ + NSCountedSet *old = (NSCountedSet*)NSMapGet(drag_types, winNum); + + if (types == nil) + { + if (old == nil) + return NO; + NSMapRemove(drag_types, (void*)winNum); + return YES; + } + else if (old == nil) + { + return NO; + } + else + { + unsigned originalCount = [old count]; + unsigned i = [types count]; + + while (i-- > 0) + { + id o = [types objectAtIndex: i]; + + [old removeObject: o]; + } + if ([old count] == originalCount) + return NO; + return YES; + } +} + +- (NSCountedSet*) _dragTypesForWindow: (int)winNum +{ + return (NSCountedSet*)NSMapGet(drag_types, winNum); +} + @end @implementation NSGraphicsContext (Private) diff --git a/Source/NSView.m b/Source/NSView.m index 16a1c9fa9..2da9658c3 100644 --- a/Source/NSView.m +++ b/Source/NSView.m @@ -47,7 +47,6 @@ #include #include -#include #include #include @@ -67,6 +66,72 @@ static SEL appSel = @selector(appendTransform:); static void (*invalidateImp)(NSView*, SEL) = 0; static SEL invalidateSel = @selector(_invalidateCoordinates); +/* + * Stuff to maintain a map table so we know what views are + * registered for drag and drop - we don't store the info in + * the view directly 'cot it would take up a pointer in each + * view and the vast majority of views wouldn't use it. + * Types are not registered/unregistered often enough for the + * performance of this mechanism to be an issue. + */ +static NSMapTable *typesMap = 0; +static NSLock *typesLock = nil; + +/* + * This is the only external interface to the drag types info. + */ +NSArray* +GSGetDragTypes(NSView *obj) +{ + NSArray *t; + + [typesLock lock]; + t = (NSArray*)NSMapGet(typesMap, (void*)(gsaddr)obj); + [typesLock unlock]; + return t; +} + +static void +GSRemoveDragTypes(NSView* obj) +{ + [typesLock lock]; + NSMapRemove(typesMap, (void*)(gsaddr)obj); + [typesLock unlock]; +} + +static NSArray* +GSSetDragTypes(NSView* obj, NSArray *types) +{ + unsigned count = [types count]; + NSString *strings[count]; + NSArray *t; + unsigned i; + + /* + * Make a new array with copies of the type strings so we don't get + * them mutated by someone else. + */ + [types getObjects: strings]; + for (i = 0; i < count; i++) + { + strings[i] = [strings[i] copy]; + } + t = [NSArray arrayWithObjects: strings count: count]; + for (i = 0; i < count; i++) + { + RELEASE(strings[i]); + } + /* + * Store it. + */ + [typesLock lock]; + NSMapInsert(typesMap, (void*)(gsaddr)obj, (void*)(gsaddr)t); + [typesLock unlock]; + return t; +} + + + /* * Class methods */ @@ -77,6 +142,10 @@ static SEL invalidateSel = @selector(_invalidateCoordinates); Class matrixClass = [NSAffineTransform class]; NSAffineTransformStruct ats = { 1, 0, 0, -1, 0, 1 }; + typesMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + typesLock = [NSLock new]; + appImp = (void (*)(NSAffineTransform*, SEL, NSAffineTransform*)) [matrixClass instanceMethodForSelector: appSel]; @@ -405,7 +474,21 @@ static SEL invalidateSel = @selector(_invalidateCoordinates); - (void) viewWillMoveToWindow: (NSWindow*)newWindow { + if (newWindow == window) + return; + + if (_rFlags.has_draginfo) + { + NSGraphicsContext *ctxt = GSCurrentContext(); + NSArray *t = GSGetDragTypes(self); + + if (window != nil) + [ctxt _removeDragTypes: t fromWindow: [window windowNumber]]; + [ctxt _addDragTypes: t toWindow: [newWindow windowNumber]]; + } + window = newWindow; + if (_rFlags.has_subviews) { unsigned count = [sub_views count]; @@ -1772,17 +1855,56 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level) slideBack: (BOOL)slideFlag {} -- (void) registerForDraggedTypes: (NSArray*)newTypes +- (void) registerForDraggedTypes: (NSArray*)types { - GSRegisterDragTypes(self, newTypes); + NSArray *o; + NSArray *t; + + if (types == nil || [types count] == 0) + [NSException raise: NSInvalidArgumentException + format: @"Types information missing"]; + + /* + * Get the old drag types for this view if we need to tell the context + * to change the registered types for the window. + */ + if (_rFlags.has_draginfo == 1 && window != nil) + { + o = GSGetDragTypes(self); + TEST_RETAIN(o); + } + else + { + o = nil; + } + + t = GSSetDragTypes(self, types); _rFlags.has_draginfo = 1; + if (window != nil) + { + NSGraphicsContext *ctxt = GSCurrentContext(); + + [ctxt _addDragTypes: t toWindow: [window windowNumber]]; + if (o != nil) + { + [ctxt _removeDragTypes: t fromWindow: [window windowNumber]]; + } + } + TEST_RELEASE(o); } - (void) unregisterDraggedTypes { if (_rFlags.has_draginfo) { - GSUnregisterDragTypes(self); + if (window != nil) + { + NSGraphicsContext *ctxt = GSCurrentContext(); + NSArray *t = GSGetDragTypes(self); + + [ctxt _removeDragTypes: t fromWindow: [window windowNumber]]; + } + GSRemoveDragTypes(self); _rFlags.has_draginfo = 0; } } diff --git a/Source/NSWindow.m b/Source/NSWindow.m index 5b1f59162..9b91fbdbf 100644 --- a/Source/NSWindow.m +++ b/Source/NSWindow.m @@ -181,7 +181,12 @@ static Class responderClass; TEST_RELEASE(miniaturized_image); TEST_RELEASE(window_title); TEST_RELEASE(rectsBeingDrawn); - [self unregisterDraggedTypes]; + + /* + * FIXME This should not be necessary - the views should have removed + * their drag types, so we should already have been removed. + */ + [GSCurrentContext() _removeDragTypes: nil fromWindow: [self windowNumber]]; [super dealloc]; } @@ -1464,17 +1469,17 @@ static Class responderClass; - (void) registerForDraggedTypes: (NSArray*)newTypes { - GSRegisterDragTypes(self, newTypes); - _rFlags.has_draginfo = 1; + /* + * Ensure we have a content view and it's associated window view. + */ + if (content_view == nil) + [self setContentView: nil]; + [[content_view superView] registerForDraggedTypes: newTypes]; } - (void) unregisterDraggedTypes { - if (_rFlags.has_draginfo) - { - GSUnregisterDragTypes(self); - _rFlags.has_draginfo = 0; - } + [[content_view superView] unregisterDraggedTypes]; } /*