preferences.rkt
1 #lang at-exp racket/base 2 #| 3 4 There are three attributes for each preference: 5 6 - default set, or not 7 - marshalling function set, or not 8 - initialization still okay, or not 9 10 the state transitions / contracts are: 11 12 get(true, _, _) -> (true, _, false) 13 get(false, _, _) -> error default not yet set 14 15 set is just like get. 16 17 set-default(false, _, true) -> set-default(true, _, true) 18 set-default(true, _, _) -> error default already set 19 set-default(_, _, false) -> initialization not okay anymore /* cannot happen, I think */ 20 21 set-un/marshall(true, false, true) -> (true, true, true) 22 .. otherwise error 23 24 for all syms: 25 prefs-snapshot(_, _, _) -> (_, _, false) 26 27 |# 28 29 (require scribble/srcdoc 30 racket/contract/base racket/file) 31 (require/doc racket/base 32 scribble/manual 33 scribble/example 34 (for-label racket/serialize)) 35 36 (define-struct (exn:unknown-preference exn) ()) 37 38 ;; these two names are for consistency 39 (define exn:make-unknown-preference make-exn:unknown-preference) 40 (define exn:struct:unknown-preference struct:exn:unknown-preference) 41 42 (define preferences:low-level-put-preferences (make-parameter put-preferences)) 43 (define preferences:low-level-get-preference (make-parameter get-preference)) 44 45 (define (add-pref-prefix p) (string->symbol (format "plt:framework-pref:~a" p))) 46 47 ;; preferences : hash-table[sym -o> any] 48 ;; the current values of the preferences 49 ;; marshall-unmarshall : sym -o> un/marshall 50 ;; callbacks : sym -o> (listof (sym TST -> boolean)) 51 ;; defaults : hash-table[sym -o> default] 52 (struct preferences:layer (preferences marshall-unmarshall callbacks defaults prev)) 53 54 (define (preferences:new-layer prev) 55 (preferences:layer (make-hasheq) (make-hasheq) (make-hasheq) (make-hasheq) prev)) 56 (define preferences:current-layer (make-parameter (preferences:new-layer #f))) 57 58 (define (find-layer pref) 59 (let loop ([pref-state (preferences:current-layer)]) 60 (and pref-state 61 (cond 62 [(hash-has-key? (preferences:layer-defaults pref-state) pref) 63 pref-state] 64 [(hash-has-key? (preferences:layer-callbacks pref-state) pref) 65 pref-state] 66 [else 67 (loop (preferences:layer-prev pref-state))])))) 68 69 (define (preferences:default-set? pref) 70 (define layer (find-layer pref)) 71 (and layer 72 (hash-has-key? (preferences:layer-defaults layer) pref))) 73 74 ;; type un/marshall = (make-un/marshall (any -> prinable) (printable -> any)) 75 (define-struct un/marshall (marshall unmarshall)) 76 77 ;; type pref = (make-pref any) 78 (define-struct pref (value)) 79 80 ;; type default = (make-default any (-> any bool) (listof symbol) (listof (-> any any))) 81 (define-struct default (value checker aliases rewrite-aliases)) 82 83 ;; pref-callback : (make-pref-callback (union (weak-box (sym tst -> void)) (sym tst -> void))) 84 ;; this is used as a wrapped to deal with the problem that different procedures might be eq?. 85 (define-struct pref-callback (cb) #:transparent) 86 87 ;; used to detect missing hash entries 88 (define none (gensym 'none)) 89 90 ;; get : symbol -> any 91 ;; return the current value of the preference `p' 92 ;; exported 93 (define (preferences:get p) 94 (define pref-state (find-layer p)) 95 (when (or (not pref-state) 96 (not (hash-has-key? (preferences:layer-defaults pref-state) p))) 97 (raise-unknown-preference-error 98 'preferences:get 99 "tried to get a preference but preferences:set-default has not been called for ~e" 100 p)) 101 (define preferences (preferences:layer-preferences pref-state)) 102 (define v (hash-ref preferences p none)) 103 (cond 104 ;; first time reading this, check the file & unmarshall value, if 105 ;; it's not there, use the default 106 [(eq? v none) 107 (define defaults (preferences:layer-defaults pref-state)) 108 ;; try to read the preference from the preferences file 109 (define marshalled-v (read-pref-from-file (hash-ref defaults p) p)) 110 (define default-info (hash-ref defaults p)) 111 (define the-default-value (default-value default-info)) 112 (define v (if (eq? marshalled-v none) 113 ;; no value read, take the default value 114 the-default-value 115 ;; found a saved value, unmarshall it 116 (unmarshall-pref pref-state p marshalled-v 117 (default-checker default-info) 118 the-default-value))) 119 ;; set the value in the preferences table for easier reference 120 ;; and so we know it has been read from the disk 121 ;; (and thus setting the marshaller after this is no good) 122 (hash-set! preferences p v) 123 v] 124 ;; oth. it is found, so we can just return it 125 [else v])) 126 127 ;; read-pref-from-file : symbol -> (or/c any none) 128 ;; reads the preference saved in the low-level preferences 129 ;; file, first checking 'p' and then checking the aliases (in order) 130 (define (read-pref-from-file defaults p) 131 (let loop ([syms (cons p (default-aliases defaults))] 132 [rewriters (cons values (default-rewrite-aliases defaults))]) 133 (cond 134 [(null? syms) none] 135 [else 136 (let/ec k 137 ((car rewriters) 138 ((preferences:low-level-get-preference) 139 (add-pref-prefix (car syms)) 140 (lambda () (k (loop (cdr syms) (cdr rewriters)))))))]))) 141 142 ;; set : symbol any -> void 143 ;; updates the preference 144 ;; exported 145 (define (preferences:set p value) (multi-set (list p) (list value))) 146 147 ;; set : symbol any -> void 148 ;; updates the preference 149 ;; exported 150 (define (multi-set ps values) 151 (dynamic-wind 152 (λ () 153 (call-pref-save-callbacks #t)) 154 (λ () 155 (for ([p (in-list ps)] 156 [value (in-list values)]) 157 (define pref-state (find-layer p)) 158 (cond 159 [pref-state 160 (define default (hash-ref (preferences:layer-defaults pref-state) p)) 161 (define checker? (default-checker default)) 162 (unless (checker? value) 163 (error 'preferences:set 164 (string-append 165 "new value doesn't satisfy preferences:set-default predicate\n" 166 " pref symbol: ~e\n" 167 " given: ~e\n" 168 " predicate: ~e") 169 p value checker?)) 170 (check-callbacks pref-state p value) 171 (hash-set! (preferences:layer-preferences pref-state) p value)] 172 [else 173 (raise-unknown-preference-error 174 'preferences:set 175 (string-append 176 "cannot set preference before setting default" 177 " pref symbol: ~e\n" 178 " given: ~e") 179 p 180 value)])) 181 ((preferences:low-level-put-preferences) 182 (map add-pref-prefix ps) 183 (for/list ([p (in-list ps)] 184 [value (in-list values)]) 185 (marshall-pref p value))) 186 (void)) 187 (λ () 188 (call-pref-save-callbacks #f)))) 189 190 (define pref-save-callbacks '()) 191 192 (define (preferences:get/set sym) 193 (case-lambda 194 [() (preferences:get sym)] 195 [(v) (preferences:set sym v)])) 196 197 (define (preferences:register-save-callback f) 198 (define key (gensym)) 199 (set! pref-save-callbacks (cons (list key f) pref-save-callbacks)) 200 key) 201 202 (define (preferences:unregister-save-callback k) 203 (set! pref-save-callbacks 204 (let loop ([callbacks pref-save-callbacks]) 205 (cond 206 [(null? callbacks) '()] 207 [else 208 (let ([cb (car callbacks)]) 209 (if (eq? (list-ref cb 0) k) 210 (cdr callbacks) 211 (cons cb (loop (cdr callbacks)))))])))) 212 213 (define (call-pref-save-callbacks b) 214 (for ([cb (in-list pref-save-callbacks)]) 215 ((list-ref cb 1) b))) 216 217 (define (raise-unknown-preference-error sym fmt . args) 218 (raise (exn:make-unknown-preference 219 (string-append (format "~a: " sym) (apply format fmt args)) 220 (current-continuation-marks)))) 221 222 ;; add-callback : sym (-> void) -> void 223 (define (preferences:add-callback p callback [weak? #f]) 224 (define pref-state (or (find-layer p) (preferences:current-layer))) 225 (define callbacks (preferences:layer-callbacks pref-state)) 226 (define new-cb 227 (make-pref-callback (if weak? 228 (impersonator-ephemeron callback) 229 callback))) 230 (hash-set! callbacks 231 p 232 (append 233 (hash-ref callbacks p '()) 234 (list new-cb))) 235 (λ () 236 (hash-set! 237 callbacks 238 p 239 (let loop ([callbacks (hash-ref callbacks p '())]) 240 (cond 241 [(null? callbacks) '()] 242 [else 243 (let ([callback (car callbacks)]) 244 (cond 245 [(eq? callback new-cb) 246 (loop (cdr callbacks))] 247 [else 248 (cons (car callbacks) (loop (cdr callbacks)))]))]))))) 249 250 ;; check-callbacks : pref-state sym val -> void 251 (define (check-callbacks pref-state p value) 252 (define callbacks (preferences:layer-callbacks pref-state)) 253 (define new-callbacks 254 (let loop ([callbacks (hash-ref callbacks p '())]) 255 (cond 256 [(null? callbacks) null] 257 [else 258 (define callback (car callbacks)) 259 (define cb (pref-callback-cb callback)) 260 (cond 261 [(ephemeron? cb) 262 (define v (ephemeron-value cb)) 263 (cond 264 [v 265 (v p value) 266 (cons callback (loop (cdr callbacks)))] 267 [else 268 (loop (cdr callbacks))])] 269 [else 270 (cb p value) 271 (cons callback (loop (cdr callbacks)))])]))) 272 (if (null? new-callbacks) 273 (hash-remove! callbacks p) 274 (hash-set! callbacks p new-callbacks))) 275 276 (define (preferences:set-un/marshall p marshall unmarshall) 277 (define pref-state (find-layer p)) 278 (cond 279 [pref-state 280 (define marshall-unmarshall (preferences:layer-marshall-unmarshall pref-state)) 281 (define pref-un/marshall-set? (hash-ref marshall-unmarshall p #f)) 282 (define pref-can-init? (not (hash-has-key? (preferences:layer-preferences pref-state) p))) 283 (cond 284 [(and (not pref-un/marshall-set?) pref-can-init?) 285 (hash-set! marshall-unmarshall p (make-un/marshall marshall unmarshall))] 286 [pref-un/marshall-set? 287 (error 'preferences:set-un/marshall 288 "already set un/marshall for ~e" 289 p)] 290 [(not pref-can-init?) 291 (error 'preferences:set-un/marshall "the preference ~e cannot be configured any more" p)])] 292 [else 293 (error 'preferences:set-un/marshall 294 "must call preferences:set-default for ~s before calling set-un/marshall for ~s" 295 p p)])) 296 297 ;; set-default : (sym TST (TST -> boolean) -> void 298 (define (preferences:set-default p default-value checker 299 #:aliases [aliases '()] 300 #:rewrite-aliases [rewrite-aliases (map (λ (x) values) aliases)]) 301 (define pref-state (or (find-layer p) (preferences:current-layer))) 302 (define defaults (preferences:layer-defaults pref-state)) 303 (when (hash-has-key? defaults p) 304 (error 'preferences:set-default 305 (string-append 306 "preferences default already set\n" 307 " pref symbol: ~e\n" 308 " default: ~e\n" 309 " checker: ~e") 310 p default-value checker)) 311 (unless (checker default-value) 312 (error 'preferences:set-default 313 (string-append 314 "checker doesn't match default\n" 315 " pref symbol: ~e\n" 316 " default: ~e\n" 317 " checker: ~e") 318 p default-value checker)) 319 (unless (= (length aliases) (length rewrite-aliases)) 320 (error 'preferences:set-default 321 (string-append 322 "expected equal length lists for the #:aliases" 323 " and #:rewrite-aliases arguments, got ~e and ~e") 324 aliases rewrite-aliases)) 325 (hash-set! defaults p (make-default default-value checker aliases rewrite-aliases))) 326 327 ;; marshall-pref : symbol any -> (list symbol printable) 328 (define (marshall-pref p value) 329 (define pref-state (find-layer p)) 330 (let/ec k 331 (define marshaller 332 (un/marshall-marshall 333 (hash-ref (preferences:layer-marshall-unmarshall pref-state) 334 p 335 (λ () (k value))))) 336 (marshaller value))) 337 338 ;; unmarshall-pref : pref-state symbol marshalled (any -> bool) any -> any 339 ;; unmarshalls a preference read from the disk 340 (define (unmarshall-pref pref-state p data the-checker the-default-value) 341 (define marshall-unmarshall (preferences:layer-marshall-unmarshall pref-state)) 342 (define un/marshall (hash-ref marshall-unmarshall p #f)) 343 (define result 344 (if un/marshall 345 ((un/marshall-unmarshall un/marshall) data) 346 data)) 347 (if (the-checker result) 348 result 349 the-default-value)) 350 351 ;; copy-pref-value : sym any -> any 352 ;; uses the marshalling code to copy a preference. If there 353 ;; is not marshaller set, then no copying happens. 354 (define (copy-pref-value p value) 355 (let/ec k 356 (define pref-state (find-layer p)) 357 (define marshall-unmarshall (preferences:layer-marshall-unmarshall pref-state)) 358 (define un/marshaller (hash-ref marshall-unmarshall p (λ () (k value)))) 359 (define default (hash-ref (preferences:layer-defaults pref-state) p)) 360 (define marsh (un/marshall-marshall un/marshaller)) 361 (define unmarsh (un/marshall-unmarshall un/marshaller)) 362 (define marshalled (marsh value)) 363 (define copy (unmarsh marshalled)) 364 (if ((default-checker default) copy) 365 copy 366 value))) 367 368 (define (preferences:restore-defaults) 369 (let loop ([prefs-state (preferences:current-layer)]) 370 (when prefs-state 371 (for ([(p def) (in-hash (preferences:layer-defaults prefs-state))]) 372 (preferences:set p (default-value def))) 373 (loop (preferences:layer-prev prefs-state))))) 374 375 (define-struct preferences:snapshot (x)) 376 (define (preferences:get-prefs-snapshot) 377 (make-preferences:snapshot 378 (let loop ([prefs-state (preferences:current-layer)] 379 [sofar '()]) 380 (cond 381 [prefs-state 382 (loop (preferences:layer-prev prefs-state) 383 (for/fold ([sofar sofar]) 384 ([(k def) (in-hash (preferences:layer-defaults prefs-state))]) 385 (cons (cons k (copy-pref-value k (preferences:get k))) 386 sofar)))] 387 [else sofar])))) 388 389 (define (preferences:restore-prefs-snapshot snapshot) 390 (multi-set (map car (preferences:snapshot-x snapshot)) 391 (map cdr (preferences:snapshot-x snapshot))) 392 (void)) 393 394 (begin-for-doc 395 (define pref-layer-eval (make-base-eval)) 396 (pref-layer-eval 397 '(begin 398 (require framework/preferences) 399 (let ([the-prefs-table (make-hash)]) 400 (preferences:low-level-put-preferences 401 (λ (syms vals) 402 (for ([sym (in-list syms)] 403 [val (in-list vals)]) 404 (hash-set! the-prefs-table sym val)))) 405 (preferences:low-level-get-preference 406 (λ (sym [fail void]) 407 (hash-ref the-prefs-table sym fail))))))) 408 409 (provide/doc 410 (proc-doc/names 411 preferences:get 412 (symbol? . -> . any/c) 413 (sym) 414 @{Returns the value for the preference @racket[sym]. 415 416 Raises an exception matching 417 @racket[exn:unknown-preference?] if the preference's default 418 has not been set. 419 420 Use @racket[preference:set-default] to set the default value of the preference 421 before calling this function.}) 422 423 (proc-doc/names 424 preferences:set 425 (symbol? any/c . -> . void?) 426 (sym val) 427 @{Sets the preference 428 @racket[sym] to @racket[val]. It should be called when the 429 user requests a change to a preference; 430 @racket[preferences:set] immediately writes the preference value to disk. 431 432 It raises an exception matching 433 @racket[exn:unknown-preference?] 434 if the preference's default has not been set. 435 436 Use @racket[preference:set-default] to set the default value of the preference 437 before calling this function.}) 438 439 (proc-doc/names 440 preferences:get/set 441 (-> symbol? (case-> (-> any/c) (-> any/c void?))) 442 (pref) 443 @{Returns a procedure that when applied to zero arguments retrieves the 444 current value of the preference named @racket[pref] and when 445 applied to one argument updates the preference named @racket[pref]. 446 447 @history[#:added "1.18"]{}}) 448 449 (proc-doc/names 450 preferences:add-callback 451 (->* (symbol? (-> symbol? any/c any)) 452 (boolean?) 453 (-> void?)) 454 ((p f) 455 ((weak? #f))) 456 @{This function adds a callback which is called with a symbol naming a 457 preference and its value, when the preference changes. 458 @racket[preferences:add-callback] returns a thunk, which when 459 invoked, removes the callback from this preference. 460 461 If @racket[weak?] is true, the preferences system will only hold on to 462 the callback 463 @tech[#:key "weak references" 464 #:doc '(lib "scribblings/reference/reference.scrbl")]{weakly}. 465 466 The callbacks will be called in the order in which they were added. 467 468 If you are adding a callback for a preference that requires 469 marshalling and unmarshalling, you must set the marshalling and 470 unmarshalling functions by calling 471 @racket[preferences:set-un/marshall] before adding a callback. 472 473 The result thunk removes the callback from the same @tech{preferences layer} 474 that @racket[p] was in when @racket[preferences:add-callback] was 475 originally called. 476 477 This function raises an exception matching 478 @racket[exn:unknown-preference?] 479 if the preference default has not been set via 480 @racket[preferences:set-default].}) 481 (proc-doc/names 482 preferences:set-default 483 (->* (symbol? any/c (any/c . -> . any)) 484 (#:aliases (listof symbol?) 485 #:rewrite-aliases (listof (-> any/c any))) 486 void?) 487 ((symbol value test) 488 ((aliases '()) (rewrite-aliases (map (lambda (x) values) aliases)))) 489 @{This function must be called every time your application starts up, before 490 any call to @racket[preferences:get] or @racket[preferences:set] 491 (for any given preference). 492 493 If you use @racket[preferences:set-un/marshall], 494 you must call this function before calling it. 495 496 This sets the default value of the preference @racket[symbol] to 497 @racket[value]. If the user has chosen a different setting, 498 (reflected via a call to @racket[preferences:set], possibly 499 in a different run of your program), 500 the user's setting will take precedence over the default value. 501 502 The @racket[test] argument is used as a safeguard. That function is 503 called to determine if a preference read in from a file is a valid 504 preference. If @racket[test] returns @racket[#t], then the preference is 505 treated as valid. If @racket[test] returns @racket[#f] then the default is 506 used. 507 508 The @racket[aliases] and @racket[rewrite-aliases] arguments aids 509 in renaming preferences. If @racket[aliases] is present, it is 510 expected to be a list of symbols that correspond to old versions 511 of the preferences. It defaults to @racket['()]. If @racket[rewrite-aliases] 512 is present, it is used to adjust the old values of the preferences 513 when they are present in the saved file. 514 515 @history[#:changed "1.23" @list{Allow @racket[preferences:set-default] 516 to be called even after a snapshot has been grabbed.}] 517 }) 518 519 (proc-doc/names 520 preferences:default-set? 521 (-> symbol? boolean?) 522 (pref) 523 @{Returns @racket[#t] if @racket[pref] has been passed to 524 @racket[preferences:set-default], @racket[#f] 525 otherwise}) 526 527 (proc-doc/names 528 preferences:set-un/marshall 529 (symbol? (any/c . -> . printable/c) (printable/c . -> . any/c) . -> . void?) 530 (symbol marshall unmarshall) 531 @{@racket[preferences:set-un/marshall] is used to specify marshalling and 532 unmarshalling functions for the preference 533 @racket[symbol]. @racket[marshall] will be called when the users saves their 534 preferences to turn the preference value for @racket[symbol] into a 535 printable value. @racket[unmarshall] will be called when the user's 536 preferences are read from the file to transform the printable value 537 into its internal representation. If @racket[preferences:set-un/marshall] 538 is never called for a particular preference, the values of that 539 preference are assumed to be printable. 540 541 If the unmarshalling function returns a value that does not meet the 542 guard passed to @racket[preferences:set-default] 543 for this preference, the default value is used. 544 545 The @racket[marshall] function might be called with any value returned 546 from @racket[read] and it must not raise an error 547 (although it can return arbitrary results if it gets bad input). This might 548 happen when the preferences file becomes corrupted, or is edited 549 by hand. 550 551 @racket[preferences:set-un/marshall] must be called before calling 552 @racket[preferences:get],@racket[preferences:set]. 553 554 See also @racket[serialize] and @racket[deserialize]. 555 }) 556 557 (proc-doc/names 558 preferences:restore-defaults 559 (-> void?) 560 () 561 @{@racket[(preferences:restore-defaults)] restores the users' configuration 562 to the default preferences.}) 563 564 (proc-doc/names 565 preferences:register-save-callback 566 (-> (-> boolean? any) symbol?) 567 (callback) 568 @{Registers @racket[callback] to run twice for each call 569 to @racket[preferences:set]---once before the preferences 570 file is written, with @racket[#t], and once after it is 571 written, with @racket[#f]. Registration returns a key for 572 use with @racket[preferences:unregister-save-callback]. 573 Caveats: @itemize{ 574 @item{The callback occurs on whichever 575 thread happened to call @racket[preferences:set]. 576 } 577 @item{ 578 Pre- and post-write notifications are not necessarily 579 paired; unregistration may cancel the post-write 580 notification before it occurs.}}}) 581 582 (proc-doc/names 583 preferences:unregister-save-callback 584 (-> symbol? void?) 585 (key) 586 @{Unregisters the save callback associated with @racket[key].}) 587 588 (proc-doc/names 589 exn:make-unknown-preference 590 (string? continuation-mark-set? . -> . exn:unknown-preference?) 591 (message continuation-marks) 592 @{Creates an unknown preference exception.}) 593 594 (proc-doc/names 595 exn:unknown-preference? 596 (any/c . -> . boolean?) 597 (exn) 598 @{Determines if a value is an unknown preference exn.}) 599 600 (thing-doc 601 exn:struct:unknown-preference 602 struct-type? 603 @{The struct type for the unknown preference exn.}) 604 605 606 (parameter-doc 607 preferences:low-level-put-preferences 608 (parameter/c (-> (listof symbol?) (listof any/c) any)) 609 put-preferences 610 @{This parameter's value is called to save preference the preferences file. 611 Its interface should be just like mzlib's @racket[put-preferences]. 612 613 The default value calls @racket[put-preferences] and, if there is an error, 614 then starts using a hash-table to save the preferences instead. 615 See also @racket[]}) 616 617 (parameter-doc 618 preferences:low-level-get-preference 619 (parameter/c (->* (symbol?) [(-> any)] any)) 620 get-preference 621 @{This parameter's value is called to get a preference from the preferences 622 file. Its interface should be just like @racket[get-preference]. 623 624 The default value calls @racket[get-preferences] and, if there is an error, 625 then starts using a hash-table to save the preferences instead.}) 626 627 (proc-doc/names 628 preferences:snapshot? 629 (-> any/c boolean?) 630 (arg) 631 @{Determines if its argument is a preferences snapshot. 632 633 See also @racket[preferences:get-prefs-snapshot] and 634 @racket[preferences:restore-prefs-snapshot].}) 635 (proc-doc/names 636 preferences:restore-prefs-snapshot 637 (-> preferences:snapshot? void?) 638 (snapshot) 639 @{Restores the preferences saved in @racket[snapshot], updating 640 all of the preferences values to the ones they had at the time 641 that @racket[preferences:get-prefs-snapshot] was called. 642 643 See also @racket[preferences:get-prefs-snapshot].}) 644 645 (proc-doc/names 646 preferences:get-prefs-snapshot 647 (-> preferences:snapshot?) 648 () 649 @{Caches all of the current values of the known preferences and returns them. 650 For any preference that has marshalling and unmarshalling set 651 (see @racket[preferences:set-un/marshall]), the preference value is 652 copied by passing it through the marshalling and unmarshalling process. 653 Other values are not copied, but references to them are instead saved. 654 655 See also @racket[preferences:restore-prefs-snapshot].}) 656 657 (proc-doc/names 658 preferences:new-layer 659 (-> (or/c #f preferences:layer?) preferences:layer?) 660 (previous-preferences-layer) 661 @{Creates a @tech{preferences layer} that extends @racket[previous-preferences-layer]. 662 663 @history[#:added "1.30"]}) 664 665 (proc-doc/names 666 preferences:layer? 667 (-> any/c boolean?) 668 (v) 669 @{Determines if @racket[v] is a @deftech{preferences layer}. 670 671 A preferences layer gives a form of scoping to preferences. When 672 a new preference is first registered with this library (via a call to 673 @racket[preferences:set-default] or @racket[preferences:add-callback]) 674 it is put into the layer in @racket[preferences:current-layer] 675 (and not into any of that layer's previous layers). 676 When @racket[preferences:get], @racket[preferences:set], 677 @racket[preferences:set-un/marshall] are called, they consult and 678 manipulate only the layer where the preference was first installed. 679 Accordingly, preference layers give a way to discard some set of 680 calls to @racket[preference:set-default] and other preference configuration 681 and to start over with a new set. Note that this affects only the configuration 682 of the preferences for the library; the values are all stored centrally 683 (see @racket[preferences:low-level-put-preferences]) and are unaffected 684 by the layers. 685 686 @examples[#:eval pref-layer-eval 687 688 (define original-layer (preferences:current-layer)) 689 690 (define layer2 (preferences:new-layer original-layer)) 691 (parameterize ([preferences:current-layer layer2]) 692 (code:comment "initialize 'a-pref in layer2") 693 (preferences:set-default 'a-pref 5 real?) 694 (preferences:set 'a-pref 6) 695 (preferences:get 'a-pref)) 696 697 (define layer3 (preferences:new-layer original-layer)) 698 (parameterize ([preferences:current-layer layer3]) 699 (code:comment "initialize 'a-pref again, this time in layer3") 700 (code:comment "without the new layer in place, this would be an error") 701 (preferences:set-default 'a-pref 5 real?) 702 (code:comment "the actual value of the preference remains") 703 (code:comment "from the previous call to preferences:set") 704 (preferences:get 'a-pref))] 705 706 @history[#:added "1.30"] 707 }) 708 709 (parameter-doc 710 preferences:current-layer 711 (parameter/c preferences:layer?) 712 preferences-layer 713 @{Determines the current @tech{preferences layer}. 714 @history[#:added "1.30"]}) 715 )