about summary refs log tree commit diff
path: root/exwm-randr.el
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2019-04-14T00·00+0000
committerChris Feng <chris.w.feng@gmail.com>2019-04-14T00·00+0000
commitf70bdb5868fc098b7f1f44e6eced3819eb13ea42 (patch)
tree95ec342684c00193543ef3285342c8edb9464bae /exwm-randr.el
parent4ac0d6c1fd00ffd9229ef2d5fd1c63ee6151ed2d (diff)
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.
Diffstat (limited to 'exwm-randr.el')
-rw-r--r--exwm-randr.el132
1 files changed, 96 insertions, 36 deletions
diff --git a/exwm-randr.el b/exwm-randr.el
index 022a213153d8..c028c3029608 100644
--- a/exwm-randr.el
+++ b/exwm-randr.el
@@ -98,11 +98,13 @@ corresponding monitors whenever the monitors are active.
 (defvar exwm-randr--prev-screen-change-seqnum nil
   "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 ()
-  "Get RandR monitors."
+  "Get RandR 1.5 monitors."
   (exwm--log)
-  (let (monitor-name geometry monitor-geometry-alist primary-monitor
-                     monitor-position-alist monitor-alias-alist)
+  (let (monitor-name geometry monitor-geometry-alist primary-monitor)
     (with-slots (timestamp monitors)
         (xcb:+request-unchecked+reply exwm--connection
             (make-instance 'xcb:randr:GetMonitors
@@ -126,8 +128,58 @@ corresponding monitors whenever the monitors are active.
                     (not primary-monitor))
             (setq primary-monitor monitor-name)))))
     (exwm--log "Primary monitor: %s" primary-monitor)
-    ;; In a mirroring setup some monitors overlap and should be treated
-    ;; as one.
+    (list primary-monitor monitor-geometry-alist
+          (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)
                                      (cdr (assoc primary-monitor
                                                  monitor-geometry-alist))
@@ -147,14 +199,16 @@ corresponding monitors whenever the monitors are active.
                                                monitor-position-alist)
                   monitor-alias-alist (cons (cons monitor-name monitor-name)
                                             monitor-alias-alist))))))
-    (list primary-monitor monitor-geometry-alist monitor-alias-alist)))
+    monitor-alias-alist))
 
 ;;;###autoload
 (defun exwm-randr-refresh ()
   "Refresh workspaces according to the updated RandR info."
   (interactive)
   (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))
          (monitor-geometry-alist (elt result 1))
          (monitor-alias-alist (elt result 2))
@@ -262,35 +316,41 @@ Refresh when any RandR 1.5 monitor changes."
 (defun exwm-randr--init ()
   "Initialize RandR extension and EXWM RandR module."
   (exwm--log)
-  (if (= 0 (slot-value (xcb:get-extension-data exwm--connection 'xcb:randr)
-                       'present))
-      (error "[EXWM] RandR extension is not supported by the server")
-    (with-slots (major-version minor-version)
-        (xcb:+request-unchecked+reply exwm--connection
-            (make-instance 'xcb:randr:QueryVersion
-                           :major-version 1 :minor-version 5))
-      (if (or (/= major-version 1) (< minor-version 5))
-          (error "[EXWM] The server only support RandR version up to %d.%d"
-                 major-version minor-version)
-        ;; External monitor(s) may already be connected.
-        (run-hooks 'exwm-randr-screen-change-hook)
-        (exwm-randr-refresh)
-        ;; Listen for `ScreenChangeNotify' to notify external tools to
-        ;; configure RandR and `CrtcChangeNotify/OutputChangeNotify' to
-        ;; refresh the workspace layout.
-        (xcb:+event exwm--connection 'xcb:randr:ScreenChangeNotify
-                    #'exwm-randr--on-ScreenChangeNotify)
-        (xcb:+event exwm--connection 'xcb:randr:Notify #'exwm-randr--on-Notify)
-        (xcb:+event exwm--connection 'xcb:ConfigureNotify
-                    #'exwm-randr--on-ConfigureNotify)
-        (xcb:+request exwm--connection
-            (make-instance 'xcb:randr:SelectInput
-                           :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))))
+  (when (= 0 (slot-value (xcb:get-extension-data exwm--connection 'xcb:randr)
+                         'present))
+    (error "[EXWM] RandR extension is not supported by the server"))
+  (with-slots (major-version minor-version)
+      (xcb:+request-unchecked+reply exwm--connection
+          (make-instance 'xcb:randr:QueryVersion
+                         :major-version 1 :minor-version 5))
+    (cond ((and (= major-version 1) (= minor-version 5))
+           (setq exwm-randr--compatibility-mode nil))
+          ((and (= major-version 1) (>= minor-version 2))
+           (setq exwm-randr--compatibility-mode t))
+          (t
+           (error "[EXWM] The server only support RandR version up to %d.%d"
+                  major-version minor-version)))
+    ;; External monitor(s) may already be connected.
+    (run-hooks 'exwm-randr-screen-change-hook)
+    (exwm-randr-refresh)
+    ;; Listen for `ScreenChangeNotify' to notify external tools to
+    ;; configure RandR and `CrtcChangeNotify/OutputChangeNotify' to
+    ;; refresh the workspace layout.
+    (xcb:+event exwm--connection 'xcb:randr:ScreenChangeNotify
+                #'exwm-randr--on-ScreenChangeNotify)
+    (xcb:+event exwm--connection 'xcb:randr:Notify
+                #'exwm-randr--on-Notify)
+    (xcb:+event exwm--connection 'xcb:ConfigureNotify
+                #'exwm-randr--on-ConfigureNotify)
+    (xcb:+request exwm--connection
+        (make-instance 'xcb:randr:SelectInput
+                       :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
   ;; saved/restored.
   (dolist (i '(exwm-randr-monitor))