Skip to content

Commit 2a00e0c

Browse files
committed
extensions: randr: fix RR-GET-SCREEN-INFO rates
The documentation for the RRGetScreenInfo request is admittedly opaque, but each screen size's corresponding sequence of refresh rates is preceded by a refresh rate count, which the length of the refresh rate information sequence includes, and the first of which RR-GET-SCREEN-INFO was skipping. Also, RR-GET-SCREEN-INFO was invariably reading the current refresh rate and the refresh rate information sequence whether the client had previously queried the version or not (which it had no way of knowing), which led to impenetrable SB-INT:INVALID-ARRAY-INDEX-ERRORs (on SBCL) when the server omitted the refresh rate information sequence in its reply. This commit introduces RR-MAYBE-QUERY-VERSION, which queries the version only when necessary (i.e., when supplied with NIL MAJOR and MINOR arguments), to conveniently handle version-dependent requests, and RR-HAS-RATES to handle the conditional refresh rates. Functions requiring RR-MAYBE-QUERY-VERSION should themselves accept MAJOR and MINOR as arguments in order to pass them on to RR-MAYBE-QUERY-VERSION. Although this commit introduces two backwards-incompatible changes, they should (hopefully) not be too inconvenient because this extension is as yet unfinished and thus unsuitable for general use. The first, and more important, change is the replacement of optional arguments with keyword arguments in all request functions having optional arguments, which affects only those callers who were supplying any optional arguments. Keyword arguments are more practical when functions have many unrequired arguments, and this will be the case of all functions executing version-dependent requests because the functions will need the extra (unrequired) MAJOR and MINOR arguments. The second, and more stylistic, change is the reordering of RR-GET-SCREEN-INFO's multiple return values in order that the current refresh rate and the refresh rate information sequence be located at the end (which evidently affects only the callers of the function). This is more consistent, because any parameters introduced in later protocol versions will belong at the end of any existing multiple return values in order to preserve backwards compatibility. Additionally: - Declaim RR-QUERY-VERSION and RR-GET-SCREEN-INFO, and expand their docstrings. - Fix the incorrect type definition of ROTATION-MASK. - Wrap some overlong lines. - Clean up some comments and whitespace. - Conform various details to the rest of the codebase.
1 parent bfed9f0 commit 2a00e0c

File tree

1 file changed

+132
-44
lines changed

1 file changed

+132
-44
lines changed

extensions/randr.lisp

Lines changed: 132 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@
182182
'(member :rotate-0 :rotate-90 :rotate-180 :rotate-270 :reflect-x :reflect-y))
183183

184184
(deftype rotation-mask ()
185-
'(or mask16 (clx-list event-mask-class)))
185+
'(or mask16 (clx-list rotation-mask-class)))
186186

187187
;; Select
188188

@@ -435,18 +435,49 @@
435435
(boolean state)
436436
)
437437

438-
;; x-requests
438+
;;; Helpers
439439

