separated default options (config) and saved options (layout)

added some synchronization
optimized focus-control
cleaned up a bit
This commit is contained in:
frese 2003-04-27 19:10:22 +00:00
parent 315a71013a
commit de00f837dc
5 changed files with 477 additions and 366 deletions

View File

@ -37,7 +37,7 @@
((eq? type (manager-type switch)) "switch-wm") ((eq? type (manager-type switch)) "switch-wm")
((eq? type (manager-type move)) "move-wm"))) ((eq? type (manager-type move)) "move-wm")))
(define (create-wm dpy parent options children (define (create-wm dpy parent options default-options children
type options-spec out-channel fun) type options-spec out-channel fun)
(let* ((wa (get-window-attributes dpy parent)) (let* ((wa (get-window-attributes dpy parent))
(main-window (main-window
@ -52,8 +52,10 @@
(wm (make-wm type in-channel out-channel internal-out-channel (wm (make-wm type in-channel out-channel internal-out-channel
dpy main-window colormap dpy main-window colormap
(create-options dpy colormap (create-options dpy colormap
(options-spec-union options-spec (spec-defaults default-options
manager-options-spec) (options-spec-union
options-spec
manager-options-spec))
options) options)
'() #f))) '() #f)))
@ -118,8 +120,18 @@
(send internal-out-channel '(fit-windows))) (send internal-out-channel '(fit-windows)))
((focus-change-event? xevent) ((focus-change-event? xevent)
;; really send it always ?? (if (window-exists? dpy (wm:window wm))
(send internal-out-channel '(update-manager-state))) (let ((mode (focus-change-event-mode xevent))
(detail (focus-change-event-detail xevent)))
(if (and (eq? mode (notify-mode normal))
(memq detail (list (notify-detail nonlinear)
(notify-detail nonlinear-virtual)
(notify-detail virtual)
(notify-detail ancestor))))
(let ((focused? (eq? (event-type focus-in)
(focus-change-event-type xevent))))
(send internal-out-channel
(list 'update-manager-state focused?)))))))
;; the manager got the focus (as a client) ;; the manager got the focus (as a client)
((client-message-event? xevent) ((client-message-event? xevent)
@ -147,90 +159,78 @@
(let ((internal-out-channel (wm:internal-out-channel wm)) (let ((internal-out-channel (wm:internal-out-channel wm))
(dpy (wm:dpy wm))) (dpy (wm:dpy wm)))
(case (car msg) (case (car msg)
((manage-window) ((wait)
(let ((window (second msg)) (let ((sp (second msg))
(maybe-rect (third msg))) (message (third msg)))
(let ((client (create-client wm window))) (handle-external-message wm exit message)
(set-wm:clients! wm (append (wm:clients wm) (list client))) (sync-point-release sp)))
(send internal-out-channel
(list 'init-client client maybe-rect))
;; sync??
;;(if (window-exists? dpy window)
;; (map-window dpy window))
;;(send internal-out-channel (list 'fit-client client))
;;(send internal-out-channel (list 'update-client-state client))
)))
((configure-window) ((manage-window)
(let ((window (second msg)) (let ((window (second msg))
(changes (third msg))) (maybe-rect (third msg)))
(send internal-out-channel (let ((client (create-client wm window)))
(list 'configure-window window changes)))) (set-wm:clients! wm (append (wm:clients wm) (list client)))
(send-message+wait internal-out-channel
(list 'init-client client maybe-rect)))))
((unmanage-window) ((configure-window)
(let* ((window (second msg)) (let ((window (second msg))
(client (find (lambda (c) (changes (third msg)))
(eq? window (client:window c))) (send-message+wait internal-out-channel
(wm:clients wm)))) (list 'configure-window window changes))))
(if client
(reparent-to-root dpy window))))
((destroy-manager) ((unmanage-window)
;; (send internal-out-channel '(deinit-manager)) (let* ((window (second msg))
;; sync ?? (client (find (lambda (c)
(if (window-exists? dpy (wm:window wm)) (eq? window (client:window c)))
(destroy-window dpy (wm:window wm)))) (wm:clients wm))))
(if client
(reparent-to-root dpy window))))
((deinit-client) ((destroy-manager)
(let ((client (second msg))) (send-message+wait internal-out-channel '(deinit-manager))
(set-wm:clients! wm (filter (lambda (c) (not (eq? c client))) (if (window-exists? dpy (wm:window wm))
(wm:clients wm))) (destroy-window dpy (wm:window wm))))
(if (eq? (wm:current-client wm) client)
(set-wm:current-client! wm (and (not (null? (wm:clients wm)))
(car (wm:clients wm)))))
(send (wm:internal-out-channel wm) (list 'deinit-client client))
;; sync ??
(destroy-window dpy (client:client-window client))))
((select-client) ((deinit-client)
(let ((client (second msg)) (let ((client (second msg)))
(time (third msg))) (set-wm:clients! wm (filter (lambda (c) (not (eq? c client)))
(for-each (lambda (client) (wm:clients wm)))
(set-wm:current-client! wm client) (if (eq? (wm:current-client wm) client)
(raise-window dpy (client:client-window client)) ;; select-client ??
(if (window-exists? dpy (client:window client)) (set-wm:current-client! wm (and (not (null? (wm:clients wm)))
(take-focus dpy (client:window client) time))) (car (wm:clients wm)))))
(cons client (transients-for-client wm client))) (send-message+wait (wm:internal-out-channel wm)
; (for-each (lambda (c) (list 'deinit-client client))
; (if (not (eq? c client)) (destroy-window dpy (client:client-window client))))
; (grab-button dpy
; (button button1) (state-set)
; (client:client-window c) #f
; (event-mask button-press)
; (grab-mode async) (grab-mode async)
; none none)))
; (wm:clients wm))
))
))) ((select-client)
(let ((client (second msg))
(time (third msg)))
(for-each (lambda (client)
(set-wm:current-client! wm client)
(raise-window dpy (client:client-window client))
(if (window-exists? dpy (client:window client))
(take-focus dpy (client:window client) time)))
(cons client (transients-for-client wm client)))))
(else (warn "unhandled manager message" wm msg)))))
(define (wm-deinit-client wm client) (define (wm-deinit-client wm client)
(mdisplay "manager deinit-client " wm " " client "\n")
(send (wm:in-channel wm) (list 'deinit-client client))) (send (wm:in-channel wm) (list 'deinit-client client)))
;; *** external messages ********************************************* ;; *** external messages *********************************************
(define (wm-manage-window wm window . rect) (define (wm-manage-window wm window . rect)
(send (wm:in-channel wm) (let ((maybe-rect (if (null? rect)
(list 'manage-window window #f
(if (null? rect) (car rect))))
#f (send-message+wait (wm:in-channel wm)
(car rect)))) (list 'manage-window window maybe-rect))))
;; sync ??
)
(define (wm-configure-window wm window changes) (define (wm-configure-window wm window changes)
(send (wm:in-channel wm) (list 'configure-window window changes))) (send-message+wait (wm:in-channel wm)
(list 'configure-window window changes)))
(define (wm-unmanage-window wm window) (define (wm-unmanage-window wm window)
(send (wm:in-channel wm) (list 'unmanage-window window))) (send (wm:in-channel wm) (list 'unmanage-window window)))
@ -240,7 +240,7 @@
(send (wm:in-channel wm) (list 'select-client client time))))) (send (wm:in-channel wm) (list 'select-client client time)))))
(define (destroy-wm wm) (define (destroy-wm wm)
(send (wm:in-channel wm) '(destroy-manager))) (send-message+wait (wm:in-channel wm) '(destroy-manager)))
(define (send-root-drop wm window x y) (define (send-root-drop wm window x y)
(send (wm:out-channel wm) (list 'root-drop window x y))) (send (wm:out-channel wm) (list 'root-drop window x y)))
@ -248,19 +248,27 @@
;; *** client ******************************************************** ;; *** client ********************************************************
(define-record-type client :client (define-record-type client :client
(make-client window client-window in-channel data) (make-client window client-window in-channel data focused?)
client? client?
(window client:window set-client:window!) (window client:window set-client:window!)
(client-window client:client-window) (client-window client:client-window)
(in-channel client:in-channel) (in-channel client:in-channel)
(data client:data set-client:data!)) (data client:data set-client:data!)
(focused? client:focused? set-client:focused?!))
(define (set-client-focused?! wm client focused?)
(let ((prev (client:focused? client)))
(if (not (eq? prev focused?))
(begin
(set-client:focused?! client focused?)
(send (wm:internal-out-channel wm)
(list 'update-client-state client focused?))))))
(define-record-discloser :client (define-record-discloser :client
(lambda (c) (lambda (c)
`(Client ,(client:window c) in ,(client:client-window c)))) `(Client ,(client:window c) in ,(client:client-window c))))
(define (create-client wm window) (define (create-client wm window)
(mdisplay "creating client for " window "\n")
(let* ((dpy (wm:dpy wm)) (let* ((dpy (wm:dpy wm))
(client-window (create-simple-window dpy (wm:window wm) (client-window (create-simple-window dpy (wm:window wm)
0 0 0 0
@ -270,10 +278,9 @@
(white-pixel dpy) (white-pixel dpy)
(black-pixel dpy))) (black-pixel dpy)))
(in-channel (make-channel)) (in-channel (make-channel))
(client (make-client window client-window in-channel #f))) (client (make-client window client-window in-channel #f #f)))
(reparent-window dpy window client-window 0 0) (reparent-window dpy window client-window 0 0)
(create-client-handler wm client) (create-client-handler wm client)
;;(map-window dpy window)
client)) client))
(define (create-client-handler wm client) (define (create-client-handler wm client)
@ -303,9 +310,11 @@
(lambda (msg) (lambda (msg)
(case (car msg) (case (car msg)
((restart-handler) ((restart-handler)
(mdisplay "restart-handler " wm " " client "\n")
(create-client-handler wm client) (create-client-handler wm client)
(exit 'restart))))) (sync-point-release (second msg))
(exit 'restart))
(else (warn "unhandled client message" wm
client msg)))))
(wrap (receive-rv client-window-channel) (wrap (receive-rv client-window-channel)
(lambda (xevent) (lambda (xevent)
(handle-client-window-xevent wm exit client xevent))) (handle-client-window-xevent wm exit client xevent)))
@ -315,13 +324,11 @@
(loop))))))))))) (loop)))))))))))
(define (client-of-window wm window) (define (client-of-window wm window)
(let ((l (filter (lambda (client) (find (lambda (client)
(equal? window (client:window client))) (equal? window (client:window client)))
(wm-clients wm)))) (wm-clients wm)))
(and (pair? l) (car l))))
(define (client-replace-window wm old-window new-window) (define (client-replace-window wm old-window new-window)
(mdisplay "client-replace-window: " wm " " old-window " " new-window "\n")
(let ((client (client-of-window wm old-window)) (let ((client (client-of-window wm old-window))
(internal-out-channel (wm:internal-out-channel wm)) (internal-out-channel (wm:internal-out-channel wm))
(dpy (wm:dpy wm))) (dpy (wm:dpy wm)))
@ -332,16 +339,14 @@
(client:client-window client))) (client:client-window client)))
(reparent-window dpy new-window (client:client-window client) (reparent-window dpy new-window (client:client-window client)
0 0)) 0 0))
(send (client:in-channel client) '(restart-handler)) (let ((sp (make-sync-point)))
;; wait ?! (send (client:in-channel client)
;; update everything... TODO (list 'restart-handler sp))
;;(send internal-out-channel (list 'init-client client #f)) (sync-point-wait sp))
(send internal-out-channel (list 'fit-client client)) (send-message+wait internal-out-channel (list 'fit-client client))
;;(send internal-out-channel (list 'fit-windows client)) (send internal-out-channel
;; sync ?? (list 'update-client-name client (client-name dpy client)))
(map-window (wm:dpy wm) new-window) (map-window (wm:dpy wm) new-window))
(send internal-out-channel (list 'update-client-state client))
)
#f))) #f)))
(define (handle-client-window-xevent wm exit client xevent) (define (handle-client-window-xevent wm exit client xevent)
@ -370,18 +375,17 @@
changes)) changes))
(send internal-out-channel (list 'fit-client-window client))) (send internal-out-channel (list 'fit-client-window client)))
(send-configuration dpy (client:window client))))) (send-configuration dpy (client:window client)))))
((circulate-event? xevent) ;; ((circulate-event? xevent)
(send internal-out-channel (list 'update-client-state client))) ;; (send internal-out-channel (list 'update-client-state client)))
((eq? (event-type enter-notify) type) ((eq? (event-type enter-notify) type)
(if (memq 'enter (get-option-value (wm:options wm) 'focus-policy)) (if (memq 'enter (get-option-value (wm:options wm) 'focus-policy))
(wm-select-client wm client (crossing-event-time xevent)))) (wm-select-client wm client (crossing-event-time xevent))))
((eq? (event-type button-press) type) ;; ((eq? (event-type button-press) type)
(if (memq 'click (get-option-value (wm:options wm) 'focus-policy)) ;; (if (memq 'click (get-option-value (wm:options wm) 'focus-policy))
(wm-select-client wm client (button-event-time xevent)))) ;; (wm-select-client wm client (button-event-time xevent))))
((destroy-window-event? xevent) ((destroy-window-event? xevent)
(mdisplay "client-window destroyed" wm client "\n")
(exit 'destroy))))) (exit 'destroy)))))
(define (handle-client-xevent wm exit client xevent) (define (handle-client-xevent wm exit client xevent)
@ -389,29 +393,23 @@
(internal-out-channel (wm:internal-out-channel wm)) (internal-out-channel (wm:internal-out-channel wm))
(dpy (wm:dpy wm))) (dpy (wm:dpy wm)))
(cond (cond
((eq? (event-type focus-out) type) ((focus-change-event? xevent)
(if (window-exists? dpy (client:window client)) (if (window-exists? dpy (client:window client))
(let ((mode (focus-change-event-mode xevent)) (let ((mode (focus-change-event-mode xevent))
(detail (focus-change-event-detail xevent))) (detail (focus-change-event-detail xevent)))
(if (and (eq? mode (notify-mode normal)) (if (and (eq? mode (notify-mode normal))
(memq detail (list (notify-detail nonlinear) (memq detail (list (notify-detail nonlinear)
(notify-detail nonlinear-virtual) (notify-detail nonlinear-virtual)
(notify-detail virtual)
(notify-detail ancestor)))) (notify-detail ancestor))))
(uninstall-colormaps dpy (client:window client))))) (if (eq? (event-type focus-in)
(send internal-out-channel (focus-change-event-type xevent))
(list 'update-client-state client))) (begin
(install-colormaps dpy (client:window client))
((eq? (event-type focus-in) type) (set-client-focused?! wm client #t))
(if (window-exists? dpy (client:window client)) (begin
(let ((mode (focus-change-event-mode xevent)) (uninstall-colormaps dpy (client:window client))
(detail (focus-change-event-detail xevent))) (set-client-focused?! wm client #f)))))))
(if (and (eq? mode (notify-mode normal))
(memq detail (list (notify-detail nonlinear)
(notify-detail nonlinear-virtual)
(notify-detail ancestor))))
(install-colormaps dpy (client:window client)))))
(send internal-out-channel
(list 'update-client-state client)))
((property-event? xevent) ((property-event? xevent)
(if (window-exists? dpy (client:window client)) (if (window-exists? dpy (client:window client))
@ -420,20 +418,18 @@
(cond (cond
((equal? "WM_NAME" name) ((equal? "WM_NAME" name)
(send internal-out-channel (send internal-out-channel
(list 'update-client-state client))) (list 'update-client-name client
;; TODO: respect NORMAL_HINTS change (client-name dpy client))))))))
))))
((reparent-event? xevent) ((reparent-event? xevent)
(if (and (window-exists? dpy (client:window client)) (if (and (window-exists? dpy (client:window client))
(not (eq? (client:client-window client) (not (eq? (client:client-window client)
(window-parent dpy (client:window client))))) (window-parent dpy (client:window client)))))
(begin (begin
;; window has been reparented away ;; window has been reparented away
(mdisplay "manager " (wm:type wm) " reparented client\n")
(wm-deinit-client wm client) (wm-deinit-client wm client)
(exit 'reparent)))) (exit 'reparent))))
((destroy-window-event? xevent) ((destroy-window-event? xevent)
(mdisplay "destroy-window-event client " wm " " client "\n")
(if (eq? (client:window client) (destroy-window-event-event xevent)) (if (eq? (client:window client) (destroy-window-event-event xevent))
(begin (begin
(wm-deinit-client wm client) (wm-deinit-client wm client)

View File

@ -21,6 +21,7 @@
xc-bottom-side xc-bottom-left-corner default-cursor)))) xc-bottom-side xc-bottom-left-corner default-cursor))))
(spawn* (spawn*
(list 'move-wm-resizer wm client)
(lambda (release) (lambda (release)
(call-with-event-channel (call-with-event-channel
dpy window dpy window
@ -34,13 +35,14 @@
(lambda () (lambda ()
(let ((xevent (receive event-channel))) (let ((xevent (receive event-channel)))
(cond (cond
((motion-event? xevent) ((and (motion-event? xevent) (window-exists? dpy window))
(set-resize-cursor wm client cursors (set-resize-cursor wm client cursors
(motion-event-x xevent) (motion-event-x xevent)
(motion-event-y xevent)) (motion-event-y xevent))
(idle)) (idle))
((eq? (event-type button-press) ((and (eq? (event-type button-press)
(any-event-type xevent)) (any-event-type xevent))
(window-exists? dpy window))
(let* ((x (button-event-x xevent)) (let* ((x (button-event-x xevent))
(y (button-event-y xevent)) (y (button-event-y xevent))
(dir (resizer-direction wm client x y))) (dir (resizer-direction wm client x y)))
@ -80,7 +82,11 @@
prev-rect dir))))))) prev-rect dir)))))))
(idle)))) (idle))))
(free-gc dpy gc) (free-gc dpy gc)
(for-each (lambda (c) (free-cursor dpy (cdr c))) cursors))))) (for-each (lambda (c) (free-cursor dpy (cdr c))) cursors)))
window))
(define (destroy-resizer dpy resizer)
(destroy-window dpy resizer))
(define (rubber-draw dpy gc rect) (define (rubber-draw dpy gc rect)
(draw-rectangle dpy (default-root-window dpy) gc (draw-rectangle dpy (default-root-window dpy) gc

View File

@ -10,73 +10,103 @@
(border-colors colors '("#333333" "#dddddd")) (border-colors colors '("#333333" "#dddddd"))
) )
(define (create-move-wm out-channel dpy parent options . children) (define (create-move-wm out-channel dpy parent options default-options
(create-wm dpy parent options children . children)
(create-wm dpy parent options default-options children
(manager-type move) move-wm-options-spec (manager-type move) move-wm-options-spec
out-channel out-channel
(lambda (wm in-channel) (lambda (wm in-channel)
(spawn* (list 'move-wm wm) (init-move-wm wm in-channel)
(lambda (release)
(release)
(move-wm-handler wm in-channel)))
wm))) wm)))
(define (move-wm-handler wm channel) (define (init-move-wm wm channel)
(let* ((dpy (wm:dpy wm)) (let* ((dpy (wm:dpy wm))
(window (wm:window wm)) (window (wm:window wm))
(gc (create-gc dpy window '()))) (gc (create-gc dpy window '())))
(let loop () (spawn* (list 'move-wm wm)
(let ((msg (receive channel))) (lambda (release)
(case (car msg) (release)
((draw-main-window) (call-with-current-continuation
(set-gc-foreground! dpy gc (black-pixel dpy)) (lambda (exit)
(fill-rectangle* dpy window gc (let loop ()
(clip-rectangle dpy window))) (let ((msg (receive channel)))
(handle-message wm gc exit msg)
(loop)))))
(free-gc dpy gc)))))
((fit-windows) (define (handle-message wm gc exit msg)
(map (lambda (client) (let ((dpy (wm:dpy wm))
(assert-client-visible wm client)) (window (wm:window wm)))
(wm-clients wm))) (case (car msg)
((wait)
(let ((sp (second msg))
(message (third msg)))
(handle-message wm gc
(lambda args
(sync-point-release sp)
(apply exit args))
message)
(sync-point-release sp)))
((init-client) ((deinit-manager)
(init-client wm (second msg) (third msg))) (exit 'deinit-manager))
((deinit-client)
(deinit-client wm (second msg)))
((configure-window) ((draw-main-window)
(let ((window (second msg)) (set-gc-foreground! dpy gc (black-pixel dpy))
(changes (third msg))) (fill-rectangle* dpy window gc
;; TODO: exact sizes ?! (clip-rectangle dpy window)))
(configure-window dpy window
(append (make-window-change-alist
(border-width 0))
changes))))
((draw-client-window) ((update-manager-state) #t)
(draw-client-window wm (second msg) gc))
((fit-client)
;; client-window changed it's size
(fit-client-windows wm (second msg)))
((fit-client-window) ((fit-windows)
;; client changed it's size ?? (map (lambda (client)
(fit-client-window wm (second msg))) (assert-client-visible wm client))
(wm-clients wm)))
((manager-focused) #t) ((init-client)
(init-client wm (second msg) (third msg)))
((update-client-state) ((deinit-client)
(let* ((client (second msg)) (deinit-client wm (second msg)))
(dpy (wm:dpy wm))
(window (client:window client)) ((configure-window)
(state (if (window-contains-focus? dpy window) (let ((window (second msg))
'focused (changes (third msg)))
'normal)) ;; TODO: exact sizes ?!
(titlebar (car (client:data client))) (configure-window dpy window
(name (client-name (wm:dpy wm) client))) (append (make-window-change-alist
(set-titlebar-title+state! titlebar name state))) (border-width 0))
)) changes))))
(loop))
(free-gc (wm:dpy wm) gc))) ((draw-client-window)
(draw-client-window wm (second msg) gc))
((fit-client)
;; client-window changed it's size
(fit-client-windows wm (second msg)))
((fit-client-window)
;; client changed it's size ??
(fit-client-window wm (second msg)))
((manager-focused) #t)
((update-client-state)
(let* ((client (second msg))
(focused? (third msg))
(state (if focused?
'focused
'normal))
(titlebar (car (client:data client))))
(set-titlebar-state! titlebar state)))
((update-client-name)
(let ((client (second msg))
(name (third msg)))
(let ((titlebar (car (client:data client))))
(set-titlebar-title! titlebar name))))
(else (warn "unhandled move-wm message" wm msg)))))
(define (init-client wm client maybe-rect) (define (init-client wm client maybe-rect)
(let ((dpy (wm:dpy wm))) (let ((dpy (wm:dpy wm)))
@ -127,7 +157,8 @@
(delete-window dpy (client:window client) (second msg))) (delete-window dpy (client:window client) (second msg)))
)))) ))))
;; TODO: internal channel ;; TODO: internal channel
(loop)))) (loop))
(destroy-resizer dpy resizer)))
(map-titlebar titlebar) (map-titlebar titlebar)
(if (window-exists? dpy (client:window client)) (if (window-exists? dpy (client:window client))
@ -138,8 +169,8 @@
(let ((options (wm:options wm))) (let ((options (wm:options wm)))
(create-titlebar channel (wm:dpy wm) (client:client-window client) (create-titlebar channel (wm:dpy wm) (client:client-window client)
(wm:colormap wm) (wm:colormap wm)
;; TODO: buttons (list (cons 'buttons '(kill maximize))
(list (cons 'normal-colors (cons 'normal-colors
(get-option options 'titlebar-colors)) (get-option options 'titlebar-colors))
(cons 'active-colors (cons 'active-colors
(get-option options'titlebar-colors-focused)) (get-option options'titlebar-colors-focused))
@ -222,8 +253,20 @@
(if maybe-rect (if maybe-rect
maybe-rect maybe-rect
(let* ((dpy (wm:dpy wm)) (let* ((dpy (wm:dpy wm))
(w.h (desired-size/hints dpy win (default-width 400)
(maximal-size/hints dpy win 400 200))) (default-height 200)
(w.h-1
(let ((w.h (minimal-size/hints dpy win default-width
default-height)))
(cons (if (< default-width (car w.h))
(car w.h)
default-width)
(if (< default-height (cdr w.h))
(cdr w.h)
default-height))))
(w.h-2 (maximal-size/hints dpy win (car w.h-1) (cdr w.h-1)))
(w.h (desired-size/hints dpy win w.h-2))
;; TODO: look for a free position ?! Transients centered?
(x.y (desired-position/hints dpy win (cons 0 0)))) (x.y (desired-position/hints dpy win (cons 0 0))))
(make-rectangle (car x.y) (cdr x.y) (make-rectangle (car x.y) (cdr x.y)
(car w.h) (cdr w.h))))) (car w.h) (cdr w.h)))))

View File

@ -17,100 +17,128 @@
;; | | | | | ;; | | | | |
;; ---------- ---------- ;; ---------- ----------
(define (create-split-wm external-in-channel dpy parent options . children) (define (create-split-wm external-in-channel dpy parent options
(create-wm dpy parent options children default-options . children)
(create-wm dpy parent options default-options children
(manager-type split) split-wm-options-spec (manager-type split) split-wm-options-spec
external-in-channel external-in-channel
(lambda (wm in-channel) (lambda (wm in-channel)
(spawn* (list 'split-wm wm) (init-split-wm wm in-channel)
(lambda (release)
(release)
(split-wm-handler wm in-channel)))
wm))) wm)))
(define (split-wm? wm) (define-record-type split-data :split-data
(and (wm? wm) (eq? (wm:type wm) (manager-type split)))) (make-split-data resizer first-client second-client)
split-data?
(resizer data:resizer)
(first-client data:first-client set-data:first-client!)
(second-client data:second-client set-data:second-client!))
(define (split-wm-handler wm channel) (define (init-split-wm wm channel)
(let ((resizer-window (create-resizer wm)) (let* ((resizer (create-resizer wm))
(dpy (wm:dpy wm)) (data (make-split-data resizer #f #f)))
(first-client #f) (spawn* (list 'split-wm wm)
(second-client #f)) (lambda (release)
(map-window (wm:dpy wm) resizer-window) (map-window (wm:dpy wm) resizer)
(let loop () (release)
(let ((msg (receive channel))) (call-with-current-continuation
(case (car msg) (lambda (exit)
((draw-main-window) #t) (let loop ()
(let ((msg (receive channel)))
(handle-message wm channel data exit msg)
(loop)))))))))
((fit-windows) (define (handle-message wm channel data exit msg)
(fit-windows wm resizer-window first-client second-client)) (let ((dpy (wm:dpy wm)))
(case (car msg)
((wait)
(let ((sp (second msg))
(message (third msg)))
(handle-message wm channel data
(lambda args
(sync-point-release sp)
(apply exit args))
message)
(sync-point-release sp)))
((init-client) ((deinit-manager)
(let ((client (second msg)) (destroy-window dpy (data:resizer data))
(first? (not first-client))) (exit 'deinit-manager))
(if first?
(set! first-client client)
(set! second-client client))
(set-window-border-width! dpy (client:window client) 0) ((draw-main-window) #t)
(fit-windows wm resizer-window first-client second-client)
(map-window dpy (client:window client)) ((update-manager-state) #t)
(map-window dpy (client:client-window client))
(let ((opt (if (eq? (get-option-value (wm:options wm) ((fit-windows)
'orientation) (fit-windows wm data))
'horizontal)
(if first? 'select-right 'select-left)
(if first? 'select-down 'select-up))))
(grab-shortcut dpy (client:client-window client)
(get-option-value (wm:options wm) opt)
(if first? 'select-second 'select-first)
channel #f))
))
((deinit-client) ((init-client)
(let ((client (second msg))) (let ((client (second msg))
(if (eq? client first-client) (first? (not (data:first-client data))))
(set! first-client #f)) (if first?
(if (eq? client second-client) (set-data:first-client! data client)
(set! second-client #f)) (set-data:second-client! data client))
;; destroy split if only one client left
(if (and (not (and first-client second-client))
(or first-client second-client))
(let ((repl (client:window (or first-client second-client))))
(mdisplay "destroying " wm ". with replacement " repl "\n")
(send (wm:out-channel wm)
(list 'destroy-wm wm repl))))))
((draw-client-window) #t) (set-window-border-width! dpy (client:window client) 0)
(fit-windows wm data)
((fit-client) (map-window dpy (client:window client))
;; client-window changed it's size (map-window dpy (client:client-window client))
(fit-client-windows wm (second msg)))
((fit-client-window) (let ((opt (if (eq? (get-option-value (wm:options wm)
;; client changed it's size ?? 'orientation)
#t) 'horizontal)
(if first? 'select-right 'select-left)
(if first? 'select-down 'select-up))))
(grab-shortcut dpy (client:client-window client)
(get-option-value (wm:options wm) opt)
(if first? 'select-second 'select-first)
channel #f))
))
((manager-focused) ((deinit-client)
(let ((time (second msg)) (let ((client (second msg)))
(cc (wm-current-client wm))) (if (eq? client (data:first-client data))
(if cc (wm-select-client wm cc time)))) (set-data:first-client! data #f))
(if (eq? client (data:second-client data))
(set-data:second-client! data #f))
;; destroy split if only one client left. replace the
;; wm by the remaining client.
(let ((first-client (data:first-client data))
(second-client (data:second-client data)))
(if (and (not (and first-client second-client))
(or first-client second-client))
(let ((r (client:window (or first-client second-client))))
(send (wm:out-channel wm) (list 'destroy-wm wm r)))))))
((update-client-state) #t) ((draw-client-window) #t)
;; Shortcuts ((fit-client)
((select-first) ;; client-window changed it's size
(let ((time (second msg))) (fit-client-windows wm (second msg)))
(if first-client
(wm-select-client wm first-client time)))) ((fit-client-window)
((select-second) ;; client changed it's size ??
(let ((time (second msg))) #t)
(if second-client
(wm-select-client wm second-client time)))) ((manager-focused)
)) (let ((time (second msg))
(loop)))) (cc (wm-current-client wm)))
(if cc (wm-select-client wm cc time))))
((update-client-state) #t)
((update-client-name) #t)
;; Shortcuts
((select-first)
(let ((time (second msg)))
(if (data:first-client data)
(wm-select-client wm (data:first-client data) time))))
((select-second)
(let ((time (second msg)))
(if (data:second-client data)
(wm-select-client wm (data:second-client data) time))))
(else (warn "unhandled split-wm message" wm msg)))))
(define (calc-rectangles wm) (define (calc-rectangles wm)
(let* ((options (wm:options wm)) (let* ((options (wm:options wm))
@ -141,18 +169,21 @@
(+ (rectangle:height r1) bar-width))))) (+ (rectangle:height r1) bar-width)))))
(list r1 r2 r3))))) (list r1 r2 r3)))))
(define (fit-windows wm resizer-window first-client second-client) (define (fit-windows wm data)
(let* ((rects (calc-rectangles wm)) (let ((resizer-window (data:resizer data))
(dpy (wm:dpy wm))) (first-client (data:first-client data))
(move-resize-window* dpy resizer-window (second rects)) (second-client (data:second-client data)))
(if first-client (let* ((rects (calc-rectangles wm))
(move-resize-window* dpy (dpy (wm:dpy wm)))
(client:client-window first-client) (move-resize-window* dpy resizer-window (second rects))
(first rects))) (if first-client
(if second-client (move-resize-window* dpy
(move-resize-window* dpy (client:client-window first-client)
(client:client-window second-client) (first rects)))
(third rects))))) (if second-client
(move-resize-window* dpy
(client:client-window second-client)
(third rects))))))
(define (fit-client-windows wm client) (define (fit-client-windows wm client)
(let ((dpy (wm:dpy wm))) (let ((dpy (wm:dpy wm)))

View File

@ -9,15 +9,13 @@
(select-previous keys "M-k p") (select-previous keys "M-k p")
) )
(define (create-switch-wm out-channel dpy parent options . children) (define (create-switch-wm out-channel dpy parent options default-options
(create-wm dpy parent options children . children)
(create-wm dpy parent options default-options children
(manager-type switch) switch-wm-options-spec (manager-type switch) switch-wm-options-spec
out-channel out-channel
(lambda (wm in-channel) (lambda (wm in-channel)
(spawn* (list 'switch-wm wm) (init-switch-wm wm in-channel)
(lambda (release)
(release)
(switch-wm-handler wm in-channel)))
wm))) wm)))
(define-record-type switch-wm-data :switch-wm-data (define-record-type switch-wm-data :switch-wm-data
@ -26,7 +24,7 @@
(titlebars data:titlebars set-data:titlebars!) (titlebars data:titlebars set-data:titlebars!)
(empty-titlebar data:empty-titlebar)) (empty-titlebar data:empty-titlebar))
(define (switch-wm-handler wm channel) (define (init-switch-wm wm channel)
(let* ((dpy (wm:dpy wm)) (let* ((dpy (wm:dpy wm))
(window (wm:window wm)) (window (wm:window wm))
(options (wm:options wm)) (options (wm:options wm))
@ -42,74 +40,111 @@
(get-option-value options 'select-previous) (get-option-value options 'select-previous)
'select-previous channel #f) 'select-previous channel #f)
(let loop () (spawn* (list 'switch-wm wm)
(let ((msg (receive channel))) (lambda (release)
(case (car msg) (release)
((draw-main-window) (call-with-current-continuation
(set-gc-foreground! dpy gc (black-pixel dpy)) (lambda (exit)
(fill-rectangle* dpy window gc (let loop ()
(clip-rectangle dpy window))) (let ((msg (receive channel)))
(handle-message wm data gc exit msg)
(loop)))))
(free-gc dpy gc)))))
((fit-windows) (define (handle-message wm data gc exit msg)
(fit-titlebars wm data) (let ((dpy (wm:dpy wm))
(for-each (lambda (c) (window (wm:window wm)))
(fit-client-window wm c)) (case (car msg)
(wm-clients wm))) ((wait)
(let ((sp (second msg))
(message (third msg)))
(handle-message wm data gc
(lambda args
(sync-point-release sp)
(apply exit args))
message)
(sync-point-release sp)))
((init-client) ((deinit-manager)
(init-client wm data (second msg) (third msg))) (destroy-titlebar (data:empty-titlebar data))
((deinit-client) (for-each (lambda (client.tb)
(deinit-client wm data (second msg))) (destroy-titlebar (cdr client.tb)))
(data:titlebars data))
(exit 'deinit-manager))
((configure-window) ((draw-main-window)
(let ((window (second msg)) (set-gc-foreground! dpy gc (black-pixel dpy))
(changes (third msg))) (fill-rectangle* dpy window gc
;; TODO: exact sizes ?! (clip-rectangle dpy window)))
(configure-window dpy window
(append (make-window-change-alist
(border-width 0))
changes))))
((draw-client-window) #f) ((fit-windows)
(fit-titlebars wm data)
(for-each (lambda (c)
(fit-client-window wm c))
(wm-clients wm)))
((fit-client) ((init-client)
;; client-window changed it's size (init-client wm data (second msg) (third msg)))
(fit-client wm (second msg)))
((fit-client-window) ((deinit-client)
;; client changed it's size ?? (deinit-client wm data (second msg)))
(fit-client-window wm (second msg)))
((update-manager-state) ((configure-window)
(let ((state (if (window-contains-focus? dpy (wm:window wm)) (let ((window (second msg))
'focused (changes (third msg)))
'active))) ;; TODO: exact sizes ?!
(set-titlebar-state! empty-titlebar state))) (configure-window dpy window
(append (make-window-change-alist
(border-width 0))
changes))))
((manager-focused) ((draw-client-window) #f)
(let ((time (second msg))
(cc (wm-current-client wm)))
(if cc (wm-select-client wm cc time))))
((update-client-state) ((fit-client)
(let* ((client (second msg)) ;; client-window changed it's size
(dpy (wm:dpy wm)) (fit-client wm (second msg)))
(window (client:window client)))
(if (window-exists? dpy window)
(let ((state (if (window-contains-focus? dpy window)
'focused
(if (window-viewable? dpy window)
'active
'normal)))
(titlebar (assq/false client (data:titlebars data)))
(name (client-name dpy client)))
(set-titlebar-title+state! titlebar name state)))))
((select-next) (select-next-client wm (second msg))) ((fit-client-window)
((select-previous) (select-previous-client wm (second msg))) ;; client changed it's size ??
)) (fit-client-window wm (second msg)))
(loop))
(free-gc (wm:dpy wm) gc))) ((update-manager-state)
(let* ((focused? (second msg))
(state (if focused?
'focused
'active)))
(set-titlebar-state! (data:empty-titlebar data) state)))
((manager-focused)
(let ((time (second msg))
(cc (wm-current-client wm)))
(if cc (wm-select-client wm cc time))))
((update-client-state)
(let* ((client (second msg))
(focused? (third msg))
(dpy (wm:dpy wm))
(window (client:window client))
(titlebar (assq/false client (data:titlebars data))))
(if (and titlebar (window-exists? dpy window))
(let ((state (if focused?
'focused
(if (window-viewable? dpy window)
'active
'normal))))
(set-titlebar-state! titlebar state)))))
((update-client-name)
(let ((client (second msg))
(name (third msg)))
(let ((titlebar (assq/false client (data:titlebars data))))
(if titlebar
(set-titlebar-title! titlebar name)))))
((select-next) (select-next-client wm (second msg)))
((select-previous) (select-previous-client wm (second msg)))
(else (warn "unhandled switch-wm message" wm msg)))))
(define (fit-titlebars wm data) (define (fit-titlebars wm data)
(let* ((dpy (wm:dpy wm)) (let* ((dpy (wm:dpy wm))
@ -144,15 +179,16 @@
(data:titlebars data)))))) (data:titlebars data))))))
(define (init-client wm data client maybe-rect) (define (init-client wm data client maybe-rect)
;; TODO: transients!
(let ((dpy (wm:dpy wm)) (let ((dpy (wm:dpy wm))
(options (wm:options wm))) (options (wm:options wm)))
(let* ((channel (make-channel)) (let* ((channel (make-channel))
(titlebar (create-client-titlebar channel wm client))) (titlebar (create-client-titlebar channel wm client)))
(set-data:titlebars! data (append (data:titlebars data) (set-data:titlebars! data (append (data:titlebars data)
(list (cons client titlebar)))) (list (cons client titlebar))))
(set-titlebar-title! titlebar (client-name dpy client))
(fit-titlebars wm data) (fit-titlebars wm data)
(update-titlebars wm data) (update-titlebars wm data)
(fit-client-window wm client) (fit-client-window wm client)
(fit-client wm client) (fit-client wm client)
@ -180,8 +216,7 @@
;; from titlebar-buttons ;; from titlebar-buttons
((kill) ((kill)
(delete-window dpy (client:window client) (second msg))) (delete-window dpy (client:window client) (second msg)))
(else (mdisplay "unhandled client message: " msg "\n")))) (else (warn "unhandled client message " wm client msg))))
;; TODO: internal channel
(loop)))) (loop))))
(map-titlebar titlebar) (map-titlebar titlebar)
@ -193,8 +228,8 @@
(let ((options (wm:options wm))) (let ((options (wm:options wm)))
(create-titlebar channel (wm:dpy wm) (wm:window wm) (create-titlebar channel (wm:dpy wm) (wm:window wm)
(wm:colormap wm) (wm:colormap wm)
;; TODO: buttons (list (cons 'buttons '(kill))
(list (cons 'normal-colors (cons 'normal-colors
(get-option options 'titlebar-colors)) (get-option options 'titlebar-colors))
(cons 'active-colors (cons 'active-colors
(get-option options 'titlebar-colors-active)) (get-option options 'titlebar-colors-active))
@ -207,7 +242,7 @@
(let* ((options (wm:options wm)) (let* ((options (wm:options wm))
(tb (tb
(create-titlebar #f (wm:dpy wm) (wm:window wm) (wm:colormap wm) (create-titlebar #f (wm:dpy wm) (wm:window wm) (wm:colormap wm)
(list ;; TODO: (cons 'draggable #f) (list
(cons 'normal-colors (cons 'normal-colors
(get-option options 'titlebar-colors)) (get-option options 'titlebar-colors))
(cons 'active-colors (cons 'active-colors