cocoa: event-dispatch repairs, especially when no frame is shown

Relevant to PR 11672
This commit is contained in:
Matthew Flatt 2011-01-28 11:14:33 -07:00
parent dc2bdfcea3
commit b485d375b0
4 changed files with 79 additions and 33 deletions

View File

@ -24,6 +24,8 @@
(protect menu-parent-only (protect menu-parent-only
menu-or-bar-parent)) menu-or-bar-parent))
(define root-menu-frame-used? #f)
;; Most of the work is in the item. Anything that appears in a menubar or ;; Most of the work is in the item. Anything that appears in a menubar or
;; menu has an item. Submenus are created as instances of menu%, but ;; menu has an item. Submenus are created as instances of menu%, but
;; menu% has a get-item method for manipulating the menu w.r.t. the parent ;; menu% has a get-item method for manipulating the menu w.r.t. the parent
@ -426,17 +428,13 @@
(private-field (private-field
[callback demand-callback] [callback demand-callback]
[prnt (if (eq? parent 'root) [prnt (if (eq? parent 'root)
(let ([f (make-object (class frame% (begin
(define/override (on-exit)
(exit))
(super-make-object "Root")))])
(as-entry (as-entry
(lambda () (lambda ()
(when root-menu-frame (when root-menu-frame-used?
(raise-mismatch-error (constructor-name 'menu-bar) "already has a menu bar: " parent)) (raise-mismatch-error (constructor-name 'menu-bar) "already has a menu bar: " parent))
(send (mred->wx f) designate-root-frame) (set! root-menu-frame-used? #t)))
(set-root-menu-frame! f))) root-menu-frame)
f)
parent)] parent)]
[wx #f] [wx #f]
[wx-parent #f] [wx-parent #f]

View File

@ -14,13 +14,13 @@
"wxpanel.ss" "wxpanel.ss"
"wxitem.ss" "wxitem.ss"
"mrwindow.ss" "mrwindow.ss"
"mrcontainer.ss") "mrcontainer.ss"
"app.ss")
(provide top-level-window<%> (provide top-level-window<%>
frame% frame%
dialog% dialog%
(protect root-menu-frame (protect root-menu-frame)
set-root-menu-frame!)
get-top-level-windows get-top-level-windows
get-top-level-focus-window get-top-level-focus-window
get-top-level-edit-target-window get-top-level-edit-target-window
@ -267,11 +267,6 @@
(check-container-ready cwho parent))) (check-container-ready cwho parent)))
label parent)))))) label parent))))))
(define root-menu-frame #f)
(define (set-root-menu-frame! f)
(set! root-menu-frame f)
(set-root-menu-wx-frame! (mred->wx f)))
(define (get-top-level-windows) (define (get-top-level-windows)
(remq root-menu-frame (map wx->mred (wx:get-top-level-windows)))) (remq root-menu-frame (map wx->mred (wx:get-top-level-windows))))
@ -313,4 +308,18 @@
(define (check-frame-parent/false who p) (define (check-frame-parent/false who p)
(unless (or (not p) (is-a? p frame%)) (unless (or (not p) (is-a? p frame%))
(raise-type-error (who->name who) "frame% object or #f" p)))) (raise-type-error (who->name who) "frame% object or #f" p)))
(define root-menu-frame
(and (current-eventspace-has-menu-root?)
;; The very first frame shown is somehow sticky under Cocoa,
;; so create the root frame, show it , and hide it.
(let* ([f (make-object (class frame%
(define/override (on-exit)
(exit))
(super-make-object "Root" #f 0 0 -9000 -9000
'(no-resize-border no-caption))))]
[wx (mred->wx f)])
(set-root-menu-wx-frame! wx)
(send wx designate-root-frame)
f))))

View File

@ -114,6 +114,11 @@
(let ([wx (->wx wxb)]) (let ([wx (->wx wxb)])
(when wx (when wx
(send wx notify-responder #f))))] (send wx notify-responder #f))))]
[-a _void (windowDidMiniaturize: [_id notification])
(when wxb
(let ([wx (->wx wxb)])
(when wx
(send wx force-window-focus))))]
[-a _void (toggleToolbarShown: [_id sender]) [-a _void (toggleToolbarShown: [_id sender])
(when wxb (when wxb
(let ([wx (->wx wxb)]) (let ([wx (->wx wxb)])
@ -136,13 +141,25 @@
(values f (values f
(and f (send f get-eventspace)))))) (and f (send f get-eventspace))))))
(set-eventspace-hook! (lambda (w) (set-eventspace-hook! (lambda (evt w)
(or (and w (define (is-mouse-or-key?)
(if (objc-is-a? w MyWindow) (bitwise-bit-set? MouseAndKeyEventMask
(tell #:type _scheme w getEventspace) (tell #:type _NSInteger evt type)))
#f)) (cond
(and front [w
(send front get-eventspace))))) (and (or (not root-fake-frame)
;; only mouse and key events in the root
;; frame need to be dispatched in the root
;; eventspace:
(not (ptr-equal? w (send root-fake-frame get-cocoa)))
(is-mouse-or-key?))
(objc-is-a? w MyWindow)
(tell #:type _scheme w getEventspace))]
[front (send front get-eventspace)]
[root-fake-frame
(and (is-mouse-or-key?)
(send root-fake-frame get-eventspace))]
[else #f])))
(define frame% (define frame%
(class window% (class window%
@ -287,12 +304,9 @@
(send p set-sheet #f) (send p set-sheet #f)
(tell (tell NSApplication sharedApplication) (tell (tell NSApplication sharedApplication)
endSheet: cocoa)))) endSheet: cocoa))))
(tellv cocoa deminiaturize: #f)
(tellv cocoa orderOut: #f) (tellv cocoa orderOut: #f)
(let ([next (get-app-front-window)]) (force-window-focus)))
(cond
[next (tellv next makeKeyWindow)]
[root-fake-frame (send root-fake-frame install-mb)]
[else (void)]))))
(register-frame-shown this on?) (register-frame-shown this on?)
(let ([num (tell #:type _NSInteger cocoa windowNumber)]) (let ([num (tell #:type _NSInteger cocoa windowNumber)])
(if on? (if on?
@ -320,6 +334,20 @@
(atomically (atomically
(direct-show on?))) (direct-show on?)))
(define/public (force-window-focus)
(let ([next (get-app-front-window)])
(cond
[next (tellv next makeKeyWindow)]
[root-fake-frame
;; Make key focus shift to root frame:
(let ([root-cocoa (send root-fake-frame get-cocoa)])
(tellv root-cocoa orderFront: #f)
(tellv root-cocoa makeKeyWindow)
(tellv root-cocoa orderOut: #f))
;; Install root frame's menu bar:
(send root-fake-frame install-mb)]
[else (void)])))
(define/private (do-paint-children) (define/private (do-paint-children)
(when saved-child (when saved-child
(send saved-child paint-children)) (send saved-child paint-children))
@ -350,7 +378,8 @@
(send saved-child enable-window (and on? (is-window-enabled?))))) (send saved-child enable-window (and on? (is-window-enabled?)))))
(define/override (is-shown?) (define/override (is-shown?)
(tell #:type _bool cocoa isVisible)) (or (tell #:type _bool cocoa isVisible)
(tell #:type _bool cocoa isMiniaturized)))
(define/override (is-shown-to-root?) (define/override (is-shown-to-root?)
(is-shown?)) (is-shown?))
@ -534,7 +563,12 @@
(def/public-unimplemented on-mdi-activate) (def/public-unimplemented on-mdi-activate)
(define/public (on-close) #t) (define/public (on-close) #t)
(define/public (designate-root-frame) (define/public (designate-root-frame)
(set! root-fake-frame this)) (set! root-fake-frame this)
;; The first window shown is somehow sticky, so that it becomes
;; the main window if no windows are shown:
(tellv cocoa orderFront: #f)
(tellv cocoa orderOut: #f)
(sync-cocoa-events))
(def/public-unimplemented system-menu) (def/public-unimplemented system-menu)
(define/public (set-modified on?) (define/public (set-modified on?)

View File

@ -22,7 +22,8 @@
set-fixup-window-locations! set-fixup-window-locations!
post-dummy-event post-dummy-event
try-to-sync-refresh) try-to-sync-refresh
sync-cocoa-events)
;; from common/queue: ;; from common/queue:
current-eventspace current-eventspace
@ -315,7 +316,7 @@
(when evt (check-menu-bar-click evt)) (when evt (check-menu-bar-click evt))
(and evt (and evt
(or (not dequeue?) (or (not dequeue?)
(let ([e (eventspace-hook (tell evt window))]) (let ([e (eventspace-hook evt (tell evt window))])
(if e (if e
(let ([mouse-or-key? (let ([mouse-or-key?
(bitwise-bit-set? MouseAndKeyEventMask (bitwise-bit-set? MouseAndKeyEventMask
@ -374,6 +375,10 @@
;; in atomic mode ;; in atomic mode
(dispatch-all-ready))) (dispatch-all-ready)))
(define (sync-cocoa-events)
(atomically
(dispatch-all-ready)))
;; ------------------------------------------------------------ ;; ------------------------------------------------------------
;; Install an alternate "sleep" function (in the PLT Scheme core) ;; Install an alternate "sleep" function (in the PLT Scheme core)
;; that wakes up if any Cocoa event is ready. ;; that wakes up if any Cocoa event is ready.