orion-wm/src/move-wm.scm

274 lines
8.6 KiB
Scheme

(define-options-spec move-wm-options-spec
(titlebar-colors colors '("#aaaaaa" "#eeeeee" "#777777" "black"))
(titlebar-colors-focused colors '("#666699" "#aaaacc" "#333366" "#eeeeee"))
(titlebar-height int 18)
(titlebar-style symbol 'flat)
(font font "-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*")
(border-width int 3)
(corner-width int 10)
(border-style symbol 'raised) ;; raised | sunken | flat
(border-colors colors '("#333333" "#dddddd"))
)
(define (create-move-wm out-channel dpy parent options default-options
. children)
(create-wm dpy parent options default-options children
(manager-type move) move-wm-options-spec
out-channel
(lambda (wm in-channel)
(init-move-wm wm in-channel)
wm)))
(define (init-move-wm wm channel)
(let* ((dpy (wm:dpy wm))
(window (wm:window wm))
(gc (create-gc dpy window '())))
(spawn* (list 'move-wm wm)
(lambda (release)
(release)
(call-with-current-continuation
(lambda (exit)
(let loop ()
(let ((msg (receive channel)))
(handle-message wm gc exit msg)
(loop)))))
(free-gc dpy gc)))))
(define (handle-message wm gc exit msg)
(let ((dpy (wm:dpy wm))
(window (wm:window 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)))
((deinit-manager)
(exit 'deinit-manager))
((draw-main-window)
(set-gc-foreground! dpy gc (black-pixel dpy))
(fill-rectangle* dpy window gc
(clip-rectangle dpy window)))
((update-manager-state) #t)
((fit-windows)
(map (lambda (client)
(assert-client-visible wm client))
(wm-clients wm)))
((init-client)
(init-client wm (second msg) (third msg)))
((deinit-client)
(deinit-client wm (second msg)))
((configure-window)
(let ((window (second msg))
(changes (third msg)))
;; TODO: exact sizes ?!
(configure-window dpy window
(append (make-window-change-alist
(border-width 0))
changes))))
((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)
(let ((dpy (wm:dpy wm)))
(let* ((r (initial-client-rect wm (client:window client) maybe-rect))
(channel (make-channel))
(titlebar (create-client-titlebar channel wm client))
(resizer (create-resizer wm client))
(options (wm:options wm)))
(set-client:data! client (list titlebar resizer))
(set-titlebar-title! titlebar (client-name dpy client))
(let ((bw (get-option-value options 'border-width))
(th (get-option-value options 'titlebar-height)))
(move-resize-window dpy (client:client-window client)
(rectangle:x r) (rectangle:y r)
(+ (rectangle:width r) (* 2 bw))
(+ (rectangle:height r) (* 2 bw) th)))
(fit-client-windows wm client)
(install-dragging-control channel dpy
(titlebar:window titlebar)
(client:client-window client))
(spawn*
(list 'move-wm-client-handler wm client)
(lambda (release)
(release)
(let loop ()
(select*
(wrap (receive-rv channel)
(lambda (msg)
(case (car msg)
((drop)
;; check if outside...
(let ((window-x (second msg))
(window-y (third msg))
(root-x (fourth msg))
(root-y (fifth msg)))
(let ((r (root-rectangle dpy (wm:window wm))))
(if (point-in-rectangle? r root-x root-y)
(move-window dpy (client:client-window client)
window-x window-y)
(send (wm:out-channel wm)
(list 'root-drop (client:window client)
root-x root-y))))))
((click)
(wm-select-client wm client (fourth msg)))
;; from titlebar-buttons
((kill)
(delete-window dpy (client:window client) (second msg)))
))))
;; TODO: internal channel
(loop))
(destroy-resizer dpy resizer)))
(map-titlebar titlebar)
(if (window-exists? dpy (client:window client))
(map-window dpy (client:window client)))
(map-window dpy (client:client-window client)))))
(define (create-client-titlebar channel wm client)
(let ((options (wm:options wm)))
(create-titlebar channel (wm:dpy wm) (client:client-window client)
(wm:colormap wm)
(list (cons 'buttons '(kill maximize))
(cons 'normal-colors
(get-option options 'titlebar-colors))
(cons 'active-colors
(get-option options'titlebar-colors-focused))
(cons 'focused-colors
(get-option options 'titlebar-colors-focused))
(cons 'border-style
(get-option options 'titlebar-style))))))
(define (deinit-client wm client)
(let ((dpy (wm:dpy wm)))
#t))
;; ***
(define (fit-client-windows wm client)
(let* ((dpy (wm:dpy wm))
(options (wm:options wm))
(border-width (get-option-value options 'border-width))
(titlebar-height (get-option-value options 'titlebar-height))
(wa (get-window-attributes dpy (client:client-window client))))
;; TODO: is called much too often
(if (window-exists? dpy (client:window client))
(move-resize-window dpy (client:window client)
border-width
(+ border-width titlebar-height)
(- (window-attribute:width wa)
(* 2 border-width))
(- (window-attribute:height wa)
(+ (* 2 border-width) titlebar-height))))
(move-resize-titlebar
(car (client:data client))
(make-rectangle border-width border-width
(- (window-attribute:width wa) (* 2 border-width))
titlebar-height))))
(define (fit-client-window wm client)
(let* ((dpy (wm:dpy wm))
(options (wm:options wm))
(border-width (get-option-value options 'border-width))
(titlebar-height (get-option-value options 'titlebar-height)))
(if (window-exists? dpy (client:window client))
(let ((wa (get-window-attributes dpy (client:window client))))
(resize-window dpy (client:client-window client)
(+ (window-attribute:width wa) (* 2 border-width))
(+ (window-attribute:height wa)
(* 2 border-width)
titlebar-height))))))
(define (assert-client-visible wm client)
(let* ((dpy (wm:dpy wm))
(win (client:client-window client))
(x (window-x dpy win))
(y (window-y dpy win)))
#t)) ;; ... TODO
(define (draw-client-window wm client gc)
(let* ((options (wm:options wm))
(colors (get-option-value options 'border-colors))
(window (client:client-window client))
(dpy (wm:dpy wm))
(border-style (get-option-value options 'border-style))
(border-width (get-option-value options 'border-width))
(clip-rect (clip-rectangle dpy window)))
(if (not (eq? border-style 'flat))
(let ((light (if (eq? border-style 'sunken)
(car colors) (cadr colors)))
(dark (if (eq? border-style 'sunken)
(cadr colors) (car colors))))
(for-each (lambda (i)
(let ((r (make-rectangle
(+ i (rectangle:x clip-rect))
(+ i (rectangle:y clip-rect))
(- (rectangle:width clip-rect) (* i 2))
(- (rectangle:height clip-rect) (* i 2)))))
(draw-shadow-rectangle dpy window gc
r light dark)))
(iota border-width))))))
(define (initial-client-rect wm win maybe-rect)
(if maybe-rect
maybe-rect
(let* ((dpy (wm:dpy wm))
(default-width 400)
(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))))
(make-rectangle (car x.y) (cdr x.y)
(car w.h) (cdr w.h)))))