1 /*
2  * Copyright (c) 2008 NVIDIA, Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 /*
25  * Make sure that XTHREADS is defined, so that the
26  * LockDisplay/UnlockDisplay macros are expanded properly and the
27  * libXNVCtrl library properly protects the Display connection.
28  */
29 
30 #define NEED_EVENTS
31 #define NEED_REPLIES
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <X11/Xlibint.h>
35 #include <X11/Xutil.h>
36 #include <X11/extensions/Xext.h>
37 #include <X11/extensions/extutil.h>
38 
39 #if !defined(XTHREADS)
40 #define XTHREADS
41 #endif /* XTHREADS */
42 
43 #include "NVCtrlLib.h"
44 #include "nv_control.h"
45 
46 #define NVCTRL_EXT_EXISTS              1
47 #define NVCTRL_EXT_NEED_TARGET_SWAP    2
48 #define NVCTRL_EXT_64_BIT_ATTRIBUTES   4
49 #define NVCTRL_EXT_NEED_CHECK          (1 << (sizeof(XPointer) - 1))
50 
51 static XExtensionInfo _nvctrl_ext_info_data;
52 static XExtensionInfo *nvctrl_ext_info = &_nvctrl_ext_info_data;
53 static /* const */ char *nvctrl_extension_name = NV_CONTROL_NAME;
54 
55 #define XNVCTRLCheckExtension(dpy,i,val) \
56   XextCheckExtension (dpy, i, nvctrl_extension_name, val)
57 #define XNVCTRLSimpleCheckExtension(dpy,i) \
58   XextSimpleCheckExtension (dpy, i, nvctrl_extension_name)
59 
60 static int close_display();
61 static uintptr_t version_flags(Display *dpy, XExtDisplayInfo *info);
62 static Bool wire_to_event();
63 static /* const */ XExtensionHooks nvctrl_extension_hooks = {
64     NULL,                               /* create_gc */
65     NULL,                               /* copy_gc */
66     NULL,                               /* flush_gc */
67     NULL,                               /* free_gc */
68     NULL,                               /* create_font */
69     NULL,                               /* free_font */
70     close_display,                      /* close_display */
71     wire_to_event,                      /* wire_to_event */
72     NULL,                               /* event_to_wire */
73     NULL,                               /* error */
74     NULL,                               /* error_string */
75 };
76 
77 static XEXT_GENERATE_FIND_DISPLAY (find_display, nvctrl_ext_info,
78                                    nvctrl_extension_name,
79                                    &nvctrl_extension_hooks,
80                                    NV_CONTROL_EVENTS,
81                                    (XPointer)NVCTRL_EXT_NEED_CHECK)
82 
XEXT_GENERATE_CLOSE_DISPLAY(close_display,nvctrl_ext_info)83 static XEXT_GENERATE_CLOSE_DISPLAY (close_display, nvctrl_ext_info)
84 
85 /*
86  * NV-CONTROL versions 1.8 and 1.9 pack the target_type and target_id
87  * fields in reversed order.  In order to talk to one of these servers,
88  * we need to swap these fields.
89  */
90 
91 static void XNVCTRLCheckTargetData(Display *dpy, XExtDisplayInfo *info,
92                                    int *target_type, int *target_id)
93 {
94     uintptr_t flags = version_flags(dpy, info);
95 
96     /* We need to swap the target_type and target_id */
97     if (flags & NVCTRL_EXT_NEED_TARGET_SWAP) {
98         int tmp;
99         tmp = *target_type;
100         *target_type = *target_id;
101         *target_id = tmp;
102     }
103 }
104 
105 
XNVCTRLQueryExtension(Display * dpy,int * event_basep,int * error_basep)106 Bool XNVCTRLQueryExtension (
107     Display *dpy,
108     int *event_basep,
109     int *error_basep
110 ){
111     XExtDisplayInfo *info = find_display (dpy);
112 
113     if (XextHasExtension(info)) {
114         if (event_basep) *event_basep = info->codes->first_event;
115         if (error_basep) *error_basep = info->codes->first_error;
116         return True;
117     } else {
118         return False;
119     }
120 }
121 
122 /*
123  * Retrieve any cached flags that depend on the version of the NV-CONTROL
124  * extension.
125  */
126 
version_flags(Display * dpy,XExtDisplayInfo * info)127 static uintptr_t version_flags(Display *dpy, XExtDisplayInfo *info)
128 {
129     uintptr_t data = (uintptr_t)info->data;
130 
131     /* If necessary, determine the NV-CONTROL version */
132     if (data & NVCTRL_EXT_NEED_CHECK) {
133         int major, minor;
134         data = 0;
135         if (XNVCTRLQueryVersion(dpy, &major, &minor)) {
136             data |= NVCTRL_EXT_EXISTS;
137             if (major == 1 && (minor == 8 || minor == 9)) {
138                 data |= NVCTRL_EXT_NEED_TARGET_SWAP;
139             }
140             if ((major > 1) || ((major == 1) && (minor > 20))) {
141                 data |= NVCTRL_EXT_64_BIT_ATTRIBUTES;
142             }
143         }
144 
145         info->data = (XPointer)data;
146     }
147 
148     return data;
149 }
150 
XNVCTRLQueryVersion(Display * dpy,int * major,int * minor)151 Bool XNVCTRLQueryVersion (
152     Display *dpy,
153     int *major,
154     int *minor
155 ){
156     XExtDisplayInfo *info = find_display (dpy);
157     xnvCtrlQueryExtensionReply rep;
158     xnvCtrlQueryExtensionReq   *req;
159 
160     if(!XextHasExtension(info))
161         return False;
162 
163     XNVCTRLCheckExtension (dpy, info, False);
164 
165     LockDisplay (dpy);
166     GetReq (nvCtrlQueryExtension, req);
167     req->reqType = info->codes->major_opcode;
168     req->nvReqType = X_nvCtrlQueryExtension;
169     if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
170         UnlockDisplay (dpy);
171         SyncHandle ();
172         return False;
173     }
174     if (major) *major = rep.major;
175     if (minor) *minor = rep.minor;
176     UnlockDisplay (dpy);
177     SyncHandle ();
178     return True;
179 }
180 
181 
XNVCTRLIsNvScreen(Display * dpy,int screen)182 Bool XNVCTRLIsNvScreen (
183     Display *dpy,
184     int screen
185 ){
186     XExtDisplayInfo *info = find_display (dpy);
187     xnvCtrlIsNvReply rep;
188     xnvCtrlIsNvReq   *req;
189     Bool isnv;
190 
191     if(!XextHasExtension(info))
192         return False;
193 
194     XNVCTRLCheckExtension (dpy, info, False);
195 
196     LockDisplay (dpy);
197     GetReq (nvCtrlIsNv, req);
198     req->reqType = info->codes->major_opcode;
199     req->nvReqType = X_nvCtrlIsNv;
200     req->screen = screen;
201     if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
202         UnlockDisplay (dpy);
203         SyncHandle ();
204         return False;
205     }
206     isnv = rep.isnv;
207     UnlockDisplay (dpy);
208     SyncHandle ();
209     return isnv;
210 }
211 
212 
XNVCTRLQueryTargetCount(Display * dpy,int target_type,int * value)213 Bool XNVCTRLQueryTargetCount (
214     Display *dpy,
215     int target_type,
216     int *value
217 ){
218     XExtDisplayInfo *info = find_display (dpy);
219     xnvCtrlQueryTargetCountReply  rep;
220     xnvCtrlQueryTargetCountReq   *req;
221 
222     if(!XextHasExtension(info))
223         return False;
224 
225     XNVCTRLCheckExtension (dpy, info, False);
226 
227     LockDisplay (dpy);
228     GetReq (nvCtrlQueryTargetCount, req);
229     req->reqType = info->codes->major_opcode;
230     req->nvReqType = X_nvCtrlQueryTargetCount;
231     req->target_type = target_type;
232     if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
233         UnlockDisplay (dpy);
234         SyncHandle ();
235         return False;
236     }
237     if (value) *value = rep.count;
238     UnlockDisplay (dpy);
239     SyncHandle ();
240     return True;
241 }
242 
243 
XNVCTRLSetTargetAttribute(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,int value)244 void XNVCTRLSetTargetAttribute (
245     Display *dpy,
246     int target_type,
247     int target_id,
248     unsigned int display_mask,
249     unsigned int attribute,
250     int value
251 ){
252     XExtDisplayInfo *info = find_display (dpy);
253     xnvCtrlSetAttributeReq *req;
254 
255     XNVCTRLSimpleCheckExtension (dpy, info);
256     XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id);
257 
258     LockDisplay (dpy);
259     GetReq (nvCtrlSetAttribute, req);
260     req->reqType = info->codes->major_opcode;
261     req->nvReqType = X_nvCtrlSetAttribute;
262     req->target_type = target_type;
263     req->target_id = target_id;
264     req->display_mask = display_mask;
265     req->attribute = attribute;
266     req->value = value;
267     UnlockDisplay (dpy);
268     SyncHandle ();
269 }
270 
XNVCTRLSetAttribute(Display * dpy,int screen,unsigned int display_mask,unsigned int attribute,int value)271 void XNVCTRLSetAttribute (
272     Display *dpy,
273     int screen,
274     unsigned int display_mask,
275     unsigned int attribute,
276     int value
277 ){
278     XNVCTRLSetTargetAttribute (dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen,
279                                display_mask, attribute, value);
280 }
281 
282 
XNVCTRLSetTargetAttributeAndGetStatus(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,int value)283 Bool XNVCTRLSetTargetAttributeAndGetStatus (
284     Display *dpy,
285     int target_type,
286     int target_id,
287     unsigned int display_mask,
288     unsigned int attribute,
289     int value
290 ){
291     XExtDisplayInfo *info = find_display (dpy);
292     xnvCtrlSetAttributeAndGetStatusReq *req;
293     xnvCtrlSetAttributeAndGetStatusReply rep;
294     Bool success;
295 
296     if(!XextHasExtension(info))
297         return False;
298 
299     XNVCTRLCheckExtension (dpy, info, False);
300 
301     LockDisplay (dpy);
302     GetReq (nvCtrlSetAttributeAndGetStatus, req);
303     req->reqType = info->codes->major_opcode;
304     req->nvReqType = X_nvCtrlSetAttributeAndGetStatus;
305     req->target_type = target_type;
306     req->target_id = target_id;
307     req->display_mask = display_mask;
308     req->attribute = attribute;
309     req->value = value;
310     if (!_XReply (dpy, (xReply *) &rep, 0, False)) {
311         UnlockDisplay (dpy);
312         SyncHandle ();
313         return False;
314     }
315     UnlockDisplay (dpy);
316     SyncHandle ();
317 
318     success = rep.flags;
319     return success;
320 }
321 
XNVCTRLSetAttributeAndGetStatus(Display * dpy,int screen,unsigned int display_mask,unsigned int attribute,int value)322 Bool XNVCTRLSetAttributeAndGetStatus (
323     Display *dpy,
324     int screen,
325     unsigned int display_mask,
326     unsigned int attribute,
327     int value
328 ){
329     return XNVCTRLSetTargetAttributeAndGetStatus(dpy,
330                                                  NV_CTRL_TARGET_TYPE_X_SCREEN,
331                                                  screen, display_mask,
332                                                  attribute, value);
333 }
334 
335 
XNVCTRLQueryTargetAttribute(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,int * value)336 Bool XNVCTRLQueryTargetAttribute (
337     Display *dpy,
338     int target_type,
339     int target_id,
340     unsigned int display_mask,
341     unsigned int attribute,
342     int *value
343 ){
344     XExtDisplayInfo *info = find_display (dpy);
345     xnvCtrlQueryAttributeReply rep;
346     xnvCtrlQueryAttributeReq   *req;
347     Bool exists;
348 
349     if(!XextHasExtension(info))
350         return False;
351 
352     XNVCTRLCheckExtension (dpy, info, False);
353     XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id);
354 
355     LockDisplay (dpy);
356     GetReq (nvCtrlQueryAttribute, req);
357     req->reqType = info->codes->major_opcode;
358     req->nvReqType = X_nvCtrlQueryAttribute;
359     req->target_type = target_type;
360     req->target_id = target_id;
361     req->display_mask = display_mask;
362     req->attribute = attribute;
363     if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
364         UnlockDisplay (dpy);
365         SyncHandle ();
366         return False;
367     }
368     exists = rep.flags;
369     if (exists && value) *value = rep.value;
370     UnlockDisplay (dpy);
371     SyncHandle ();
372     return exists;
373 }
374 
XNVCTRLQueryAttribute(Display * dpy,int screen,unsigned int display_mask,unsigned int attribute,int * value)375 Bool XNVCTRLQueryAttribute (
376     Display *dpy,
377     int screen,
378     unsigned int display_mask,
379     unsigned int attribute,
380     int *value
381 ){
382     return XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN,
383                                        screen, display_mask, attribute, value);
384 }
385 
386 
XNVCTRLQueryTargetAttribute64(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,int64_t * value)387 Bool XNVCTRLQueryTargetAttribute64 (
388     Display *dpy,
389     int target_type,
390     int target_id,
391     unsigned int display_mask,
392     unsigned int attribute,
393     int64_t *value
394 ){
395     XExtDisplayInfo *info = find_display(dpy);
396     xnvCtrlQueryAttribute64Reply rep;
397     xnvCtrlQueryAttributeReq *req;
398     Bool exists;
399 
400     if (!XextHasExtension(info))
401         return False;
402 
403     XNVCTRLCheckExtension(dpy, info, False);
404     XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id);
405 
406     LockDisplay(dpy);
407     GetReq(nvCtrlQueryAttribute, req);
408     req->reqType = info->codes->major_opcode;
409     req->nvReqType = X_nvCtrlQueryAttribute64;
410     req->target_type = target_type;
411     req->target_id = target_id;
412     req->display_mask = display_mask;
413     req->attribute = attribute;
414     if (!_XReply(dpy, (xReply *)&rep, 0, xTrue)) {
415         UnlockDisplay(dpy);
416         SyncHandle();
417         return False;
418     }
419     exists = rep.flags;
420     if (exists && value) *value = rep.value_64;
421     UnlockDisplay(dpy);
422     SyncHandle();
423     return exists;
424 }
425 
426 
XNVCTRLQueryTargetStringAttribute(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,char ** ptr)427 Bool XNVCTRLQueryTargetStringAttribute (
428     Display *dpy,
429     int target_type,
430     int target_id,
431     unsigned int display_mask,
432     unsigned int attribute,
433     char **ptr
434 ){
435     XExtDisplayInfo *info = find_display (dpy);
436     xnvCtrlQueryStringAttributeReply rep;
437     xnvCtrlQueryStringAttributeReq   *req;
438     Bool exists;
439     int length, numbytes, slop;
440 
441     if (!ptr) return False;
442 
443     if(!XextHasExtension(info))
444         return False;
445 
446     XNVCTRLCheckExtension (dpy, info, False);
447     XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id);
448 
449     LockDisplay (dpy);
450     GetReq (nvCtrlQueryStringAttribute, req);
451     req->reqType = info->codes->major_opcode;
452     req->nvReqType = X_nvCtrlQueryStringAttribute;
453     req->target_type = target_type;
454     req->target_id = target_id;
455     req->display_mask = display_mask;
456     req->attribute = attribute;
457     if (!_XReply (dpy, (xReply *) &rep, 0, False)) {
458         UnlockDisplay (dpy);
459         SyncHandle ();
460         return False;
461     }
462     length = rep.length;
463     numbytes = rep.n;
464     slop = numbytes & 3;
465     exists = rep.flags;
466     if (exists) {
467         *ptr = (char *) Xmalloc(numbytes);
468     }
469     if (!exists || !*ptr) {
470         _XEatData(dpy, length);
471         UnlockDisplay (dpy);
472         SyncHandle ();
473         return False;
474     } else {
475         _XRead(dpy, (char *) *ptr, numbytes);
476         if (slop) _XEatData(dpy, 4-slop);
477     }
478     UnlockDisplay (dpy);
479     SyncHandle ();
480     return exists;
481 }
482 
XNVCTRLQueryStringAttribute(Display * dpy,int screen,unsigned int display_mask,unsigned int attribute,char ** ptr)483 Bool XNVCTRLQueryStringAttribute (
484     Display *dpy,
485     int screen,
486     unsigned int display_mask,
487     unsigned int attribute,
488     char **ptr
489 ){
490     return XNVCTRLQueryTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN,
491                                              screen, display_mask,
492                                              attribute, ptr);
493 }
494 
495 
XNVCTRLSetTargetStringAttribute(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,char * ptr)496 Bool XNVCTRLSetTargetStringAttribute (
497     Display *dpy,
498     int target_type,
499     int target_id,
500     unsigned int display_mask,
501     unsigned int attribute,
502     char *ptr
503 ){
504     XExtDisplayInfo *info = find_display (dpy);
505     xnvCtrlSetStringAttributeReq *req;
506     xnvCtrlSetStringAttributeReply rep;
507     int size;
508     Bool success;
509 
510     if(!XextHasExtension(info))
511         return False;
512 
513     XNVCTRLCheckExtension (dpy, info, False);
514 
515     size = strlen(ptr)+1;
516 
517     LockDisplay (dpy);
518     GetReq (nvCtrlSetStringAttribute, req);
519     req->reqType = info->codes->major_opcode;
520     req->nvReqType = X_nvCtrlSetStringAttribute;
521     req->target_type = target_type;
522     req->target_id = target_id;
523     req->display_mask = display_mask;
524     req->attribute = attribute;
525     req->length += ((size + 3) & ~3) >> 2;
526     req->num_bytes = size;
527     Data(dpy, ptr, size);
528 
529     if (!_XReply (dpy, (xReply *) &rep, 0, False)) {
530         UnlockDisplay (dpy);
531         SyncHandle ();
532         return False;
533     }
534     UnlockDisplay (dpy);
535     SyncHandle ();
536 
537     success = rep.flags;
538     return success;
539 }
540 
XNVCTRLSetStringAttribute(Display * dpy,int screen,unsigned int display_mask,unsigned int attribute,char * ptr)541 Bool XNVCTRLSetStringAttribute (
542     Display *dpy,
543     int screen,
544     unsigned int display_mask,
545     unsigned int attribute,
546     char *ptr
547 ){
548     return XNVCTRLSetTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN,
549                                            screen, display_mask,
550                                            attribute, ptr);
551 }
552 
553 
XNVCTRLQueryValidTargetAttributeValues32(Display * dpy,XExtDisplayInfo * info,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,NVCTRLAttributeValidValuesRec * values)554 static Bool XNVCTRLQueryValidTargetAttributeValues32 (
555     Display *dpy,
556     XExtDisplayInfo *info,
557     int target_type,
558     int target_id,
559     unsigned int display_mask,
560     unsigned int attribute,
561     NVCTRLAttributeValidValuesRec *values
562 ){
563     xnvCtrlQueryValidAttributeValuesReply rep;
564     xnvCtrlQueryValidAttributeValuesReq   *req;
565     Bool exists;
566 
567     LockDisplay (dpy);
568     GetReq (nvCtrlQueryValidAttributeValues, req);
569     req->reqType = info->codes->major_opcode;
570     req->nvReqType = X_nvCtrlQueryValidAttributeValues;
571     req->target_type = target_type;
572     req->target_id = target_id;
573     req->display_mask = display_mask;
574     req->attribute = attribute;
575     if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
576         UnlockDisplay (dpy);
577         SyncHandle ();
578         return False;
579     }
580     exists = rep.flags;
581     if (exists) {
582         values->type = rep.attr_type;
583         if (rep.attr_type == ATTRIBUTE_TYPE_RANGE) {
584             values->u.range.min = rep.min;
585             values->u.range.max = rep.max;
586         }
587         if (rep.attr_type == ATTRIBUTE_TYPE_INT_BITS) {
588             values->u.bits.ints = rep.bits;
589         }
590         values->permissions = rep.perms;
591     }
592     UnlockDisplay (dpy);
593     SyncHandle ();
594     return exists;
595 }
596 
597 
XNVCTRLQueryValidTargetStringAttributeValues(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,NVCTRLAttributeValidValuesRec * values)598 Bool XNVCTRLQueryValidTargetStringAttributeValues (
599     Display *dpy,
600     int target_type,
601     int target_id,
602     unsigned int display_mask,
603     unsigned int attribute,
604     NVCTRLAttributeValidValuesRec *values
605 ){
606     XExtDisplayInfo *info = find_display(dpy);
607     Bool exists;
608     xnvCtrlQueryValidAttributeValuesReply rep;
609     xnvCtrlQueryValidAttributeValuesReq   *req;
610 
611     if (!values) return False;
612 
613     if (!XextHasExtension(info))
614         return False;
615 
616     XNVCTRLCheckExtension(dpy, info, False);
617 
618     LockDisplay(dpy);
619     GetReq (nvCtrlQueryValidAttributeValues, req);
620     req->reqType = info->codes->major_opcode;
621     req->nvReqType = X_nvCtrlQueryValidStringAttributeValues;
622     req->target_type = target_type;
623     req->target_id = target_id;
624     req->display_mask = display_mask;
625     req->attribute = attribute;
626     if (!_XReply(dpy, (xReply *)&rep, 0, xTrue)) {
627         UnlockDisplay(dpy);
628         SyncHandle();
629         return False;
630     }
631     exists = rep.flags;
632     if (exists) {
633         values->type = rep.attr_type;
634         values->permissions = rep.perms;
635     }
636     UnlockDisplay(dpy);
637     SyncHandle();
638     return exists;
639 }
640 
641 
XNVCTRLQueryValidTargetAttributeValues64(Display * dpy,XExtDisplayInfo * info,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,NVCTRLAttributeValidValuesRec * values)642 static Bool XNVCTRLQueryValidTargetAttributeValues64 (
643     Display *dpy,
644     XExtDisplayInfo *info,
645     int target_type,
646     int target_id,
647     unsigned int display_mask,
648     unsigned int attribute,
649     NVCTRLAttributeValidValuesRec *values
650 ){
651     xnvCtrlQueryValidAttributeValues64Reply rep;
652     xnvCtrlQueryValidAttributeValuesReq *req;
653     Bool exists;
654 
655     LockDisplay(dpy);
656     GetReq(nvCtrlQueryValidAttributeValues, req);
657     req->reqType = info->codes->major_opcode;
658     req->nvReqType = X_nvCtrlQueryValidAttributeValues64;
659     req->target_type = target_type;
660     req->target_id = target_id;
661     req->display_mask = display_mask;
662     req->attribute = attribute;
663     if (!_XReply(dpy, (xReply *)&rep,
664                  sz_xnvCtrlQueryValidAttributeValues64Reply_extra,
665                  xTrue)) {
666         UnlockDisplay(dpy);
667         SyncHandle();
668         return False;
669     }
670     exists = rep.flags;
671     if (exists) {
672         values->type = rep.attr_type;
673         if (rep.attr_type == ATTRIBUTE_TYPE_RANGE) {
674             values->u.range.min = rep.min_64;
675             values->u.range.max = rep.max_64;
676         }
677         if (rep.attr_type == ATTRIBUTE_TYPE_INT_BITS) {
678             values->u.bits.ints = rep.bits_64;
679         }
680         values->permissions = rep.perms;
681     }
682     UnlockDisplay(dpy);
683     SyncHandle();
684     return exists;
685 }
686 
XNVCTRLQueryValidTargetAttributeValues(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,NVCTRLAttributeValidValuesRec * values)687 Bool XNVCTRLQueryValidTargetAttributeValues (
688     Display *dpy,
689     int target_type,
690     int target_id,
691     unsigned int display_mask,
692     unsigned int attribute,
693     NVCTRLAttributeValidValuesRec *values
694 ){
695     XExtDisplayInfo *info = find_display(dpy);
696     Bool exists;
697     uintptr_t flags;
698 
699     if (!values) return False;
700 
701     if (!XextHasExtension(info))
702         return False;
703 
704     XNVCTRLCheckExtension(dpy, info, False);
705     XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id);
706 
707     flags = version_flags(dpy,info);
708 
709     if (!(flags & NVCTRL_EXT_EXISTS))
710         return False;
711 
712     if (flags & NVCTRL_EXT_64_BIT_ATTRIBUTES) {
713         exists = XNVCTRLQueryValidTargetAttributeValues64(dpy, info,
714                                                           target_type,
715                                                           target_id,
716                                                           display_mask,
717                                                           attribute,
718                                                           values);
719     } else {
720         exists = XNVCTRLQueryValidTargetAttributeValues32(dpy, info,
721                                                           target_type,
722                                                           target_id,
723                                                           display_mask,
724                                                           attribute,
725                                                           values);
726     }
727     return exists;
728 }
729 
730 
XNVCTRLQueryValidAttributeValues(Display * dpy,int screen,unsigned int display_mask,unsigned int attribute,NVCTRLAttributeValidValuesRec * values)731 Bool XNVCTRLQueryValidAttributeValues (
732     Display *dpy,
733     int screen,
734     unsigned int display_mask,
735     unsigned int attribute,
736     NVCTRLAttributeValidValuesRec *values
737 ){
738     return XNVCTRLQueryValidTargetAttributeValues(dpy,
739                                                   NV_CTRL_TARGET_TYPE_X_SCREEN,
740                                                   screen, display_mask,
741                                                   attribute, values);
742 }
743 
744 
QueryAttributePermissionsInternal(Display * dpy,unsigned int attribute,NVCTRLAttributePermissionsRec * permissions,unsigned int reqType)745 static Bool QueryAttributePermissionsInternal (
746     Display *dpy,
747     unsigned int attribute,
748     NVCTRLAttributePermissionsRec *permissions,
749     unsigned int reqType
750 ){
751     XExtDisplayInfo *info = find_display (dpy);
752     xnvCtrlQueryAttributePermissionsReply rep;
753     xnvCtrlQueryAttributePermissionsReq *req;
754     Bool exists;
755 
756     if(!XextHasExtension(info))
757         return False;
758 
759     XNVCTRLCheckExtension (dpy, info, False);
760 
761     LockDisplay(dpy);
762     GetReq(nvCtrlQueryAttributePermissions, req);
763     req->reqType = info->codes->major_opcode;
764     req->nvReqType = reqType;
765     req->attribute = attribute;
766     if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
767         UnlockDisplay (dpy);
768         SyncHandle();
769         return False;
770     }
771     exists = rep.flags;
772     if (exists && permissions) {
773         permissions->type = rep.attr_type;
774         permissions->permissions = rep.perms;
775     }
776     UnlockDisplay(dpy);
777     SyncHandle();
778     return exists;
779 }
780 
781 
XNVCTRLQueryAttributePermissions(Display * dpy,unsigned int attribute,NVCTRLAttributePermissionsRec * permissions)782 Bool XNVCTRLQueryAttributePermissions (
783     Display *dpy,
784     unsigned int attribute,
785     NVCTRLAttributePermissionsRec *permissions
786 ){
787     return QueryAttributePermissionsInternal(dpy,
788                                              attribute,
789                                              permissions,
790                                              X_nvCtrlQueryAttributePermissions);
791 }
792 
793 
XNVCTRLQueryStringAttributePermissions(Display * dpy,unsigned int attribute,NVCTRLAttributePermissionsRec * permissions)794 Bool XNVCTRLQueryStringAttributePermissions (
795     Display *dpy,
796     unsigned int attribute,
797     NVCTRLAttributePermissionsRec *permissions
798 ){
799     return QueryAttributePermissionsInternal(dpy,
800                                              attribute,
801                                              permissions,
802                                              X_nvCtrlQueryStringAttributePermissions);
803 }
804 
805 
XNVCTRLQueryBinaryDataAttributePermissions(Display * dpy,unsigned int attribute,NVCTRLAttributePermissionsRec * permissions)806 Bool XNVCTRLQueryBinaryDataAttributePermissions (
807     Display *dpy,
808     unsigned int attribute,
809     NVCTRLAttributePermissionsRec *permissions
810 ){
811     return QueryAttributePermissionsInternal(dpy,
812                                              attribute,
813                                              permissions,
814                                              X_nvCtrlQueryBinaryDataAttributePermissions);
815 }
816 
817 
XNVCTRLQueryStringOperationAttributePermissions(Display * dpy,unsigned int attribute,NVCTRLAttributePermissionsRec * permissions)818 Bool XNVCTRLQueryStringOperationAttributePermissions (
819     Display *dpy,
820     unsigned int attribute,
821     NVCTRLAttributePermissionsRec *permissions
822 ){
823     return QueryAttributePermissionsInternal(dpy,
824                                              attribute,
825                                              permissions,
826                                              X_nvCtrlQueryStringOperationAttributePermissions);
827 }
828 
829 
XNVCTRLSetGvoColorConversion(Display * dpy,int screen,float colorMatrix[3][3],float colorOffset[3],float colorScale[3])830 void XNVCTRLSetGvoColorConversion (
831     Display *dpy,
832     int screen,
833     float colorMatrix[3][3],
834     float colorOffset[3],
835     float colorScale[3]
836 ){
837     XExtDisplayInfo *info = find_display (dpy);
838     xnvCtrlSetGvoColorConversionReq *req;
839 
840     XNVCTRLSimpleCheckExtension (dpy, info);
841 
842     LockDisplay (dpy);
843     GetReq (nvCtrlSetGvoColorConversion, req);
844     req->reqType = info->codes->major_opcode;
845     req->nvReqType = X_nvCtrlSetGvoColorConversion;
846     req->screen = screen;
847 
848     req->cscMatrix_y_r = colorMatrix[0][0];
849     req->cscMatrix_y_g = colorMatrix[0][1];
850     req->cscMatrix_y_b = colorMatrix[0][2];
851 
852     req->cscMatrix_cr_r = colorMatrix[1][0];
853     req->cscMatrix_cr_g = colorMatrix[1][1];
854     req->cscMatrix_cr_b = colorMatrix[1][2];
855 
856     req->cscMatrix_cb_r = colorMatrix[2][0];
857     req->cscMatrix_cb_g = colorMatrix[2][1];
858     req->cscMatrix_cb_b = colorMatrix[2][2];
859 
860     req->cscOffset_y  = colorOffset[0];
861     req->cscOffset_cr = colorOffset[1];
862     req->cscOffset_cb = colorOffset[2];
863 
864     req->cscScale_y  = colorScale[0];
865     req->cscScale_cr = colorScale[1];
866     req->cscScale_cb = colorScale[2];
867 
868     UnlockDisplay (dpy);
869     SyncHandle ();
870 }
871 
872 
XNVCTRLQueryGvoColorConversion(Display * dpy,int screen,float colorMatrix[3][3],float colorOffset[3],float colorScale[3])873 Bool XNVCTRLQueryGvoColorConversion (
874     Display *dpy,
875     int screen,
876     float colorMatrix[3][3],
877     float colorOffset[3],
878     float colorScale[3]
879 ){
880     XExtDisplayInfo *info = find_display (dpy);
881     xnvCtrlQueryGvoColorConversionReply rep;
882     xnvCtrlQueryGvoColorConversionReq *req;
883 
884     if(!XextHasExtension(info))
885         return False;
886 
887     XNVCTRLCheckExtension (dpy, info, False);
888 
889     LockDisplay (dpy);
890 
891     GetReq (nvCtrlQueryGvoColorConversion, req);
892     req->reqType = info->codes->major_opcode;
893     req->nvReqType = X_nvCtrlQueryGvoColorConversion;
894     req->screen = screen;
895 
896     if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
897         UnlockDisplay (dpy);
898         SyncHandle ();
899         return False;
900     }
901 
902     _XRead(dpy, (char *)(colorMatrix), 36);
903     _XRead(dpy, (char *)(colorOffset), 12);
904     _XRead(dpy, (char *)(colorScale), 12);
905 
906     UnlockDisplay (dpy);
907     SyncHandle ();
908 
909     return True;
910 }
911 
912 
XNVCtrlSelectTargetNotify(Display * dpy,int target_type,int target_id,int notify_type,Bool onoff)913 Bool XNVCtrlSelectTargetNotify (
914     Display *dpy,
915     int target_type,
916     int target_id,
917     int notify_type,
918     Bool onoff
919 ){
920     XExtDisplayInfo *info = find_display (dpy);
921     xnvCtrlSelectTargetNotifyReq *req;
922 
923     if(!XextHasExtension (info))
924         return False;
925 
926     XNVCTRLCheckExtension (dpy, info, False);
927 
928     LockDisplay (dpy);
929     GetReq (nvCtrlSelectTargetNotify, req);
930     req->reqType = info->codes->major_opcode;
931     req->nvReqType = X_nvCtrlSelectTargetNotify;
932     req->target_type = target_type;
933     req->target_id = target_id;
934     req->notifyType = notify_type;
935     req->onoff = onoff;
936     UnlockDisplay (dpy);
937     SyncHandle ();
938 
939     return True;
940 }
941 
942 
XNVCtrlSelectNotify(Display * dpy,int screen,int type,Bool onoff)943 Bool XNVCtrlSelectNotify (
944     Display *dpy,
945     int screen,
946     int type,
947     Bool onoff
948 ){
949     XExtDisplayInfo *info = find_display (dpy);
950     xnvCtrlSelectNotifyReq *req;
951 
952     if(!XextHasExtension (info))
953         return False;
954 
955     XNVCTRLCheckExtension (dpy, info, False);
956 
957     LockDisplay (dpy);
958     GetReq (nvCtrlSelectNotify, req);
959     req->reqType = info->codes->major_opcode;
960     req->nvReqType = X_nvCtrlSelectNotify;
961     req->screen = screen;
962     req->notifyType = type;
963     req->onoff = onoff;
964     UnlockDisplay (dpy);
965     SyncHandle ();
966 
967     return True;
968 }
969 
XNVCTRLQueryTargetBinaryData(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,unsigned char ** ptr,int * len)970 Bool XNVCTRLQueryTargetBinaryData (
971     Display *dpy,
972     int target_type,
973     int target_id,
974     unsigned int display_mask,
975     unsigned int attribute,
976     unsigned char **ptr,
977     int *len
978 ){
979     XExtDisplayInfo *info = find_display (dpy);
980     xnvCtrlQueryBinaryDataReply rep;
981     xnvCtrlQueryBinaryDataReq   *req;
982     Bool exists;
983     int length, numbytes, slop;
984 
985     if (!ptr) return False;
986 
987     if(!XextHasExtension(info))
988         return False;
989 
990     XNVCTRLCheckExtension (dpy, info, False);
991     XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id);
992 
993     LockDisplay (dpy);
994     GetReq (nvCtrlQueryBinaryData, req);
995     req->reqType = info->codes->major_opcode;
996     req->nvReqType = X_nvCtrlQueryBinaryData;
997     req->target_type = target_type;
998     req->target_id = target_id;
999     req->display_mask = display_mask;
1000     req->attribute = attribute;
1001     if (!_XReply (dpy, (xReply *) &rep, 0, False)) {
1002         UnlockDisplay (dpy);
1003         SyncHandle ();
1004         return False;
1005     }
1006     length = rep.length;
1007     numbytes = rep.n;
1008     slop = numbytes & 3;
1009     exists = rep.flags;
1010     if (exists) {
1011         *ptr = (unsigned char *) Xmalloc(numbytes);
1012     }
1013     if (!exists || !*ptr) {
1014         _XEatData(dpy, length);
1015         UnlockDisplay (dpy);
1016         SyncHandle ();
1017         return False;
1018     } else {
1019         _XRead(dpy, (char *) *ptr, numbytes);
1020         if (slop) _XEatData(dpy, 4-slop);
1021     }
1022     if (len) *len = numbytes;
1023     UnlockDisplay (dpy);
1024     SyncHandle ();
1025     return exists;
1026 }
1027 
XNVCTRLQueryBinaryData(Display * dpy,int screen,unsigned int display_mask,unsigned int attribute,unsigned char ** ptr,int * len)1028 Bool XNVCTRLQueryBinaryData (
1029     Display *dpy,
1030     int screen,
1031     unsigned int display_mask,
1032     unsigned int attribute,
1033     unsigned char **ptr,
1034     int *len
1035 ){
1036     return XNVCTRLQueryTargetBinaryData(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN,
1037                                         screen, display_mask,
1038                                         attribute, ptr, len);
1039 }
1040 
XNVCTRLStringOperation(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,char * pIn,char ** ppOut)1041 Bool XNVCTRLStringOperation (
1042     Display *dpy,
1043     int target_type,
1044     int target_id,
1045     unsigned int display_mask,
1046     unsigned int attribute,
1047     char *pIn,
1048     char **ppOut
1049 ) {
1050     XExtDisplayInfo *info = find_display(dpy);
1051     xnvCtrlStringOperationReq *req;
1052     xnvCtrlStringOperationReply rep;
1053     Bool ret;
1054     int inSize, outSize, length, slop;
1055 
1056     if (!XextHasExtension(info))
1057         return False;
1058 
1059     if (!ppOut)
1060         return False;
1061 
1062     *ppOut = NULL;
1063 
1064     XNVCTRLCheckExtension(dpy, info, False);
1065     XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id);
1066 
1067     if (pIn) {
1068         inSize = strlen(pIn) + 1;
1069     } else {
1070         inSize = 0;
1071     }
1072 
1073     LockDisplay(dpy);
1074     GetReq(nvCtrlStringOperation, req);
1075 
1076     req->reqType = info->codes->major_opcode;
1077     req->nvReqType = X_nvCtrlStringOperation;
1078     req->target_type = target_type;
1079     req->target_id = target_id;
1080     req->display_mask = display_mask;
1081     req->attribute = attribute;
1082 
1083     req->length += ((inSize + 3) & ~3) >> 2;
1084     req->num_bytes = inSize;
1085 
1086     if (pIn) {
1087         Data(dpy, pIn, inSize);
1088     }
1089 
1090     if (!_XReply (dpy, (xReply *) &rep, 0, False)) {
1091         UnlockDisplay(dpy);
1092         SyncHandle();
1093         return False;
1094     }
1095 
1096     length = rep.length;
1097     outSize = rep.num_bytes;
1098     slop = outSize & 3;
1099 
1100     if (outSize) *ppOut = (char *) Xmalloc(outSize);
1101 
1102     if (!*ppOut) {
1103         _XEatData(dpy, length);
1104     } else {
1105         _XRead(dpy, (char *) *ppOut, outSize);
1106         if (slop) _XEatData(dpy, 4-slop);
1107     }
1108 
1109     ret = rep.ret;
1110 
1111     UnlockDisplay(dpy);
1112     SyncHandle();
1113 
1114     return ret;
1115 }
1116 
1117 
wire_to_event(Display * dpy,XEvent * host,xEvent * wire)1118 static Bool wire_to_event (Display *dpy, XEvent *host, xEvent *wire)
1119 {
1120     XExtDisplayInfo *info = find_display (dpy);
1121     XNVCtrlEvent *re;
1122     xnvctrlEvent *event;
1123     XNVCtrlEventTarget *reTarget;
1124     xnvctrlEventTarget *eventTarget;
1125     XNVCtrlEventTargetAvailability *reTargetAvailability;
1126     XNVCtrlStringEventTarget *reTargetString;
1127     XNVCtrlBinaryEventTarget *reTargetBinary;
1128 
1129     XNVCTRLCheckExtension (dpy, info, False);
1130 
1131     switch ((wire->u.u.type & 0x7F) - info->codes->first_event) {
1132     case ATTRIBUTE_CHANGED_EVENT:
1133         re = (XNVCtrlEvent *) host;
1134         event = (xnvctrlEvent *) wire;
1135         re->attribute_changed.type = event->u.u.type & 0x7F;
1136         re->attribute_changed.serial =
1137             _XSetLastRequestRead(dpy, (xGenericReply*) event);
1138         re->attribute_changed.send_event = ((event->u.u.type & 0x80) != 0);
1139         re->attribute_changed.display = dpy;
1140         re->attribute_changed.time = event->u.attribute_changed.time;
1141         re->attribute_changed.screen = event->u.attribute_changed.screen;
1142         re->attribute_changed.display_mask =
1143             event->u.attribute_changed.display_mask;
1144         re->attribute_changed.attribute = event->u.attribute_changed.attribute;
1145         re->attribute_changed.value = event->u.attribute_changed.value;
1146         break;
1147     case TARGET_ATTRIBUTE_CHANGED_EVENT:
1148         reTarget = (XNVCtrlEventTarget *) host;
1149         eventTarget = (xnvctrlEventTarget *) wire;
1150         reTarget->attribute_changed.type = eventTarget->u.u.type & 0x7F;
1151         reTarget->attribute_changed.serial =
1152             _XSetLastRequestRead(dpy, (xGenericReply*) eventTarget);
1153         reTarget->attribute_changed.send_event =
1154             ((eventTarget->u.u.type & 0x80) != 0);
1155         reTarget->attribute_changed.display = dpy;
1156         reTarget->attribute_changed.time =
1157             eventTarget->u.attribute_changed.time;
1158         reTarget->attribute_changed.target_type =
1159             eventTarget->u.attribute_changed.target_type;
1160         reTarget->attribute_changed.target_id =
1161             eventTarget->u.attribute_changed.target_id;
1162         reTarget->attribute_changed.display_mask =
1163             eventTarget->u.attribute_changed.display_mask;
1164         reTarget->attribute_changed.attribute =
1165             eventTarget->u.attribute_changed.attribute;
1166         reTarget->attribute_changed.value =
1167             eventTarget->u.attribute_changed.value;
1168         break;
1169     case TARGET_ATTRIBUTE_AVAILABILITY_CHANGED_EVENT:
1170         reTargetAvailability = (XNVCtrlEventTargetAvailability *) host;
1171         eventTarget = (xnvctrlEventTarget *) wire;
1172         reTargetAvailability->attribute_changed.type =
1173             eventTarget->u.u.type & 0x7F;
1174         reTargetAvailability->attribute_changed.serial =
1175             _XSetLastRequestRead(dpy, (xGenericReply*) eventTarget);
1176         reTargetAvailability->attribute_changed.send_event =
1177             ((eventTarget->u.u.type & 0x80) != 0);
1178         reTargetAvailability->attribute_changed.display = dpy;
1179         reTargetAvailability->attribute_changed.time =
1180             eventTarget->u.availability_changed.time;
1181         reTargetAvailability->attribute_changed.target_type =
1182             eventTarget->u.availability_changed.target_type;
1183         reTargetAvailability->attribute_changed.target_id =
1184             eventTarget->u.availability_changed.target_id;
1185         reTargetAvailability->attribute_changed.display_mask =
1186             eventTarget->u.availability_changed.display_mask;
1187         reTargetAvailability->attribute_changed.attribute =
1188             eventTarget->u.availability_changed.attribute;
1189         reTargetAvailability->attribute_changed.availability =
1190             eventTarget->u.availability_changed.availability;
1191         reTargetAvailability->attribute_changed.value =
1192             eventTarget->u.availability_changed.value;
1193         break;
1194     case TARGET_STRING_ATTRIBUTE_CHANGED_EVENT:
1195         reTargetString = (XNVCtrlStringEventTarget *) host;
1196         eventTarget = (xnvctrlEventTarget *) wire;
1197         reTargetString->attribute_changed.type = eventTarget->u.u.type & 0x7F;
1198         reTargetString->attribute_changed.serial =
1199             _XSetLastRequestRead(dpy, (xGenericReply*) eventTarget);
1200         reTargetString->attribute_changed.send_event =
1201             ((eventTarget->u.u.type & 0x80) != 0);
1202         reTargetString->attribute_changed.display = dpy;
1203         reTargetString->attribute_changed.time =
1204             eventTarget->u.attribute_changed.time;
1205         reTargetString->attribute_changed.target_type =
1206             eventTarget->u.attribute_changed.target_type;
1207         reTargetString->attribute_changed.target_id =
1208             eventTarget->u.attribute_changed.target_id;
1209         reTargetString->attribute_changed.display_mask =
1210             eventTarget->u.attribute_changed.display_mask;
1211         reTargetString->attribute_changed.attribute =
1212             eventTarget->u.attribute_changed.attribute;
1213         break;
1214     case TARGET_BINARY_ATTRIBUTE_CHANGED_EVENT:
1215         reTargetBinary = (XNVCtrlBinaryEventTarget *) host;
1216         eventTarget = (xnvctrlEventTarget *) wire;
1217         reTargetBinary->attribute_changed.type = eventTarget->u.u.type & 0x7F;
1218         reTargetBinary->attribute_changed.serial =
1219             _XSetLastRequestRead(dpy, (xGenericReply*) eventTarget);
1220         reTargetBinary->attribute_changed.send_event =
1221             ((eventTarget->u.u.type & 0x80) != 0);
1222         reTargetBinary->attribute_changed.display = dpy;
1223         reTargetBinary->attribute_changed.time =
1224             eventTarget->u.attribute_changed.time;
1225         reTargetBinary->attribute_changed.target_type =
1226             eventTarget->u.attribute_changed.target_type;
1227         reTargetBinary->attribute_changed.target_id =
1228             eventTarget->u.attribute_changed.target_id;
1229         reTargetBinary->attribute_changed.display_mask =
1230             eventTarget->u.attribute_changed.display_mask;
1231         reTargetBinary->attribute_changed.attribute =
1232             eventTarget->u.attribute_changed.attribute;
1233         break;
1234 
1235     default:
1236         return False;
1237     }
1238 
1239     return True;
1240 }
1241 
1242