1/** <title>NSInterfaceStyle</title> 2 3 Copyright (C) 1999 Free Software Foundation, Inc. 4 5 Author: Richard Frith-Macdonald <richard@brainstorm.co.uk> 6 Date: 1999 7 8 This file is part of the GNUstep GUI Library. 9 10 This library is free software; you can redistribute it and/or 11 modify it under the terms of the GNU Lesser General Public 12 License as published by the Free Software Foundation; either 13 version 2 of the License, or (at your option) any later version. 14 15 This library is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 Lesser General Public License for more details. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this library; see the file COPYING.LIB. 22 If not, see <http://www.gnu.org/licenses/> or write to the 23 Free Software Foundation, 51 Franklin Street, Fifth Floor, 24 Boston, MA 02110-1301, USA. 25*/ 26 27#include "config.h" 28#import <Foundation/NSString.h> 29#import <Foundation/NSDictionary.h> 30#import <Foundation/NSException.h> 31#import <Foundation/NSNotification.h> 32#import <Foundation/NSUserDefaults.h> 33#import <Foundation/NSMapTable.h> 34 35#import "AppKit/NSResponder.h" 36#import "AppKit/NSInterfaceStyle.h" 37#import "GNUstepGUI/GSTheme.h" 38 39NSString *NSInterfaceStyleDefault = @"NSInterfaceStyleDefault"; 40 41static NSMapTable *styleMap = 0; 42static NSInterfaceStyle defStyle; 43 44static NSInterfaceStyle 45styleFromString(NSString* str) 46{ 47 if ([str isEqualToString: @"NSNextStepInterfaceStyle"]) 48 return NSNextStepInterfaceStyle; 49 if ([str isEqualToString: @"NSMacintoshInterfaceStyle"]) 50 return NSMacintoshInterfaceStyle; 51 if ([str isEqualToString: @"NSWindows95InterfaceStyle"]) 52 return NSWindows95InterfaceStyle; 53 if ([str isEqualToString: @"GSWindowMakerInterfaceStyle"]) 54 return GSWindowMakerInterfaceStyle; 55 return NSNoInterfaceStyle; 56} 57 58@interface GSInterfaceStyle : NSObject 59+ (void) defaultsDidChange: (NSNotification*)notification; 60@end 61 62 63 64/* 65typedef struct { 66 @defs(NSResponder) 67} *accessToResponder; 68*/ 69typedef NSResponder* accessToResponder; 70 71/** 72 <p> 73 Returns the interface style the responder should use, which affects 74 how a UI element (such as a button or menu) is displayed. If the 75 responder has an interface style set, the key is ignored and the 76 responder's interface style is returned. Otherwise the style 77 associated with the key is returned (if set), otherwise the default 78 style is returned. In no case will the style <code>NSNoInterfaceStyle</code> 79 be returned. 80 </p> 81 <p> 82 Styles can be set using the user defaults system. Currently available 83 styles are 84 </p> 85 <list> 86 <item>NSNextStepInterfaceStyle</item> 87 <item>NSMacintoshInterfaceStyle</item> 88 <item>NSWindows95InterfaceStyle</item> 89 <item>GSWindowMakerInterfaceStyle</item> 90 </list> 91 <p> 92 You can set a default style 93 for all UI elements using the <code>NSInterfaceStyleDefault</code> key: 94 </p> 95 <example> 96 defaults write NSGlobalDomain NSInterfaceStyleDefault GSWindowMakerInterfaceStyle 97 </example> 98*/ 99extern NSInterfaceStyle 100NSInterfaceStyleForKey(NSString *key, NSResponder *responder) 101{ 102 NSInterfaceStyle style; 103 104 /* 105 * If the specified responder has a style set, return it. 106 */ 107 if (responder) 108 { 109 style 110 = (NSInterfaceStyle)((accessToResponder)responder)->_interface_style; 111 if (style != NSNoInterfaceStyle) 112 { 113 return style; 114 } 115 } 116 117 /* 118 * If there is no style map, the defaults/cache management class must be 119 * initialised. 120 */ 121 if (styleMap == 0) 122 [GSInterfaceStyle class]; 123 124 /* 125 * If there is a style for the given defaults key, return it - after 126 * caching it in a map table if necessary. 127 */ 128 if (key) 129 { 130 /* 131 * First try the cache - then, if no style is found, use the 132 * defaults system and add the results into the cache. 133 */ 134 style = (NSInterfaceStyle)NSMapGet(styleMap, key); 135 if (style == NSNoInterfaceStyle) 136 { 137 NSUserDefaults *defs; 138 NSString *def; 139 140 defs = [NSUserDefaults standardUserDefaults]; 141 def = [defs stringForKey: key]; 142 if (def == nil 143 || (style = styleFromString(def)) == NSNoInterfaceStyle) 144 { 145 style = defStyle; 146 } 147 if (style != NSNoInterfaceStyle) 148 NSMapInsert(styleMap, (void*)key, (void*)style); 149 } 150 return style; 151 } 152 153 /* 154 * No responder and no key - return the default style. 155 */ 156 return defStyle; 157} 158 159 160 161/* 162 * The GSInterfaceStyle class is used solely to maintain our map of 163 * know interface styles by updating when user defaults change. 164 */ 165@implementation GSInterfaceStyle 166 167+ (void) initialize 168{ 169 if (self == [GSInterfaceStyle class]) 170 { 171 styleMap = NSCreateMapTable(NSObjectMapKeyCallBacks, 172 NSIntMapValueCallBacks, 8); 173 174 [NSUserDefaults standardUserDefaults]; 175 [self defaultsDidChange: nil]; 176 [[NSNotificationCenter defaultCenter] 177 addObserver: self 178 selector: @selector(defaultsDidChange:) 179 name: NSUserDefaultsDidChangeNotification 180 object: nil]; 181 [[NSNotificationCenter defaultCenter] 182 addObserver: self 183 selector: @selector(defaultsDidChange:) 184 name: GSThemeDidActivateNotification 185 object: nil]; 186 } 187} 188 189+ (void) defaultsDidChange: (NSNotification*)notification 190{ 191 NSUserDefaults *defs; 192 NSMapEnumerator enumerator; 193 NSString *key; 194 void *val; 195 196 /* 197 * We ignore the actual notification, which may be nil (when called at 198 * initialization), or may contain a user defaults object (if a persistent 199 * domain changed), or may contain a theme object (if a theme activated). 200 * What we need to do is examine the current state of the standard defaults. 201 */ 202 defs = [NSUserDefaults standardUserDefaults]; 203 204 /* 205 * Determine the default interface style for the application. 206 */ 207 key = [defs stringForKey: NSInterfaceStyleDefault]; 208 if (key == nil || (defStyle = styleFromString(key)) == NSNoInterfaceStyle) 209 defStyle = NSNextStepInterfaceStyle; 210 211 /* 212 * Now check the interface styles for all the keys in use and adjust our 213 * map table for any changes. 214 */ 215 enumerator = NSEnumerateMapTable(styleMap); 216 while (NSNextMapEnumeratorPair(&enumerator, (void**)&key, (void**)&val)) 217 { 218 NSInterfaceStyle newStyle; 219 NSString *def = [defs stringForKey: key]; 220 221 if (def == nil) 222 { 223 newStyle = defStyle; 224 } 225 else 226 { 227 newStyle = styleFromString(def); 228 if (newStyle == NSNoInterfaceStyle) 229 { 230 newStyle = defStyle; 231 } 232 } 233 234 if (newStyle != ((NSInterfaceStyle)val)) 235 { 236 NSMapInsert(styleMap, (void*)key, (void*)newStyle); 237 } 238 } 239} 240 241@end 242 243