Files
lime/test/x11-default-layout-smoke.lisp
2026-10-02 16:35:17 -05:00

92 lines
6.3 KiB
Common Lisp

;;;; Run with sbcl --non-interactive --load test/x11-default-layout-smoke.lisp.
;;;; Owns an isolated Xvfb; never connects to the user's desktop.
(require :asdf)
(asdf:load-asd (truename (merge-pathnames "../lime.asd" *load-truename*)))
(asdf:load-system "lime/x11")
(let ((server (uiop:launch-program
'("Xvfb" "-displayfd" "1" "-screen" "0" "1000x600x24" "-nolisten" "tcp")
:output :stream :error-output :interactive))
(backend nil) (client-display nil) (checks 0))
(unwind-protect
(let* ((number (parse-integer (read-line (uiop:process-info-output server))))
(display-name (format nil ":~D" number))
(heads (list (lime.x11:make-x11-head :head-id "left" :x 0 :y 0 :width 500 :height 600)
(lime.x11:make-x11-head :head-id "right" :x 500 :y 0 :width 500 :height 600))))
(labels ((check (truth label)
(assert truth () "Failed: ~A" label)
(incf checks))
(world () (lime.x11::x11-backend-world backend))
(current (&optional (head "left")) (lime.core:current-presentation (world) head))
(mode (&optional (head "left")) (lime.core:presentation-layout-mode (current head))))
;; Clients that precede the WM must be adopted into master/stack,
;; not briefly seeded into a permanent manual draft.
(setf client-display (xlib:open-default-display display-name))
(let* ((root (xlib:screen-root (xlib:display-default-screen client-display)))
(windows (loop repeat 3 collect
(xlib:create-window :parent root :x 0 :y 0 :width 100 :height 100))))
(dolist (window windows) (xlib:map-window window))
(xlib:display-finish-output client-display)
(setf backend (lime.x11:start-lime :display-name display-name :heads heads
:head-bar-height 0 :install-default-keybindings-p nil))
(check (eq :master-stack (mode)) "default bootstrap left")
(check (eq :master-stack (mode "right")) "default bootstrap right")
(check (null (lime.core:activity-view-ids (lime.core:find-activity (world) "scratch")))
"startup does not create saved views")
(check (= 3 (length (lime.core:presentation-client-ids (current)))) "three adopted clients")
(check (= 300 (xlib:drawable-width (first windows))) "master occupies 3/5 of head")
(check (= 200 (xlib:drawable-width (second windows))) "stack occupies 2/5 of head")
(check (= 300 (xlib:drawable-height (third windows))) "stack subdivides vertically")
(lime.x11:backend-adjust-master-stack-ratio backend 1/20)
(check (= 13/20 (getf (lime.core:presentation-layout-options (current)) :master-ratio))
"initial options support resize commands")
(lime.x11:backend-use-manual-layout backend)
(lime.x11:backend-save-view backend "manual" "Manual")
(let ((before (current)))
(lime.x11:apply-lime-configuration
backend (lime.x11:make-lime-configuration :default-layout :monocle))
(check (eq before (current)) "configuration retains existing draft object")
(check (eq :manual (mode)) "configuration retains current layout")
(check (eq :master-stack (mode "right")) "configuration retains other head layout"))
(lime.x11:backend-start-activity backend "chill" "Chill")
(check (eq :monocle (mode)) "new activity follows configured default")
(lime.x11:backend-use-master-stack-layout backend)
(lime.x11:backend-activate-activity backend "scratch" :view-id "manual")
(check (eq :manual (mode)) "saved view keeps manual layout")
(lime.x11:backend-activate-activity backend "chill")
(check (eq :master-stack (mode)) "returning to draft retains layout choice")
(let ((report (lime.x11:backend-preflight-activity-activation backend "chill" :head-id "right")))
(check (eq :monocle (lime.core:activation-report-desired-layout-mode report))
"first visit on another head preflights default"))
(lime.x11:backend-activate-activity backend "chill" :head-id "right")
(check (eq :monocle (mode "right")) "first visit on another head uses default")
(check (lime.core:validate-world (world)) "world invariants after switches"))
(lime.x11:stop-backend backend)
(setf backend nil)
(xlib:close-display client-display)
(setf client-display nil)
;; The file must be evaluated once, before initial drafts exist.
;; Its layout overrides an explicitly conflicting startup keyword.
(setf backend
(lime.x11:start-lime
:display-name display-name :heads heads :head-bar-height 0
:default-layout :manual
:config-file (asdf:system-relative-pathname "lime" "test/x11-default-layout-config.lisp")))
(check (eq :monocle (mode)) "config layout applied at startup")
(check (eq :monocle (mode "right")) "config layout applied on both heads")
(check (= 1 (symbol-value '*default-layout-smoke-loads*)) "config evaluated once")
(check (= 1 (symbol-value '*default-layout-smoke-startups*)) "startup hook executed once")
(lime.x11:backend-use-manual-layout backend)
(lime.x11:reload-backend-configuration backend)
(check (eq :manual (mode)) "file reload preserves current layout")
(check (= 2 (symbol-value '*default-layout-smoke-loads*)) "reload reads the same file")
(check (= 1 (symbol-value '*default-layout-smoke-startups*)) "reload skips startup hooks")
(lime.x11:backend-start-activity backend "after-reload" "After reload")
(check (eq :monocle (mode)) "new drafts after reload follow config")
(check (lime.core:validate-world (world)) "final world invariants")
(format t "~&Live X11 default-layout smoke: ~D checks passed.~%" checks)))
(when backend (lime.x11:stop-backend backend))
(when client-display (xlib:close-display client-display))
(uiop:terminate-process server)
(uiop:wait-process server)))