mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-22 16:10:48 +00:00
* Source/GSTheme.m: Remove code which sets and unsets images
on theme activation/deactivation. * Source/NSImage.m (+imageNamed:): Factor out code for finding the path for a name to a separate method, +pathForImageNamed. The code is unchanged otherwise, except for fixing the retrieval of images from the theme bundle, which was broken. * Source/NSImage.m (-setName:): Remove code for creating theme proxy. Subscribe/unscribe to theme change notification when the receiver is added/removed from the name dictionary. * Source/NSImage.m (-themeDidActivate:): Method called in response to a GSThemeDidActivateNotification on images with a name set. It does a path lookup in the same way that +imageNamed: would, and checks if the path has changed due to the theme change. If it has, all reps are discarded and the image at the new path is loaded. This avoids the need for the theme proxy objects. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@34474 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
82eac9eaf0
commit
bff0f57b54
3 changed files with 157 additions and 267 deletions
19
ChangeLog
19
ChangeLog
|
@ -1,3 +1,22 @@
|
|||
2012-01-09 Eric Wasylishen <ewasylishen@gmail.com>
|
||||
|
||||
* Source/GSTheme.m: Remove code which sets and unsets images
|
||||
on theme activation/deactivation.
|
||||
* Source/NSImage.m (+imageNamed:): Factor out code for finding
|
||||
the path for a name to a separate method, +pathForImageNamed.
|
||||
The code is unchanged otherwise, except for fixing the retrieval
|
||||
of images from the theme bundle, which was broken.
|
||||
* Source/NSImage.m (-setName:): Remove code for creating theme
|
||||
proxy. Subscribe/unscribe to theme change notification when
|
||||
the receiver is added/removed from the name dictionary.
|
||||
* Source/NSImage.m (-themeDidActivate:): Method called in
|
||||
response to a GSThemeDidActivateNotification on images with
|
||||
a name set. It does a path lookup in the same way that
|
||||
+imageNamed: would, and checks if the path has changed due
|
||||
to the theme change. If it has, all reps are discarded and
|
||||
the image at the new path is loaded. This avoids the need for
|
||||
the theme proxy objects.
|
||||
|
||||
2012-01-09 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/NSImage.m (+imageUnfilteredFileTypes, +imageFileTypes,
|
||||
|
|
110
Source/GSTheme.m
110
Source/GSTheme.m
|
@ -206,12 +206,6 @@ GSStringFromBorderType(NSBorderType borderType)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@interface NSImage (GSTheme)
|
||||
+ (NSImage*) _setImage: (NSImage*)image name: (NSString*)name;
|
||||
@end
|
||||
|
||||
@interface GSTheme (Private)
|
||||
- (void) _revokeOwnerships;
|
||||
@end
|
||||
|
@ -446,10 +440,7 @@ typedef struct {
|
|||
{
|
||||
NSUserDefaults *defs;
|
||||
NSMutableArray *searchList;
|
||||
NSArray *imagePaths;
|
||||
NSEnumerator *enumerator;
|
||||
NSString *imagePath;
|
||||
NSArray *imageTypes;
|
||||
NSDictionary *infoDict;
|
||||
NSWindow *window;
|
||||
GSThemeControlState state;
|
||||
|
@ -465,79 +456,6 @@ typedef struct {
|
|||
_extraColors[state] = nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* We step through all the bundle image resources and load them in
|
||||
* to memory, setting their names so that they are visible to
|
||||
* [NSImage+imageNamed:] and storing them in our local array.
|
||||
*/
|
||||
imageTypes = [_imageClass imageFileTypes];
|
||||
imagePaths = [_bundle pathsForResourcesOfType: nil
|
||||
inDirectory: @"ThemeImages"];
|
||||
enumerator = [imagePaths objectEnumerator];
|
||||
while ((imagePath = [enumerator nextObject]) != nil)
|
||||
{
|
||||
NSString *ext = [imagePath pathExtension];
|
||||
|
||||
if (ext != nil && [imageTypes containsObject: ext] == YES)
|
||||
{
|
||||
NSImage *image;
|
||||
NSString *imageName;
|
||||
|
||||
imageName = [imagePath lastPathComponent];
|
||||
imageName = [imageName stringByDeletingPathExtension];
|
||||
|
||||
image = [_images objectForKey: imageName];
|
||||
if (image == nil)
|
||||
{
|
||||
image = [[_imageClass alloc] initWithContentsOfFile: imagePath];
|
||||
if (image == nil)
|
||||
{
|
||||
NSLog(@"GSTheme failed to load %@ from %@",
|
||||
imageName, imagePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSImage *old;
|
||||
|
||||
/* OK, we have loaded a new image, so we cache it for the
|
||||
* lifetime of the theme, and we also make a record of
|
||||
* any previous/default image of the same name.
|
||||
*/
|
||||
[_images setObject: image forKey: imageName];
|
||||
RELEASE(image);
|
||||
old = [NSImage imageNamed: imageName];
|
||||
if (old == nil)
|
||||
{
|
||||
/* This could potentially be a real problem ... if the
|
||||
* image from the current theme with this name is used
|
||||
* and the theme is unloaded, what happens when the
|
||||
* app tries to draw using the proxy to the unloaded
|
||||
* image?
|
||||
* To avoid that possibility, we save the new image
|
||||
* as if it were the old one ... so when the theme is
|
||||
* unloaded the old image persists.
|
||||
*/
|
||||
[_oldImages setObject: image forKey: imageName];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Store the actual image, not the proxy.
|
||||
*/
|
||||
old = [(id)old _resource];
|
||||
[_oldImages setObject: old forKey: imageName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We try to ensure that our new image can be found by name.
|
||||
*/
|
||||
if (image != nil && [[image name] isEqualToString: imageName] == NO)
|
||||
{
|
||||
[NSImage _setImage: image name: imageName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the GSThemeDomain key in the info dictionary of the theme to
|
||||
* set a defaults domain which will establish user defaults values
|
||||
|
@ -757,10 +675,6 @@ typedef struct {
|
|||
|
||||
- (void) deactivate
|
||||
{
|
||||
NSEnumerator *enumerator;
|
||||
NSImage *image;
|
||||
NSString *name;
|
||||
|
||||
NSDebugMLLog(@"GSTheme", @"%@ %p", [self name], self);
|
||||
|
||||
/* Tell everything that we will become inactive.
|
||||
|
@ -783,30 +697,6 @@ typedef struct {
|
|||
}
|
||||
}
|
||||
|
||||
/* Unload all images created by this theme.
|
||||
*/
|
||||
enumerator = [_images objectEnumerator];
|
||||
while ((image = [enumerator nextObject]) != nil)
|
||||
{
|
||||
[image setName: nil];
|
||||
}
|
||||
[_images removeAllObjects];
|
||||
|
||||
/* Restore old images in NSImage's lookup dictionary so that the app
|
||||
* still has images to draw.
|
||||
* The remove all cached bundle images from both NSImage's name dictionary
|
||||
* and our cache dictionary, so that we can be sure we reload afresh
|
||||
* when re-activated (in case the images on disk changed ... eg by a
|
||||
* theme editor modifying the theme).
|
||||
*/
|
||||
enumerator = [_oldImages keyEnumerator];
|
||||
while ((name = [enumerator nextObject]) != nil)
|
||||
{
|
||||
image = [_oldImages objectForKey: name];
|
||||
[NSImage _setImage: image name: name];
|
||||
}
|
||||
[_oldImages removeAllObjects];
|
||||
|
||||
[self _revokeOwnerships];
|
||||
|
||||
/* Tell everything that we have become inactive.
|
||||
|
|
295
Source/NSImage.m
295
Source/NSImage.m
|
@ -37,6 +37,7 @@
|
|||
#import <Foundation/NSKeyedArchiver.h>
|
||||
#import <Foundation/NSLock.h>
|
||||
#import <Foundation/NSNotification.h>
|
||||
#import <Foundation/NSNotification.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
|
@ -159,6 +160,7 @@ repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|||
- (BOOL) _loadFromFile: (NSString *)fileName;
|
||||
- (GSRepData*) _cacheForRep: (NSImageRep*)rep;
|
||||
- (NSCachedImageRep*) _doImageCache: (NSImageRep *)rep;
|
||||
- (void) themeDidActivate: (NSNotification*)notif;
|
||||
@end
|
||||
|
||||
@implementation NSImage
|
||||
|
@ -195,10 +197,119 @@ repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|||
}
|
||||
}
|
||||
|
||||
+ (NSString *) pathForImageNamed: (NSString *)aName
|
||||
{
|
||||
[imageLock lock];
|
||||
|
||||
NSString *realName = [nsmapping objectForKey: aName];
|
||||
NSString *ext;
|
||||
NSString *path = nil;
|
||||
NSBundle *main_bundle;
|
||||
NSArray *array;
|
||||
|
||||
if (realName == nil)
|
||||
{
|
||||
realName = aName;
|
||||
}
|
||||
|
||||
// FIXME: This should use [NSBundle pathForImageResource], but this will
|
||||
// only allow imageUnfilteredFileTypes.
|
||||
/* If there is no image with that name, search in the main bundle */
|
||||
main_bundle = [NSBundle mainBundle];
|
||||
ext = [realName pathExtension];
|
||||
if (ext != nil && [ext length] == 0)
|
||||
{
|
||||
ext = nil;
|
||||
}
|
||||
|
||||
/* Check if extension is one of the image types */
|
||||
array = [self imageFileTypes];
|
||||
if (ext != nil && [array indexOfObject: ext] != NSNotFound)
|
||||
{
|
||||
/* Extension is one of the image types
|
||||
So remove from the name */
|
||||
realName = [realName stringByDeletingPathExtension];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise extension is not an image type
|
||||
So leave it alone */
|
||||
ext = nil;
|
||||
}
|
||||
|
||||
/* First search locally */
|
||||
if (ext)
|
||||
path = [main_bundle pathForResource: realName ofType: ext];
|
||||
else
|
||||
{
|
||||
id o, e;
|
||||
|
||||
e = [array objectEnumerator];
|
||||
while ((o = [e nextObject]))
|
||||
{
|
||||
path = [main_bundle pathForResource: realName
|
||||
ofType: o];
|
||||
if (path != nil && [path length] != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Second search on theme bundle */
|
||||
if (!path)
|
||||
{
|
||||
if (ext)
|
||||
path = [[[GSTheme theme] bundle] pathForResource: realName
|
||||
ofType: ext
|
||||
inDirectory: @"ThemeImages"];
|
||||
else
|
||||
{
|
||||
id o, e;
|
||||
|
||||
e = [array objectEnumerator];
|
||||
while ((o = [e nextObject]))
|
||||
{
|
||||
path = [[[GSTheme theme] bundle] pathForResource: realName
|
||||
ofType: o
|
||||
inDirectory: @"ThemeImages"];
|
||||
if (path != nil && [path length] != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If not found then search in system */
|
||||
if (!path)
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
path = [NSBundle pathForLibraryResource: realName
|
||||
ofType: ext
|
||||
inDirectory: @"Images"];
|
||||
}
|
||||
else
|
||||
{
|
||||
id o, e;
|
||||
|
||||
e = [array objectEnumerator];
|
||||
while ((o = [e nextObject]))
|
||||
{
|
||||
path = [NSBundle pathForLibraryResource: realName
|
||||
ofType: o
|
||||
inDirectory: @"Images"];
|
||||
if (path != nil && [path length] != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[imageLock unlock];
|
||||
return path;
|
||||
}
|
||||
|
||||
+ (id) imageNamed: (NSString *)aName
|
||||
{
|
||||
NSImage *image;
|
||||
|
||||
NSImage *image;
|
||||
|
||||
/* 2009-09-10 changed operation of nsmapping so that the loaded
|
||||
* image is stored under the key 'aName', not under the mapped
|
||||
* name. That way the image is created with the correct name and
|
||||
|
@ -206,105 +317,9 @@ repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|||
*/
|
||||
[imageLock lock];
|
||||
image = (NSImage*)[nameDict objectForKey: aName];
|
||||
if (image == nil || [(id)image _resource] == nil)
|
||||
if (image == nil)
|
||||
{
|
||||
NSString *realName = [nsmapping objectForKey: aName];
|
||||
NSString *ext;
|
||||
NSString *path = nil;
|
||||
NSBundle *main_bundle;
|
||||
NSArray *array;
|
||||
|
||||
if (realName == nil)
|
||||
{
|
||||
realName = aName;
|
||||
}
|
||||
|
||||
// FIXME: This should use [NSBundle pathForImageResource], but this will
|
||||
// only allow imageUnfilteredFileTypes.
|
||||
/* If there is no image with that name, search in the main bundle */
|
||||
main_bundle = [NSBundle mainBundle];
|
||||
ext = [realName pathExtension];
|
||||
if (ext != nil && [ext length] == 0)
|
||||
{
|
||||
ext = nil;
|
||||
}
|
||||
|
||||
/* Check if extension is one of the image types */
|
||||
array = [self imageFileTypes];
|
||||
if (ext != nil && [array indexOfObject: ext] != NSNotFound)
|
||||
{
|
||||
/* Extension is one of the image types
|
||||
So remove from the name */
|
||||
realName = [realName stringByDeletingPathExtension];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise extension is not an image type
|
||||
So leave it alone */
|
||||
ext = nil;
|
||||
}
|
||||
|
||||
/* First search locally */
|
||||
if (ext)
|
||||
path = [main_bundle pathForResource: realName ofType: ext];
|
||||
else
|
||||
{
|
||||
id o, e;
|
||||
|
||||
e = [array objectEnumerator];
|
||||
while ((o = [e nextObject]))
|
||||
{
|
||||
path = [main_bundle pathForResource: realName
|
||||
ofType: o];
|
||||
if (path != nil && [path length] != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Second search on theme bundle */
|
||||
if (!path)
|
||||
{
|
||||
if (ext)
|
||||
path = [[[GSTheme theme] bundle] pathForResource: realName ofType: ext];
|
||||
else
|
||||
{
|
||||
id o, e;
|
||||
|
||||
e = [array objectEnumerator];
|
||||
while ((o = [e nextObject]))
|
||||
{
|
||||
path = [[[GSTheme theme] bundle] pathForResource: realName
|
||||
ofType: o];
|
||||
if (path != nil && [path length] != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If not found then search in system */
|
||||
if (!path)
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
path = [NSBundle pathForLibraryResource: realName
|
||||
ofType: ext
|
||||
inDirectory: @"Images"];
|
||||
}
|
||||
else
|
||||
{
|
||||
id o, e;
|
||||
|
||||
e = [array objectEnumerator];
|
||||
while ((o = [e nextObject]))
|
||||
{
|
||||
path = [NSBundle pathForLibraryResource: realName
|
||||
ofType: o
|
||||
inDirectory: @"Images"];
|
||||
if (path != nil && [path length] != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
NSString *path = [self pathForImageNamed: aName];
|
||||
|
||||
if ([path length] != 0)
|
||||
{
|
||||
|
@ -362,7 +377,7 @@ repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|||
_reps = [[NSMutableArray alloc] initWithCapacity: 2];
|
||||
ASSIGN(_color, clearColor);
|
||||
_cacheMode = NSImageCacheDefault;
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -549,8 +564,6 @@ repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|||
*/
|
||||
- (BOOL) setName: (NSString *)aName
|
||||
{
|
||||
GSThemeProxy *proxy = nil;
|
||||
|
||||
[imageLock lock];
|
||||
|
||||
/* The name is already set... nothing to do.
|
||||
|
@ -564,7 +577,7 @@ repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|||
/* If the new name is already in use by another image,
|
||||
* we must do nothing.
|
||||
*/
|
||||
if (aName != nil && [[nameDict objectForKey: aName] _resource] != nil)
|
||||
if (aName != nil && [nameDict objectForKey: aName] != nil)
|
||||
{
|
||||
[imageLock unlock];
|
||||
return NO;
|
||||
|
@ -577,6 +590,10 @@ repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|||
/* We retain self in case removing from the dictionary releases us */
|
||||
IF_NO_GC([[self retain] autorelease]);
|
||||
[nameDict removeObjectForKey: _name];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: self
|
||||
name: GSThemeDidActivateNotification
|
||||
object: nil];
|
||||
DESTROY(_name);
|
||||
}
|
||||
|
||||
|
@ -589,14 +606,13 @@ repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|||
}
|
||||
|
||||
ASSIGN(_name, aName);
|
||||
|
||||
if ((proxy = [nameDict objectForKey: _name]) == nil)
|
||||
{
|
||||
proxy = [GSThemeProxy alloc];
|
||||
[nameDict setObject: proxy forKey: _name];
|
||||
[proxy release];
|
||||
}
|
||||
[proxy _setResource: self];
|
||||
|
||||
[nameDict setObject: self forKey: _name];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(themeDidActivate:)
|
||||
name: GSThemeDidActivateNotification
|
||||
object: nil];
|
||||
|
||||
[imageLock unlock];
|
||||
return YES;
|
||||
|
@ -2156,53 +2172,18 @@ iterate_reps_for_types(NSArray* imageReps, SEL method)
|
|||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSImage (GSTheme)
|
||||
|
||||
/* This method is used by the theming system to replace a named image
|
||||
* without disturbing the proxy ... so that all views and cells using
|
||||
* the named image are automatically updated to use the new image.
|
||||
* This is the counterpart to the -setName: method, which replaces the
|
||||
* proxy (to change a named image without updating the image used by
|
||||
* existing views and cells).
|
||||
*/
|
||||
+ (NSImage*) _setImage: (NSImage*)image name: (NSString*)name
|
||||
- (void) themeDidActivate: (NSNotification *)notif
|
||||
{
|
||||
GSThemeProxy *proxy = nil;
|
||||
|
||||
NSAssert([image isKindOfClass: [NSImage class]], NSInvalidArgumentException);
|
||||
NSAssert(![image isProxy], NSInvalidArgumentException);
|
||||
NSAssert([name isKindOfClass: [NSString class]], NSInvalidArgumentException);
|
||||
NSAssert([name length] > 0, NSInvalidArgumentException);
|
||||
NSAssert([image name] == nil, NSInvalidArgumentException);
|
||||
|
||||
[imageLock lock];
|
||||
ASSIGNCOPY(image->_name, name);
|
||||
if ((proxy = [nameDict objectForKey: image->_name]) == nil)
|
||||
NSString *newPath = [[self class] pathForImageNamed: _name];
|
||||
if (newPath != nil &&
|
||||
![newPath isEqual: _fileName])
|
||||
{
|
||||
proxy = [GSThemeProxy alloc];
|
||||
[nameDict setObject: proxy forKey: image->_name];
|
||||
[proxy release];
|
||||
// FIXME: Factor out into a private method for loading
|
||||
// a new path into an existing NSImage instance?
|
||||
[_reps removeAllObjects];
|
||||
_size = NSZeroSize;
|
||||
[self _useFromFile: newPath];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove the name from the old image.
|
||||
*/
|
||||
DESTROY(((NSImage*)[proxy _resource])->_name);
|
||||
}
|
||||
[proxy _setResource: image];
|
||||
IF_NO_GC([[proxy retain] autorelease]);
|
||||
|
||||
/* Force the image to be archived by name. This prevents
|
||||
* problems such as when/if gorm is being used with a theme
|
||||
* active, it will not save the image which was loaded
|
||||
* here and will, instead save the name so that the proper
|
||||
* image gets loaded in the future.
|
||||
*/
|
||||
image->_flags.archiveByName = YES;
|
||||
|
||||
[imageLock unlock];
|
||||
return (NSImage*)proxy;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in a new issue