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