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
50static XExtensionInfo _nvctrl_ext_info_data;
51static XExtensionInfo *nvctrl_ext_info = &_nvctrl_ext_info_data;
52static /* 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
59static int close_display();
60static uintptr_t version_flags(Display *dpy, XExtDisplayInfo *info);
61static Bool wire_to_event();
62static /* 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
76static 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
82static 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
90static 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
105Bool 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
126static 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
150Bool 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
181Bool 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
212Bool 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
243void 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
270void 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
282Bool 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
321Bool 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
335Bool 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
374Bool 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
386Bool 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
426Bool 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
482Bool 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
495Bool 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
540Bool 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
553static 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
597Bool 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
641static 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
686Bool 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
730Bool 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
744static 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
781Bool 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
793Bool 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
805Bool 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
817Bool 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
829void 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
872Bool 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
912Bool 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
942Bool 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
969Bool 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
1027Bool 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
1040Bool 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
1117static 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