stumpwm/external-screens.lisp @ ed5b606670fb default tip

More
author Steve Losh <steve@stevelosh.com>
date Thu, 29 Jan 2026 13:29:06 -0500
parents a65fd2691c94
children (none)
(in-package :stumpwm-user)

(defun parse-xrandr-display-line (line)
  (str:words (str:replace-all " +[(]normal.+[)].*" "" line :regex t)
             :limit 2))

(defun xrandr% ()
  (reverse
    (iterate
      (with modes = (list))
      ;; reverse to avoid final extra collect
      (for line :in (reverse (sh '("xrandr") :result-type 'list)))
      (when (str:starts-with-p "Screen " line)
        (next-iteration))
      (if (str:starts-with-p " " line)
        (push (str:trim line) modes)
        (progn (collect (list (parse-xrandr-display-line line) modes))
               (setf modes nil))))))


(defun xrandr/auto (display)
  (sh `("xrandr" "--output" ,display "--auto") :wait nil))

(defun xrandr/primary (display)
  (sh `("xrandr" "--output" ,display "--primary") :wait nil))

(defun xrandr/off (display)
  (sh `("xrandr" "--output" ,display "--off") :wait nil))

(defun xrandr/mode (display mode)
  (sh `("xrandr" "--output" ,display "--mode" ,mode) :wait nil))

(defun xrandr/dir (display dir other-display)
  (sh `("xrandr" "--output" ,display
        ,(ecase dir
           (:left "--left-of")
           (:right "--right-of")
           (:same-as "--same-as"))
        ,other-display)
      :wait nil))

(defun xrandr/menu-display (&aux (entries (xrandr%)))
  (second (select-from-menu
            (current-screen)
            (mapcar (lambda (entry)
                      (destructuring-bind ((display state) modes) entry
                        (list (format nil "~A (~D modes) ~A"
                                      display (length modes) state)
                              entry)))
                    entries)
            "xrandr display:")))

(defun xrandr/menu-action (entry)
  (destructuring-bind ((display state) modes) entry
    (declare (ignore state))
    (second (select-from-menu
              (current-screen)
              (list* '("auto" :auto)
                     '("primary" :primary)
                     '("off" :off)
                     '("left of" :left)
                     '("right of" :right)
                     '("same as" :same-as)
                     (loop :for mode in modes
                           :collect (list mode (first (str:words mode)))))
              (format nil "xrandr / ~A:" display)))))

(defcommand xrandr () ()
  (when-let ((display-entry (xrandr/menu-display)))
    (destructuring-bind ((display state) modes) display-entry
      (declare (ignore state modes))
      (when-let ((action (xrandr/menu-action display-entry)))
        (cond
          ((eql action :off) (xrandr/off display))
          ((eql action :auto) (xrandr/auto display))
          ((eql action :primary) (xrandr/primary display))
          ((member action '(:left :right :same-as))
           (when-let ((other-display-entry (xrandr/menu-display)))
             (destructuring-bind ((other-display state) modes) other-display-entry
               (declare (ignore state modes))
               (xrandr/dir display action other-display))))
          (t (xrandr/mode display action)))))))


(defcommand screen-laptop () ()
  (only)
  (hostcase
    ((:gro :juss) (loop :with laptop = "eDP"
                        :with extern = (hostcase (:gro "DisplayPort-0")
                                                 (:juss "HDMI-A-0"))
                        :for (output commands) :in `((,laptop ("--auto"))
                                                     (,laptop ("--primary"))
                                                     (,extern ("--off")))
                        :do (progn (uiop:run-program `("xrandr" "--output" ,output ,@commands)))))
    (t (message "Not configured on this system."))))

(defcommand screen-external () ()
  (only)
  (hostcase
    ((:gro :juss) (loop :with laptop = "eDP"
                        :with extern = (hostcase (:gro "DisplayPort-0")
                                                 (:juss "HDMI-A-0"))
                        :for (output commands) :in `((,extern ("--auto"))
                                                     (,extern ("--primary"))
                                                     (,laptop ("--off")))
                        :do (uiop:run-program `("xrandr" "--output" ,output ,@commands))))
    (t (message "Not configured on this system."))))

(defcommand screen-alan-single () ()
  (hostcase
    ((:juss) (loop :with laptop = "eDP"
                   :with extern = "DisplayPort-0"
                   :for (output commands) :in `((,laptop ("--mode" "1920x1080"))
                                                (,extern ("--mode" "1920x1080" "--same-as" "eDP")))
                   :do (uiop:run-program `("xrandr" "--output" ,output ,@commands))))
    (t (message "Not configured on this system."))))

(defcommand screen-alan-two () ()
  (hostcase
    ((:juss) (loop :with laptop = "eDP"
                   :with extern = "DisplayPort-0"
                   :for (output commands) :in `((,laptop ("--auto"))
                                                (,extern ("--mode" "1920x1080" "--right-of" "eDP")))
                   :do (uiop:run-program `("xrandr" "--output" ,output ,@commands))))
    (t (message "Not configured on this system."))))