2
* nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
5
* Copyright (C) 2004 NVIDIA Corporation.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of Version 2 of the GNU General Public
9
* License as published by the Free Software Foundation.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2
14
* of the GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the:
19
* Free Software Foundation, Inc.
20
* 59 Temple Place - Suite 330
21
* Boston, MA 02111-1307, USA
26
* config-file.c - this source file contains functions for processing
27
* the NVIDIA X Server control panel configuration file.
29
* The configuration file is simply a newline-separated list of
30
* attribute strings, where the syntax of an attribute string is
31
* described in the comments of parse.h
33
* The pound sign ('#') signifies the beginning of a comment; comments
34
* continue until a newline.
42
#include <sys/types.h>
50
#include "NvCtrlAttributes.h"
52
#include "config-file.h"
53
#include "query-assign.h"
57
#define MAX_CONFIG_FILE_LINE_LEN 256
64
} ParsedAttributeWrapper;
67
static ParsedAttributeWrapper *parse_config_file(char *buf,
71
static int process_config_file_attributes(const char *file,
72
ParsedAttributeWrapper *w,
73
const char *display_name);
75
static void save_gui_parsed_attributes(ParsedAttributeWrapper *w,
78
static float get_color_value(int attr,
79
float c[3], float b[3], float g[3]);
81
static int parse_config_properties(const char *line, ConfigProperties *conf);
83
static void init_config_properties(ConfigProperties *conf);
85
static void write_config_properties(FILE *stream, ConfigProperties *conf);
89
* nv_read_config_file() - read the specified config file, building a
90
* list of attributes to send. Once all attributes are read, send
91
* them to the X server.
93
* mmap(2) the file into memory for easier manipulation.
95
* If an error occurs while parsing the configuration file, an error
96
* message is printed to stderr, NV_FALSE is returned, and nothing is
97
* sent to the X server.
99
* XXX should we do any sort of versioning to handle compatibility
100
* problems in the future?
103
int nv_read_config_file(const char *file, const char *display_name,
104
ParsedAttribute *p, ConfigProperties *conf)
107
struct stat stat_buf;
109
ParsedAttributeWrapper *w = NULL;
111
/* initialize the ConfigProperties */
113
init_config_properties(conf);
117
fd = open(file, O_RDONLY);
120
* It's OK if the file doesn't exist... but should we print a
126
/* get the size of the file */
128
ret = fstat(fd, &stat_buf);
130
nv_error_msg("Unable to determine size of file '%s' (%s).",
131
file, strerror(errno));
135
if (stat_buf.st_size == 0) {
136
nv_warning_msg("File '%s' has zero size; not reading.", file);
141
/* map the file into memory */
143
buf = mmap(0, stat_buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
144
if (buf == (void *) -1) {
145
nv_error_msg("Unable to mmap file '%s' for reading (%s).",
146
file, strerror(errno));
150
/* parse the actual text in the file */
152
w = parse_config_file(buf, file, conf);
154
if (munmap (buf, stat_buf.st_size) == -1) {
155
nv_error_msg("Unable to unmap file '%s' after reading (%s).",
156
file, strerror(errno));
164
if (!w) return NV_FALSE;
166
/* process the parsed attributes */
168
ret = process_config_file_attributes(file, w, display_name);
171
* add any relevant parsed attributes back to the list to be
175
save_gui_parsed_attributes(w, p);
181
} /* nv_read_config_file() */
186
* nv_write_config_file() - write a configuration file to the
187
* specified filename.
189
* XXX how should this be handled? Currently, we just query all
190
* writable attributes, writing their current value to file.
192
* XXX should query first, and only once we know we can't fail, then
193
* write the file (to avoid deleting the existing file).
196
int nv_write_config_file(const char *filename, CtrlHandles *h,
197
ParsedAttribute *p, ConfigProperties *conf)
199
int screen, ret, entry, bit, val;
202
AttributeTableEntry *a;
204
NVCTRLAttributeValidValuesRec valid;
206
char *tmp_d_str, *tmp, *prefix, scratch[4];
208
stream = fopen(filename, "w");
210
nv_error_msg("Unable to open file '%s' for writing.", filename);
218
fprintf(stream, "#\n");
219
fprintf(stream, "# %s\n", filename);
220
fprintf(stream, "#\n");
221
fprintf(stream, "# Configuration file for nvidia-settings - the NVIDIA "
222
"X Server Settings utility\n");
224
/* NOTE: ctime(3) generates a new line */
226
fprintf(stream, "# Generated on %s", ctime(&now));
227
fprintf(stream, "#\n");
229
/* write the values in ConfigProperties */
231
write_config_properties(stream, conf);
233
/* for each screen, query each attribute in the table */
235
fprintf(stream, "\n");
236
fprintf(stream, "# Attributes:\n");
237
fprintf(stream, "\n");
239
for (screen = 0; screen < h->num_screens; screen++) {
241
/* skip it if we don't have a handle for this screen */
243
if (!h->h[screen]) continue;
246
* construct the prefix that will be printed in the config
247
* file infront of each attribute on this screen; this will
248
* either be "[screen]" or "[displayname]".
252
CONFIG_PROPERTIES_INCLUDE_DISPLAY_NAME_IN_CONFIG_FILE) {
253
prefix = h->screen_names[screen];
255
snprintf(scratch, 4, "%d", screen);
259
/* loop over all the entries in the table */
261
for (entry = 0; attributeTable[entry].name; entry++) {
263
a = &attributeTable[entry];
266
* skip all attributes that are not supposed to be written
270
if (a->flags & NV_PARSER_TYPE_NO_CONFIG_WRITE) continue;
273
* special case the color attributes because we want to
277
if (a->flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) {
278
float c[3], b[3], g[3];
279
status = NvCtrlGetColorAttributes(h->h[screen], c, b, g);
280
if (status != NvCtrlSuccess) continue;
281
fprintf(stream, "%s%c%s=%f\n",
282
prefix, DISPLAY_NAME_SEPARATOR, a->name,
283
get_color_value(a->attr, c, b, g));
287
for (bit = 0; bit < 24; bit++) {
291
if ((h->d[screen] & mask) == 0x0) continue;
294
NvCtrlGetValidDisplayAttributeValues(h->h[screen], mask,
297
if (status != NvCtrlSuccess) goto exit_bit_loop;
299
if ((valid.permissions & ATTRIBUTE_TYPE_WRITE) == 0x0)
302
status = NvCtrlGetDisplayAttribute(h->h[screen], mask,
305
if (status != NvCtrlSuccess) goto exit_bit_loop;
307
if (valid.permissions & ATTRIBUTE_TYPE_DISPLAY) {
310
display_device_mask_to_display_device_name(mask);
312
fprintf(stream, "%s%c%s[%s]=%d\n", prefix,
313
DISPLAY_NAME_SEPARATOR, a->name, tmp_d_str, val);
321
fprintf(stream, "%s%c%s=%d\n", prefix,
322
DISPLAY_NAME_SEPARATOR, a->name, val);
324
/* fall through to exit_bit_loop */
329
bit = 25; /* XXX force us out of the display device loop */
338
* loop the ParsedAttribute list, writing the attributes to file.
339
* note that we ignore conf->include_display_name_in_config_file
340
* when writing these parsed attributes; this is because parsed
341
* attributes (like the framelock properties) require a display
342
* name be specified (since there are multiple X servers
353
tmp = nv_get_attribute_name(p->attr);
356
if (p->display_device_mask) {
358
tmp_d_str = display_device_mask_to_display_device_name
359
(p->display_device_mask);
361
fprintf(stream, "%s%c%s[%s]=%d\n", p->display,
362
DISPLAY_NAME_SEPARATOR, tmp, tmp_d_str, p->val);
368
fprintf(stream, "%s%c%s=%d\n", p->display,
369
DISPLAY_NAME_SEPARATOR, tmp, p->val);
375
/* close the configuration file */
377
ret = fclose(stream);
379
nv_error_msg("Failure while closing file '%s'.", filename);
385
} /* nv_write_config_file() */
390
* parse_config_file() - scan through the buffer; skipping comment
391
* lines. Non-comment lines with non-whitespace characters are passed
392
* on to nv_parse_attribute_string for parsing.
394
* If an error occurs, an error message is printed and NULL is
395
* returned. If successful, a malloced array of
396
* ParsedAttributeWrapper structs is returned. The last
397
* ParsedAttributeWrapper in the array has line == -1. It is the
398
* caller's responsibility to free the array.
401
static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file,
402
ConfigProperties *conf)
404
int line, has_data, len, n, ret;
405
char *cur, *c, *comment, tmp[MAX_CONFIG_FILE_LINE_LEN];
406
ParsedAttributeWrapper *w;
416
has_data = NV_FALSE;;
418
while((*c != '\n') && (*c != '\0') && (*c != EOF)) {
419
if (comment) { c++; continue; }
420
if (*c == '#') { comment = c; continue; }
421
if (!isspace(*c)) has_data = NV_TRUE;
426
if (!comment) comment = c;
428
if (len >= MAX_CONFIG_FILE_LINE_LEN) {
429
nv_error_msg("Error parsing configuration file '%s' on "
430
"line %d: line length exceeds maximum "
432
file, line, MAX_CONFIG_FILE_LINE_LEN);
436
strncpy (tmp, cur, len);
439
/* first, see if this line is a config property */
441
if (!parse_config_properties(tmp, conf)) {
443
w = realloc(w, sizeof(ParsedAttributeWrapper) * (n+1));
445
ret = nv_parse_attribute_string(tmp,
446
NV_PARSER_ASSIGNMENT,
448
if (ret != NV_PARSER_STATUS_SUCCESS) {
449
nv_error_msg("Error parsing configuration file '%s' on "
450
"line %d: '%s' (%s).",
451
file, line, tmp, nv_parse_strerror(ret));
460
if ((*c == '\0') || (*c == EOF)) cur = NULL;
466
/* mark the end of the array */
468
w = realloc(w, sizeof(ParsedAttributeWrapper) * (n+1));
477
} /* parse_config_file() */
483
* process_config_file_attributes() - process the list of
484
* attributes to be assigned that we acquired in parsing the config
488
static int process_config_file_attributes(const char *file,
489
ParsedAttributeWrapper *w,
490
const char *display_name)
492
int i, j, ret, found, n = 0;
493
CtrlHandles **h = NULL;
496
* make sure that all ParsedAttributes have displays (this will do
497
* nothing if we already have a display name
500
for (i = 0; w[i].line != -1; i++) {
501
nv_assign_default_display(&w[i].a, display_name);
504
/* build the list of CtrlHandles */
506
for (i = 0; w[i].line != -1; i++) {
508
for (j = 0; j < n; j++) {
509
if (nv_strcasecmp(h[j]->display, w[i].a.display)) {
517
* no handle found for this display, need to create a new
520
* XXX we should really just build a list of what ctrl_handles
521
* we need, and what attributes on which ctrl_handles, so that
522
* we don't have to pass NV_CTRL_ATTRIBUTES_ALL_SUBSYSTEMS to
523
* NvCtrlAttributeInit (done in nv_alloc_ctrl_handles())
524
* unless we really need it.
528
h = realloc(h, sizeof(CtrlHandles *) * (n + 1));
529
h[n] = nv_alloc_ctrl_handles(w[i].a.display);
535
/* now process each attribute, passing in the correct CtrlHandles */
537
for (i = 0; w[i].line != -1; i++) {
539
ret = nv_process_parsed_attribute(&w[i].a, w[i].h, NV_TRUE, NV_FALSE,
540
"on line %d of configuration file "
541
"'%s'", w[i].line, file);
543
* XXX should we fail if processing the attribute failed? For
544
* now, we'll just keep going through the rest of the config
549
/* free all the CtrlHandles we allocated */
551
for (i = 0; i < n; i++) {
552
nv_free_ctrl_handles(h[i]);
560
} /* process_config_file_attributes() */
565
* save_gui_parsed_attributes() - scan through the parsed attribute
566
* wrappers, and save any relevant attributes to the attribute list to
567
* be passed to the gui.
570
static void save_gui_parsed_attributes(ParsedAttributeWrapper *w,
575
for (i = 0; w[i].line != -1; i++) {
576
if (w[i].a.flags & NV_PARSER_TYPE_GUI_ATTRIUBUTE) {
577
nv_parsed_attribute_add(p, &w[i].a);
580
} /* save_gui_parsed_attributes() */
584
static float get_color_value(int attr, float c[3], float b[3], float g[3])
586
switch (attr & (ALL_VALUES | ALL_CHANNELS)) {
587
case (CONTRAST_VALUE | RED_CHANNEL): return c[RED_CHANNEL_INDEX];
588
case (CONTRAST_VALUE | GREEN_CHANNEL): return c[GREEN_CHANNEL_INDEX];
589
case (CONTRAST_VALUE | BLUE_CHANNEL): return c[BLUE_CHANNEL_INDEX];
590
case (BRIGHTNESS_VALUE | RED_CHANNEL): return b[RED_CHANNEL_INDEX];
591
case (BRIGHTNESS_VALUE | GREEN_CHANNEL): return b[GREEN_CHANNEL_INDEX];
592
case (BRIGHTNESS_VALUE | BLUE_CHANNEL): return b[BLUE_CHANNEL_INDEX];
593
case (GAMMA_VALUE | RED_CHANNEL): return g[RED_CHANNEL_INDEX];
594
case (GAMMA_VALUE | GREEN_CHANNEL): return g[GREEN_CHANNEL_INDEX];
595
case (GAMMA_VALUE | BLUE_CHANNEL): return g[BLUE_CHANNEL_INDEX];
598
} /* get_color_value() */
604
* Table of ConfigProperties (properties of the nvidia-settings
605
* utilities itself, rather than properties of the X screen(s) that
606
* nvidia-settings is configuring). The table just binds string names
607
* to the bitmask constants.
613
} ConfigPropertiesTableEntry;
615
ConfigPropertiesTableEntry configPropertyTable[] = {
616
{ "ToolTips", CONFIG_PROPERTIES_TOOLTIPS },
617
{ "DisplayStatusBar", CONFIG_PROPERTIES_DISPLAY_STATUS_BAR },
618
{ "SliderTextEntries", CONFIG_PROPERTIES_SLIDER_TEXT_ENTRIES },
619
{ "IncludeDisplayNameInConfigFile",
620
CONFIG_PROPERTIES_INCLUDE_DISPLAY_NAME_IN_CONFIG_FILE },
627
* parse_config_property() - special case the config properties; if
628
* the given line sets a config property, update conf as appropriate
629
* and return NV_TRUE. If the given line does not describe a config
630
* property, return NV_FALSE.
633
static int parse_config_properties(const char *line, ConfigProperties *conf)
636
ConfigPropertiesTableEntry *t;
640
no_spaces = remove_spaces(line);
642
if (!no_spaces) goto done;
644
s = strchr(no_spaces, '=');
650
for (t = configPropertyTable, flag = 0; t->name; t++) {
651
if (nv_strcasecmp(no_spaces, t->name)) {
657
if (!flag) goto done;
661
if (nv_strcasecmp(s, "yes")) {
662
conf->booleans |= flag;
663
} else if (nv_strcasecmp(s, "no")) {
664
conf->booleans &= ~flag;
673
if (no_spaces) free(no_spaces);
676
} /* parse_config_property() */
681
* write_config_properties() - write the ConfigProperties to file;
682
* this just amounts to looping through the table, and printing if
683
* each property is enabled or disabled.
686
static void write_config_properties(FILE *stream, ConfigProperties *conf)
688
ConfigPropertiesTableEntry *t;
690
fprintf(stream, "\n");
691
fprintf(stream, "# ConfigProperties:\n");
692
fprintf(stream, "\n");
694
for (t = configPropertyTable; t->name; t++) {
695
fprintf(stream, "%s = %s\n", t->name,
696
(t->flag & conf->booleans) ? "Yes" : "No");
698
} /* write_config_properties()*/
703
* init_config_properties() - initialize the ConfigProperties
707
static void init_config_properties(ConfigProperties *conf)
709
memset(conf, 0, sizeof(ConfigProperties));
712
(CONFIG_PROPERTIES_TOOLTIPS |
713
CONFIG_PROPERTIES_DISPLAY_STATUS_BAR |
714
CONFIG_PROPERTIES_SLIDER_TEXT_ENTRIES);
716
} /* init_config_properties() */