185 lines
7.8 KiB
Racket
185 lines
7.8 KiB
Racket
#lang racket/gui
|
|
|
|
(require racket/unit racket/class framework drracket/tool
|
|
browser/external string-constants
|
|
"patchlevel.rkt"
|
|
"check.rkt")
|
|
|
|
(define download-url "http://download.racket-lang.org/")
|
|
|
|
;; either 'yes, 'no, or something else, see `enabled?' below for a reason
|
|
(preferences:set-default 'updates:enabled? 'unset symbol?)
|
|
(preferences:set-default 'updates:last 0 integer?)
|
|
;; how often do we check; default: check every week
|
|
(preferences:set-default 'updates:frequency (* 60 60 24 7) integer?)
|
|
;; time to wait if user chooses "later"; default: in two weeks
|
|
(define later-delay (* 60 60 24 14))
|
|
|
|
;; This is used to check if updates:enabled? is true or false. The problem is
|
|
;; that we don't want to set a default of #t or #f, so make it 'unset and
|
|
;; change it only when users explicitly set it. This makes it possible to have
|
|
;; the default be #f, but without making it always #f for all users, and in the
|
|
;; future it is possible to change it to default to #t.
|
|
(define (is-enabled? v)
|
|
(case v [(yes) #t] [(no) #f] [else #f])) ; default to #f
|
|
|
|
(define (check-for-updates . top?)
|
|
(define enabled? (is-enabled? (preferences:get 'updates:enabled?)))
|
|
(define explicit? (pair? top?)) ; top => explicit check for updates
|
|
(define top (and (pair? top?) (car top?)))
|
|
;; wait until the definitions are instantiated, return top-level window
|
|
(define (wait-for-definitions)
|
|
(define ws (get-top-level-windows))
|
|
(if (null? ws)
|
|
(begin (sleep 1) (wait-for-definitions))
|
|
(car ws)))
|
|
#| ;; Cute code, but may resize the window if too much space, and people
|
|
;; didn't like this way of asking if you want update checks.
|
|
;; show a message and a disable button
|
|
(define hide-message void) ; set by show-message
|
|
(define (show-message first-time?)
|
|
;; No info display if we got some non-drscheme window by accident
|
|
(cond
|
|
[(with-handlers ([void (λ _ #f)]) (send top get-info-panel)) =>
|
|
(λ (info)
|
|
(sleep 3) ; wait to make this appearance visible
|
|
(define -check "Checking for updates...")
|
|
(define -about "About to auto-check for updates, you can")
|
|
(define p (make-object horizontal-panel% info))
|
|
(define m (make-object message% (if first-time? -about -check) p))
|
|
(define b (make-object button% "Disable" p disable))
|
|
(send info change-children (λ (l) (cons p (remq p l))))
|
|
(when first-time?
|
|
(define m1 (make-object message% "these checks" p))
|
|
(sleep 20)
|
|
(send p change-children (λ (l) (remq m1 l)))
|
|
(send m set-label -check))
|
|
(sleep 2) ; wait before and after check to make it visible
|
|
(set! hide-message
|
|
(λ ([now? #f])
|
|
(unless now? (sleep 1))
|
|
(send info change-children (λ (l) (remq p l)))
|
|
(set! hide-message void)))
|
|
#t)] ; return #t so that the check starts
|
|
[else #f])) ; no standard window -- return #f to skip the whole thing
|
|
|#
|
|
;; show results in a dialog in a non-modal dialog (if it was not an
|
|
;; explicit call) , so the window can be left around as a reminder.
|
|
(define (message style fmt . args)
|
|
(define (run)
|
|
(define-values [result new-enabled?]
|
|
(message+check-box/custom
|
|
(string-constant version:results-title)
|
|
(apply format fmt args)
|
|
(string-constant version:do-periodic-checks)
|
|
(string-constant ok)
|
|
(and (eq? 'newer style) (string-constant version:take-me-there))
|
|
#f
|
|
(and explicit? top)
|
|
`(,@(case style
|
|
[(#f) '()] [(newer) '(stop)] [else (list style)])
|
|
,@(if enabled? '(checked) '())
|
|
default=1)))
|
|
(unless (eq? enabled? new-enabled?)
|
|
(preferences:set 'updates:enabled? (if new-enabled? 'yes 'no))
|
|
(set! enabled? new-enabled?))
|
|
result)
|
|
(if explicit?
|
|
(run)
|
|
;; non-modal
|
|
(parameterize ([current-eventspace (make-eventspace)]) (run))))
|
|
;; main checker
|
|
(define (check)
|
|
(define result #f)
|
|
;; run the check in a thread, with a chance to abort it
|
|
(let ([d #f])
|
|
(define t (thread (λ () (set! result (check-version))
|
|
(when d (send d show #f)))))
|
|
(unless (sync/timeout .4 t) ; still checking, pop message
|
|
(when explicit? ; unless it's an automatic check
|
|
(queue-callback
|
|
(λ ()
|
|
(set! d (new (class dialog%
|
|
(super-new
|
|
[label (string-constant version:update-check)]
|
|
[parent #f])
|
|
(make-object message%
|
|
(string-constant version:connecting-server)
|
|
this)
|
|
(make-object button%
|
|
(string-constant abort) this
|
|
(λ (b e) (kill-thread t) (send this show #f))
|
|
'(border))
|
|
(send this center))))
|
|
(send d show #t)))
|
|
(sleep/yield .5))
|
|
(thread-wait t)))
|
|
(cond
|
|
[(and (pair? result) (eq? 'newer (car result)))
|
|
(when (equal? 2 (message 'newer "Racket v~a ~a ~a"
|
|
(cadr result)
|
|
(string-constant version:now-available-at)
|
|
download-url))
|
|
;; 2 = go there
|
|
(send-url download-url)
|
|
;; (sleep 1) ((application-quit-handler))
|
|
)]
|
|
;; implicit auto-check => show a message only if there is a newer
|
|
;; version => the rest are only for explicit calls
|
|
[(not explicit?) (void)]
|
|
[(eq? result 'ok)
|
|
(message #f (string-constant version:plt-up-to-date))]
|
|
[(not (pair? result)) (void)] ; either #f (canceled) or ok
|
|
[else (case (car result)
|
|
[(error)
|
|
(message 'stop "~a: ~a~a"
|
|
(string-constant error) (cadr result)
|
|
(if (pair? (cddr result))
|
|
(string-append "\n" (caddr result)) ""))]
|
|
[(ok-but)
|
|
(message 'caution "~a,\n~a (v~a)"
|
|
(string-constant version:plt-up-to-date)
|
|
(string-constant version:but-newer-alpha)
|
|
(cadr result))]
|
|
[else (error 'check-for-updates "internal error")])]))
|
|
;; start the check if enabled and enough time passed
|
|
(when (or explicit? enabled?)
|
|
(unless top (set! top (wait-for-definitions)))
|
|
(let ([cur (current-seconds)]
|
|
[last (preferences:get 'updates:last)]
|
|
[freq (preferences:get 'updates:frequency)])
|
|
(when (or explicit? (> (- cur last) freq))
|
|
(preferences:set 'updates:last cur)
|
|
(check)))))
|
|
|
|
(provide tool@)
|
|
(define tool@
|
|
(unit (import drscheme:tool^) (export drscheme:tool-exports^)
|
|
|
|
(define (phase1) (void))
|
|
(define (phase2)
|
|
(preferences:add-to-warnings-checkbox-panel
|
|
(λ (panel)
|
|
(define b
|
|
(make-object check-box%
|
|
(string-constant version:do-periodic-checks)
|
|
panel
|
|
(λ (b e) (preferences:set 'updates:enabled?
|
|
(if (send b get-value) 'yes 'no)))))
|
|
(preferences:add-callback
|
|
'updates:enabled?
|
|
(λ (p v) (send b set-value (is-enabled? v))))
|
|
(send b set-value
|
|
(is-enabled? (preferences:get 'updates:enabled?)))))
|
|
(drscheme:get/extend:extend-unit-frame
|
|
(λ (f%)
|
|
(class f%
|
|
(define/override (help-menu:after-about m)
|
|
(make-object menu-item%
|
|
(string-constant version:update-menu-item) m
|
|
(λ (b e) (check-for-updates this)))
|
|
(super help-menu:after-about m))
|
|
(super-new))))
|
|
(thread check-for-updates))
|
|
(when (> patchlevel 0) (version:add-spec 'p patchlevel))))
|