Add compatibility mode for legacy servers

* exwm-randr.el (exwm-randr--compatibility-mode): Indicating whether
RandR 1.5 is supported by the server.
(exwm-randr--init): Set it.
(exwm-randr--get-monitor-alias): Split out from
exwm-randr--get-monitors for reuse.
(exwm-randr--get-outputs): New function for retrieving RandR 1.2
outputs when RandR 1.5 is not supported.
(exwm-randr-refresh): Call `exwm-randr--get-outputs' in compatibility
mode.
This commit is contained in:
Chris Feng 2019-04-14 00:00:00 +00:00
parent 4ac0d6c1fd
commit f70bdb5868

View file

@ -98,11 +98,13 @@ corresponding monitors whenever the monitors are active.
(defvar exwm-randr--prev-screen-change-seqnum nil (defvar exwm-randr--prev-screen-change-seqnum nil
"The most recent ScreenChangeNotify sequence number.") "The most recent ScreenChangeNotify sequence number.")
(defvar exwm-randr--compatibility-mode nil
"Non-nil when the server does not support RandR 1.5 protocol.")
(defun exwm-randr--get-monitors () (defun exwm-randr--get-monitors ()
"Get RandR monitors." "Get RandR 1.5 monitors."
(exwm--log) (exwm--log)
(let (monitor-name geometry monitor-geometry-alist primary-monitor (let (monitor-name geometry monitor-geometry-alist primary-monitor)
monitor-position-alist monitor-alias-alist)
(with-slots (timestamp monitors) (with-slots (timestamp monitors)
(xcb:+request-unchecked+reply exwm--connection (xcb:+request-unchecked+reply exwm--connection
(make-instance 'xcb:randr:GetMonitors (make-instance 'xcb:randr:GetMonitors
@ -126,8 +128,58 @@ corresponding monitors whenever the monitors are active.
(not primary-monitor)) (not primary-monitor))
(setq primary-monitor monitor-name))))) (setq primary-monitor monitor-name)))))
(exwm--log "Primary monitor: %s" primary-monitor) (exwm--log "Primary monitor: %s" primary-monitor)
;; In a mirroring setup some monitors overlap and should be treated (list primary-monitor monitor-geometry-alist
;; as one. (exwm-randr--get-monitor-alias primary-monitor
monitor-geometry-alist))))
(defun exwm-randr--get-outputs ()
"Get RandR 1.2 outputs.
Only used when RandR 1.5 is not supported by the server."
(exwm--log)
(let (output-name geometry output-geometry-alist primary-output)
(with-slots (config-timestamp outputs)
(xcb:+request-unchecked+reply exwm--connection
(make-instance 'xcb:randr:GetScreenResourcesCurrent
:window exwm--root))
(when (> config-timestamp exwm-randr--last-timestamp)
(setq exwm-randr--last-timestamp config-timestamp))
(dolist (output outputs)
(with-slots (crtc connection name)
(xcb:+request-unchecked+reply exwm--connection
(make-instance 'xcb:randr:GetOutputInfo
:output output
:config-timestamp config-timestamp))
(when (and (= connection xcb:randr:Connection:Connected)
(/= crtc 0))
(with-slots (x y width height)
(xcb:+request-unchecked+reply exwm--connection
(make-instance 'xcb:randr:GetCrtcInfo
:crtc crtc
:config-timestamp config-timestamp))
(setq output-name (decode-coding-string
(apply #'unibyte-string name) 'utf-8)
geometry (make-instance 'xcb:RECTANGLE
:x x
:y y
:width width
:height height)
output-geometry-alist (cons (cons output-name geometry)
output-geometry-alist))
(exwm--log "%s: %sx%s+%s+%s" output-name x y width height)
;; The primary output is the first one.
(unless primary-output
(setq primary-output output-name)))))))
(exwm--log "Primary output: %s" primary-output)
(list primary-output output-geometry-alist
(exwm-randr--get-monitor-alias primary-output
output-geometry-alist))))
(defun exwm-randr--get-monitor-alias (primary-monitor monitor-geometry-alist)
"Generate monitor aliases using PRIMARY-MONITOR MONITOR-GEOMETRY-ALIST.
In a mirroring setup some monitors overlap and should be treated as one."
(let (monitor-position-alist monitor-alias-alist monitor-name geometry)
(setq monitor-position-alist (with-slots (x y) (setq monitor-position-alist (with-slots (x y)
(cdr (assoc primary-monitor (cdr (assoc primary-monitor
monitor-geometry-alist)) monitor-geometry-alist))
@ -147,14 +199,16 @@ corresponding monitors whenever the monitors are active.
monitor-position-alist) monitor-position-alist)
monitor-alias-alist (cons (cons monitor-name monitor-name) monitor-alias-alist (cons (cons monitor-name monitor-name)
monitor-alias-alist)))))) monitor-alias-alist))))))
(list primary-monitor monitor-geometry-alist monitor-alias-alist))) monitor-alias-alist))
;;;###autoload ;;;###autoload
(defun exwm-randr-refresh () (defun exwm-randr-refresh ()
"Refresh workspaces according to the updated RandR info." "Refresh workspaces according to the updated RandR info."
(interactive) (interactive)
(exwm--log) (exwm--log)
(let* ((result (exwm-randr--get-monitors)) (let* ((result (if exwm-randr--compatibility-mode
(exwm-randr--get-outputs)
(exwm-randr--get-monitors)))
(primary-monitor (elt result 0)) (primary-monitor (elt result 0))
(monitor-geometry-alist (elt result 1)) (monitor-geometry-alist (elt result 1))
(monitor-alias-alist (elt result 2)) (monitor-alias-alist (elt result 2))
@ -262,35 +316,41 @@ Refresh when any RandR 1.5 monitor changes."
(defun exwm-randr--init () (defun exwm-randr--init ()
"Initialize RandR extension and EXWM RandR module." "Initialize RandR extension and EXWM RandR module."
(exwm--log) (exwm--log)
(if (= 0 (slot-value (xcb:get-extension-data exwm--connection 'xcb:randr) (when (= 0 (slot-value (xcb:get-extension-data exwm--connection 'xcb:randr)
'present)) 'present))
(error "[EXWM] RandR extension is not supported by the server") (error "[EXWM] RandR extension is not supported by the server"))
(with-slots (major-version minor-version) (with-slots (major-version minor-version)
(xcb:+request-unchecked+reply exwm--connection (xcb:+request-unchecked+reply exwm--connection
(make-instance 'xcb:randr:QueryVersion (make-instance 'xcb:randr:QueryVersion
:major-version 1 :minor-version 5)) :major-version 1 :minor-version 5))
(if (or (/= major-version 1) (< minor-version 5)) (cond ((and (= major-version 1) (= minor-version 5))
(error "[EXWM] The server only support RandR version up to %d.%d" (setq exwm-randr--compatibility-mode nil))
major-version minor-version) ((and (= major-version 1) (>= minor-version 2))
;; External monitor(s) may already be connected. (setq exwm-randr--compatibility-mode t))
(run-hooks 'exwm-randr-screen-change-hook) (t
(exwm-randr-refresh) (error "[EXWM] The server only support RandR version up to %d.%d"
;; Listen for `ScreenChangeNotify' to notify external tools to major-version minor-version)))
;; configure RandR and `CrtcChangeNotify/OutputChangeNotify' to ;; External monitor(s) may already be connected.
;; refresh the workspace layout. (run-hooks 'exwm-randr-screen-change-hook)
(xcb:+event exwm--connection 'xcb:randr:ScreenChangeNotify (exwm-randr-refresh)
#'exwm-randr--on-ScreenChangeNotify) ;; Listen for `ScreenChangeNotify' to notify external tools to
(xcb:+event exwm--connection 'xcb:randr:Notify #'exwm-randr--on-Notify) ;; configure RandR and `CrtcChangeNotify/OutputChangeNotify' to
(xcb:+event exwm--connection 'xcb:ConfigureNotify ;; refresh the workspace layout.
#'exwm-randr--on-ConfigureNotify) (xcb:+event exwm--connection 'xcb:randr:ScreenChangeNotify
(xcb:+request exwm--connection #'exwm-randr--on-ScreenChangeNotify)
(make-instance 'xcb:randr:SelectInput (xcb:+event exwm--connection 'xcb:randr:Notify
:window exwm--root #'exwm-randr--on-Notify)
:enable (logior xcb:randr:NotifyMask:ScreenChange (xcb:+event exwm--connection 'xcb:ConfigureNotify
xcb:randr:NotifyMask:CrtcChange #'exwm-randr--on-ConfigureNotify)
xcb:randr:NotifyMask:OutputChange))) (xcb:+request exwm--connection
(xcb:flush exwm--connection) (make-instance 'xcb:randr:SelectInput
(add-hook 'exwm-workspace-list-change-hook #'exwm-randr-refresh)))) :window exwm--root
:enable (logior
xcb:randr:NotifyMask:ScreenChange
xcb:randr:NotifyMask:CrtcChange
xcb:randr:NotifyMask:OutputChange)))
(xcb:flush exwm--connection)
(add-hook 'exwm-workspace-list-change-hook #'exwm-randr-refresh))
;; Prevent frame parameters introduced by this module from being ;; Prevent frame parameters introduced by this module from being
;; saved/restored. ;; saved/restored.
(dolist (i '(exwm-randr-monitor)) (dolist (i '(exwm-randr-monitor))