;;;; 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)))