
Cairo doesn't seem to deal correctly with an HDC produced by BeginPaint() that has a clipping region. The problem affects only Win64. Work around the problem by drawing to a separate HDC and copying to/from the screen. (To see the problem before this patch, draw the DrRacket window to the edge of the screen and back, and observe tha the toolbar doesn't update correctly.) This change could affect performance, but it should mostly be limited to refresh when a window moves.
222 lines
6.1 KiB
Racket
222 lines
6.1 KiB
Racket
#lang racket/base
|
|
(require racket/class
|
|
racket/draw/private/dc
|
|
racket/draw/private/bitmap-dc
|
|
racket/draw/private/bitmap
|
|
racket/draw/private/local
|
|
racket/draw/private/record-dc
|
|
racket/draw/unsafe/cairo
|
|
"../../lock.rkt"
|
|
"queue.rkt")
|
|
|
|
(provide
|
|
(protect-out backing-dc%
|
|
backing-draw-bm
|
|
|
|
;; scoped method names:
|
|
clean-slate
|
|
get-backing-size
|
|
queue-backing-flush
|
|
on-backing-flush
|
|
start-backing-retained
|
|
end-backing-retained
|
|
reset-backing-retained
|
|
make-backing-bitmap
|
|
request-delay
|
|
cancel-delay
|
|
end-delay))
|
|
|
|
(define-local-member-name
|
|
clean-slate
|
|
get-backing-size
|
|
queue-backing-flush
|
|
on-backing-flush
|
|
start-backing-retained
|
|
end-backing-retained
|
|
reset-backing-retained
|
|
make-backing-bitmap
|
|
request-delay
|
|
cancel-delay
|
|
end-delay)
|
|
|
|
(define backing-dc%
|
|
(class (record-dc-mixin (dc-mixin bitmap-dc-backend%))
|
|
(init transparent?)
|
|
|
|
(inherit internal-get-bitmap
|
|
internal-set-bitmap
|
|
reset-cr
|
|
set-recording-limit
|
|
get-recorded-command
|
|
get-clear-operator)
|
|
|
|
(super-new)
|
|
|
|
(set-recording-limit (if transparent? 1024 -1))
|
|
|
|
(define/override (ok?) #t)
|
|
|
|
;; Override this method to get the right size
|
|
(define/public (get-backing-size xb yb)
|
|
(set-box! xb 1)
|
|
(set-box! yb 1))
|
|
|
|
;; override this method to set up a callback to
|
|
;; `on-backing-flush' when the backing store can be rendered
|
|
;; to the screen; called atomically (expecting no exceptions)
|
|
(define/public (queue-backing-flush)
|
|
(void))
|
|
|
|
(define retained-cr #f)
|
|
(define retained-counter 0)
|
|
(define needs-flush? #f)
|
|
(define nada? #t)
|
|
|
|
;; called with a procedure that is applied to a bitmap;
|
|
;; returns #f if there's nothing to flush
|
|
(define/public (on-backing-flush proc)
|
|
(cond
|
|
[(not retained-cr) #f]
|
|
[(positive? retained-counter)
|
|
(unless nada?
|
|
(proc (or (get-recorded-command)
|
|
(internal-get-bitmap))))
|
|
#t]
|
|
[else
|
|
(reset-backing-retained proc)
|
|
#t]))
|
|
|
|
(define/public (can-backing-flush?)
|
|
(and retained-cr #t))
|
|
|
|
(define/public (reset-backing-retained [proc void])
|
|
(let ([cr retained-cr])
|
|
(when cr
|
|
(let ([bm (internal-get-bitmap)])
|
|
(set! retained-cr #f)
|
|
(internal-set-bitmap #f #t)
|
|
(super release-cr retained-cr)
|
|
(proc bm)
|
|
(release-backing-bitmap bm)))))
|
|
|
|
(define/public (start-backing-retained)
|
|
(as-entry
|
|
(lambda ()
|
|
(set! retained-counter (add1 retained-counter)))))
|
|
|
|
(define/public (end-backing-retained)
|
|
(as-entry
|
|
(lambda ()
|
|
(if (zero? retained-counter)
|
|
(log-error "unbalanced end-on-paint")
|
|
(set! retained-counter (sub1 retained-counter))))))
|
|
|
|
(define/public (make-backing-bitmap w h)
|
|
(make-object bitmap% w h #f #t))
|
|
|
|
(define/public (ensure-ready) (get-cr))
|
|
|
|
(define/override (get-cr)
|
|
(or retained-cr
|
|
(let ([w (box 0)]
|
|
[h (box 0)])
|
|
(get-backing-size w h)
|
|
(let ([bm (get-backing-bitmap (lambda (w h) (make-backing-bitmap w h)) (unbox w) (unbox h))])
|
|
(internal-set-bitmap bm #t))
|
|
(let ([cr (super get-cr)])
|
|
(set! retained-cr cr)
|
|
(reset-cr cr)
|
|
cr))))
|
|
|
|
(define/override (release-cr cr)
|
|
(set! nada? #f)
|
|
(when (zero? flush-suspends)
|
|
(queue-backing-flush)))
|
|
|
|
(define/override (erase)
|
|
(super erase)
|
|
(when (= (get-clear-operator)
|
|
CAIRO_OPERATOR_CLEAR)
|
|
(set! nada? #t)))
|
|
|
|
(define/public (clean-slate)
|
|
(super erase)
|
|
(set! nada? #t))
|
|
|
|
(define flush-suspends 0)
|
|
(define req #f)
|
|
|
|
(define/public (request-delay) (void))
|
|
(define/public (cancel-delay req) (void))
|
|
|
|
(define/override (suspend-flush)
|
|
(atomically
|
|
(when (zero? flush-suspends)
|
|
(when req (cancel-delay req))
|
|
(set! req (request-delay)))
|
|
(set! flush-suspends (add1 flush-suspends))))
|
|
|
|
(define/override (resume-flush)
|
|
(atomically
|
|
(unless (zero? flush-suspends)
|
|
(set! flush-suspends (sub1 flush-suspends))
|
|
(when (zero? flush-suspends)
|
|
(queue-backing-flush)))))
|
|
|
|
(define/public (end-delay)
|
|
;; call in atomic mode
|
|
(when (and (zero? flush-suspends) req)
|
|
(cancel-delay req)
|
|
(set! req #f)))))
|
|
|
|
(define (get-backing-bitmap make-bitmap w h)
|
|
(make-bitmap w h))
|
|
|
|
(define (release-backing-bitmap bm)
|
|
(send bm release-bitmap-storage))
|
|
|
|
(define cairo-dc
|
|
(make-object (dc-mixin
|
|
(class default-dc-backend%
|
|
(inherit reset-cr)
|
|
|
|
(define cr #f)
|
|
(define w 0)
|
|
(define h 0)
|
|
|
|
(super-new)
|
|
|
|
(define/public (set-cr new-cr new-w new-h)
|
|
(set! cr new-cr)
|
|
(set! w new-w)
|
|
(set! h new-h)
|
|
(when cr
|
|
(reset-cr cr)))
|
|
|
|
(define/override (get-cr) cr)
|
|
|
|
(define/override (reset-clip cr)
|
|
(super reset-clip cr)
|
|
(cairo_rectangle cr 0 0 w h)
|
|
(cairo_clip cr))))))
|
|
|
|
(define (backing-draw-bm bm cr w h [dx 0] [dy 0])
|
|
(if (procedure? bm)
|
|
(begin
|
|
(send cairo-dc reset-config)
|
|
(send cairo-dc set-cr cr w h)
|
|
(unless (and (zero? dx) (zero? dy))
|
|
(send cairo-dc translate dx dy))
|
|
(bm cairo-dc)
|
|
(send cairo-dc set-cr #f 0 0))
|
|
(let ([s (cairo_get_source cr)])
|
|
(unless (and (zero? dx) (zero? dy))
|
|
(cairo_translate cr dx dy))
|
|
(cairo_pattern_reference s)
|
|
(cairo_set_source_surface cr (send bm get-cairo-surface) 0 0)
|
|
(cairo_new_path cr)
|
|
(cairo_rectangle cr 0 0 w h)
|
|
(cairo_fill cr)
|
|
(cairo_set_source cr s)
|
|
(cairo_pattern_destroy s))))
|