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