forked from racket/racket
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtool.rkt
184 lines (177 loc) · 7.84 KB
/
tool.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#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))))