440+
(declaim (ftype (function (card32 card32) (values boolean &optional))
441+
rr-has-rates))
442+
(defun rr-has-rates (major minor)
443+
(or (> major 1)
444+
(and (= major 1) (>= minor 1))))
445+
446+
;;; Requests
447+
448+
(declaim (ftype (function (display) (values card32 card32 &optional))
449+
rr-query-version))
440450
(defun rr-query-version (display)
441-
"Returns version MAJOR and MINOR from server."
442-
(with-buffer-request-and-reply (display (randr-opcode display) nil :sizes (32))
451+
"Execute the RRQueryVersion request and return its result as multiple
452+
values consisting of the server's major and minor protocol versions."
453+
(with-buffer-request-and-reply (display (randr-opcode display) nil
454+
:sizes (32))
443455
((data +rr-QueryVersion+)
444456
(card32 +rr-major+)
445457
(card32 +rr-minor+))
446458
(values
447459
(card32-get 8)
448460
(card32-get 12))))
449461

462+
;; Unexported
463+
(declaim (ftype (function (display (or null card32) (or null card32))
464+
(values card32 card32 &optional))
465+
rr-maybe-query-version))
466+
(defun rr-maybe-query-version (display major minor)
467+
"Return MAJOR and MINOR as multiple values, substituting 0 for NIL,
468+
unless they are both NIL, in which case call RR-QUERY-VERSION and return
469+
its values.
470+
471+
Some requests (e.g., RRGetScreenInfo) behave differently after a version
472+
query (only the first query has any effect on these requests).
473+
In order that the functions executing such requests be able to skip
474+
subsequent (redundant) queries, have them accept MAJOR and MINOR keyword
475+
arguments and call this function with those arguments instead of calling
476+
RR-QUERY-VERSION."
477+
(if (or major minor)
478+
(values (or major 0) (or minor 0))
479+
(rr-query-version display)))
480+
450481
(defun rr-set-screen-config (window timestamp conf-timestamp size-id rotation refresh)
451482
"Sets the current screen to which the given window belongs. Timestamps are obtained from rr-get-screen-info. Rotation can be a list of rotation keys or a rotation mask. Returns timestamp, config timestamp, the root window of the screen and sub-pixel order."
452483
(let ((display (window-display window))
@@ -487,39 +518,96 @@
487518
(card16 select-mask)
488519
(pad16))))
489520

490-
(defun rr-get-screen-info (window &optional (result-type 'list))
491-
"Returns rotations, root-window, timestamp, config-timestamp, current-size-id, current rotation, current rate, a list of screen-size structures, and last a sequence of refresh-rates"
521+
(declaim (ftype (function (window &key
522+
(:major (or null card32))
523+
(:minor (or null card32))
524+
(:result-type t))
525+
(values (clx-list rotation-mask-class)
526+
window
527+
timestamp
528+
timestamp
529+
size-id
530+
(clx-list rotation-mask-class)
531+
(clx-list screen-size)
532+
(or null card16)
533+
(clx-sequence card16)
534+
&optional))
535+
rr-get-screen-info))
536+
(defun rr-get-screen-info (window &key major minor (result-type 'list))
537+
"Execute the RRGetScreenInfo request and return its result as multiple
538+
values consisting of:
539+
540+
1. List of possible rotations and reflections
541+
2. Root window
542+
3. Timestamp
543+
4. Configuration timestamp
544+
5. Current screen size index (in the list of possible screen sizes)
545+
6. Current rotation and reflection
546+
7. List of possible screen sizes
547+
8. Current refresh rate (non-NIL only if server's protocol version is
548+
1.1 or later)
549+
9. Sequence of refresh rate information (non-NIL only if server's
550+
protocol version is 1.1 or later)
551+
552+
Each screen size has in the refresh rate information sequence a
553+
corresponding refresh rate count followed by that number of possible
554+
refresh rates.
555+
For example, '(2 120 60 1 60) means that the first screen size has the
556+
two refresh rates 120 and 60, and that the second screen size has the
557+
single refresh rate 60.
558+
559+
If MAJOR and MINOR, which comprise the server's protocol version, are
560+
missing, this function executes the RRQueryVersion request before
561+
RRGetScreenInfo in order to, first, potentially ask the server to
562+
include, if it can, the current refresh rate and the refresh rate
563+
information sequence in its reply to the latter request, and second,
564+
determine whether this information is forthcoming.
565+
Otherwise, this function assumes MAJOR and MINOR are the result of
566+
RR-QUERY-VERSION -- failing which it will behave unreliably -- and it
567+
skips executing the RRQueryVersion request."
492568
(let ((display (window-display window)))
493-
(declare (type display display)
494-
(type window window))
495-
(with-buffer-request-and-reply (display (randr-opcode display) nil :sizes (8 16 32))
496-
((data +rr-GetScreenInfo+ )
497-
(window window))
498-
(let ((num-screens (card16-get 20))
499-
(num-rates (card16-get 28))
500-
(rates-location 0))
501-
(declare (type fixnum rates-location num-rates))
569+
(declare (type display display))
570+
(multiple-value-bind (major minor)
571+
(rr-maybe-query-version display major minor)
572+
(with-buffer-request-and-reply (display (randr-opcode display) nil
573+
:sizes (8 16 32))
574+
((data +rr-GetScreenInfo+)
575+
(window window))
576+
(let* ((num-screens (card16-get 20))
577+
(rate-info-length (card16-get 28))
578+
(screen-start +replysize+)
579+
(rate-info-start (index+ screen-start (index* num-screens 8)))
580+
(has-rates (rr-has-rates major minor)))
502581
(values
503-
(make-rotation-keys (card16-get 1)) ; possible rotations, using card16, not card8 from spec.
504-
(window-get 8) ;root window
505-
(card32-get 12) ;timestamp
506-
(card32-get 16) ;config-timestamp
507-
(card16-get 22) ;size-id
508-
(make-rotation-keys (card16-get 24)) ;current rotation
509-
(card16-get 26) ; current rate
510-
(loop :for x fixnum :from 1 :to num-screens
511-
:for offset fixnum := 32 :then (+ offset 8)
512-
:collect (make-screen-size (card16-get offset)
513-
(card16-get (index+ offset 2))
514-
(card16-get (index+ offset 4))
515-
(card16-get (index+ offset 6)))
516-
:finally (setf rates-location (+ offset 8 2)))
517-
(sequence-get :format card16 :length num-rates :index rates-location :result-type result-type))))))
518-
582+
;; Possible rotations and reflections
583+
(make-rotation-keys (card16-get 1))
584+
(window-get 8) ; Root window
585+
(card32-get 12) ; Timestamp
586+
(card32-get 16) ; Configuration timestamp
587+
(card16-get 22) ; Current screen size index
588+
;; Current rotation and reflection
589+
(make-rotation-keys (card16-get 24))
590+
(loop for i fixnum from 1 to num-screens
591+
for offset fixnum = screen-start then (+ offset 8)
592+
collect (make-screen-size (card16-get offset)
593+
(card16-get (index+ offset 2))
594+
(card16-get (index+ offset 4))
595+
(card16-get (index+ offset 6))))
596+
;; Some servers (e.g., X.Org) always reply with the current
597+
;; refresh rate if they support it, even before receiving any
598+
;; version query.
599+
;; However, the refresh rate information is available only
600+
;; after querying the version (when providing an appropriate
601+
;; client version).
602+
(when has-rates (card16-get 26)) ; Current refresh rate
603+
(when has-rates (sequence-get :result-type result-type
604+
:format card16
605+
:length rate-info-length
606+
:index rate-info-start))))))))
519607

520608
;; Version 1.2
521609

522-
(defun rr-get-screen-size-range (window &optional (result-type 'list))
610+
(defun rr-get-screen-size-range (window &key (result-type 'list))
523611
"Returns a sequence of minimum width, minimum height, max width, max height."
524612
(let ((display (window-display window)))
525613
(with-buffer-request-and-reply (display (randr-opcode display) nil :sizes (16))
@@ -546,7 +634,7 @@
546634
(card32 width-mm)
547635
(card32 height-mm))))
548636

549-
(defun rr-get-screen-resources (window &optional (result-type 'list))
637+
(defun rr-get-screen-resources (window &key (result-type 'list))
550638
""
551639
(let ((display (window-display window)))
552640
(declare (type display display)
@@ -574,7 +662,7 @@
574662

575663

576664

577-
(defun rr-get-output-info (display output config-timestamp &optional (result-type 'list))
665+
(defun rr-get-output-info (display output config-timestamp &key (result-type 'list))
578666
"FIXME: indexes might be off, name not decoded properly"
579667
(with-buffer-request-and-reply (display (randr-opcode display) nil :sizes (8 16 32))
580668
((data +rr-getoutputinfo+)
@@ -604,7 +692,7 @@
604692
(sequence-get :result-type 'string :format card16 :length name-length :index name-start :transform #'code-char))
605693
)))
606694

607-
(defun rr-list-output-properties (display output &optional (result-type 'list))
695+
(defun rr-list-output-properties (display output &key (result-type 'list))
608696
"Returns a list of atom properties for given display. ?keep it simple and return id's or atom-names?"
609697
(declare (type display display)
610698
(type card32 output))
@@ -615,7 +703,7 @@
615703
(values
616704
(sequence-get :format card32 :result-type result-type :length num-atoms :index +replysize+ :transform #'(lambda (id) (atom-name display id)))))))
617705

618-
(defun rr-query-output-property (display output atom &optional (result-type 'list))
706+
(defun rr-query-output-property (display output atom &key (result-type 'list))
619707
"Querys the current properties of an atom. Atom may be referenced by either id or keyword"
620708
(let ((atom (if (typep atom 'keyword) (find-atom display atom) atom)))
621709
(declare (type display display)
@@ -630,7 +718,7 @@
630718
(boolean-get 10) ; immutable
631719
(sequence-get :result-type result-type :index +replysize+ :length (card32-get 4))))))
632720

633-
(defun rr-configure-output-property (display output atom value-list &optional (pending nil) (range nil))
721+
(defun rr-configure-output-property (display output atom value-list &key pending range)
634722
"Atom can be specified by either id or keyword"
635723
(let ((atom (if (typep atom 'keyword) (find-atom display atom) atom))
636724
(seq (coerce value-list 'vector)))
@@ -647,7 +735,7 @@
647735
;; Spec says type is not interpreted, what use? shit, are certain property types tied to certain formats? change if necessary after get-output-property
648736

649737
;; FIXME asynchronous match error
650-
(defun rr-change-output-property (display output atom mode data &optional (atom-type 0) )
738+
(defun rr-change-output-property (display output atom mode data &key (atom-type 0))
651739
"Mode may be 0-replace 1-prepend 2-append. atom-type is obtained by calling rr-get-output-property "
652740
(let ((atom (if (typep atom 'keyword) (find-atom display atom) atom))
653741
(data-length (length data))
@@ -672,7 +760,7 @@
672760
(card32 output)
673761
(card32 atom))))
674762

675-
(defun rr-get-output-property (display output property &optional (type 0) (delete 0) (pending 0) (result-type 'list))
763+
(defun rr-get-output-property (display output property &key (type 0) (delete 0) (pending 0) (result-type 'list))
676764
""
677765
(let ((atom (if (typep property 'keyword) (find-atom display property) property)))
678766
(with-buffer-request-and-reply (display (randr-opcode display) nil :sizes (8 16 32))
@@ -744,7 +832,7 @@
744832
(card32 output)
745833
(card32 mode)))
746834

747-
(defun rr-get-crtc-info (display crtc config-timestamp &optional (result-type 'list))
835+
(defun rr-get-crtc-info (display crtc config-timestamp &key (result-type 'list))
748836
""
749837
(with-buffer-request-and-reply (display (randr-opcode display) nil :sizes (8 16 32))
750838
((data +rr-getcrtcinfo+)
@@ -794,7 +882,7 @@
794882
(values
795883
(card16-get 8))))
796884

797-
(defun rr-get-crtc-gamma (display crtc &optional (result-type 'list))
885+
(defun rr-get-crtc-gamma (display crtc &key (result-type 'list))
798886
"Get current gamma ramps, returns 3 sequences for red, green, blue."
799887
(with-buffer-request-and-reply (display (randr-opcode display) nil :sizes (8 16 32))
800888
((data +rr-getcrtcgamma+)
@@ -825,7 +913,7 @@
825913
;; version 1.3
826914

827915

828-
(defun rr-get-screen-resources-current (window &optional (result-type 'list ))
916+
(defun rr-get-screen-resources-current (window &key (result-type 'list))
829917
"Unlike RRGetScreenResources, this merely returns the current configuration, and does not poll for hardware changes."
830918
(let ((display (window-display window)))
831919
(with-buffer-request-and-reply (display (randr-opcode display) nil :sizes (8 16 32))
@@ -849,7 +937,7 @@
849937
(string-get name-bytes name-start))))))
850938

851939

852-
;; (defun rr-set-crtc-transform (display crtc transform &optional ( filter-name nil) ( filter-parameters nil))
940+
;; (defun rr-set-crtc-transform (display crtc transform &key filter-name filter-parameters)
853941
;; "FIXME:Transfrom may be a list or vector of length 9. ?perhaps allow length 6?"
854942
;; (let ((seq (if filter-parameters (coerce filter-parameters 'vector) nil ))
855943
;; (param-length (length filter-parameters))
@@ -874,7 +962,7 @@
874962
;; )))
875963

876964

877-
(defun rr-get-crtc-transform (display crtc &optional (result-type 'list))
965+
(defun rr-get-crtc-transform (display crtc &key (result-type 'list))
878966
""
879967
(with-buffer-request-and-reply (display (randr-opcode display) nil :sizes (8 16 32))
880968
((data +rr-getcrtctransform+)

0 commit comments

Comments
 (0)