4d1f3250ce217ecfa2c83ac0674e9ae5fa8723b9
[platform/adaptation/emulator/spice-vdagent.git] / src / vdagentd-xorg-conf.c
1 /*  vdagentd.c vdagentd xorg.conf writing code
2
3     Copyright 2011, 2012 Red Hat, Inc.
4
5     Red Hat Authors:
6     Hans de Goede <hdegoede@redhat.com>
7
8     This program is free software: you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #ifdef HAVE_PCIACCESS
26 #include <pciaccess.h>
27 #endif
28
29 #include <string.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <syslog.h>
33 #include "vdagentd-xorg-conf.h"
34
35 #define FPRINTF(...) \
36     do { \
37         r = fprintf(f, __VA_ARGS__); \
38         if (r < 0) { \
39             syslog(LOG_ERR, "Error writing to %s: %m", xorg_conf); \
40             fclose(f); \
41             pci_system_cleanup(); \
42             return; \
43         } \
44     } while(0)
45
46 void vdagentd_write_xorg_conf(VDAgentMonitorsConfig *monitor_conf)
47 {
48 #ifdef HAVE_PCIACCESS
49     int i, r, count, min_x = INT_MAX, min_y = INT_MAX;
50     FILE *f;
51     struct pci_device_iterator *it;
52     struct pci_device *dev;
53     const struct pci_id_match qxl_id_match = {
54         .vendor_id = 0x1b36,
55         .device_id = 0x0100,
56         .subvendor_id = PCI_MATCH_ANY,
57         .subdevice_id = PCI_MATCH_ANY,
58     };
59     const char *xorg_conf = "/opt/var/run/spice-vdagentd/xorg.conf.spice";
60     const char *xorg_conf_old = "/opt/var/run/spice-vdagentd/xorg.conf.spice.old";
61
62     r = rename(xorg_conf, xorg_conf_old);
63     if (r && errno != ENOENT) {
64         syslog(LOG_ERR,
65                "Error renaming %s to %s: %m, not generating xorg.conf",
66                xorg_conf, xorg_conf_old);
67         return;
68     }
69
70     r = pci_system_init();
71     if (r) {
72         syslog(LOG_ERR, "Error initializing libpciaccess: %d, not generating xorg.conf", r);
73         return;
74     }
75
76     it = pci_id_match_iterator_create(&qxl_id_match);
77     if (!it) {
78         syslog(LOG_ERR, "Error could not create pci id iterator for QXL devices, not generating xorg.conf");
79         pci_system_cleanup();
80         return;
81     }
82
83     dev = pci_device_next(it);
84     if (!dev) {
85         syslog(LOG_ERR, "No QXL devices found, not generating xorg.conf");
86         pci_system_cleanup();
87         return;
88     }
89
90     f = fopen(xorg_conf, "w");
91     if (!f) {
92         syslog(LOG_ERR, "Error opening %s for writing: %m", xorg_conf);
93         pci_system_cleanup();
94         return;
95     }
96
97     FPRINTF("# xorg.conf generated by spice-vdagentd\n");
98     FPRINTF("# generated from monitor info provided by the client\n\n");
99
100     if (monitor_conf->num_of_monitors == 1) {
101         FPRINTF("# Client has only 1 monitor\n");
102         FPRINTF("# This works best with no xorg.conf, leaving xorg.conf empty\n");
103         fclose(f);
104         pci_system_cleanup();
105         return;
106     }
107
108     FPRINTF("Section \"ServerFlags\"\n");
109     FPRINTF("\tOption\t\t\"Xinerama\"\t\"true\"\n");
110     FPRINTF("EndSection\n\n");
111
112     i = 0;
113     do {
114         FPRINTF("Section \"Device\"\n");
115         FPRINTF("\tIdentifier\t\"qxl%d\"\n", i++);
116         FPRINTF("\tDriver\t\t\"qxl\"\n");
117         FPRINTF("\tBusID\t\t\"PCI:%02d:%02d:%d\"\n",
118                 dev->bus, dev->dev, dev->func);
119         FPRINTF("\tOption\t\t\"NumHeads\"\t\"1\"\n");
120         FPRINTF("EndSection\n\n");
121     } while ((dev = pci_device_next(it)));
122
123     if (i < monitor_conf->num_of_monitors) {
124         FPRINTF("# Client has %d monitors, but only %d qxl devices found\n",
125                 monitor_conf->num_of_monitors, i);
126         FPRINTF("# Only generation %d \"Screen\" sections\n\n", i);
127         count = i;
128     } else {
129         count = monitor_conf->num_of_monitors;
130     }
131
132     for (i = 0; i < count; i++) {
133         FPRINTF("Section \"Screen\"\n");
134         FPRINTF("\tIdentifier\t\"Screen%d\"\n", i);
135         FPRINTF("\tDevice\t\t\"qxl%d\"\n", i);
136         FPRINTF("\tDefaultDepth\t24\n");
137         FPRINTF("\tSubSection \"Display\"\n");
138         FPRINTF("\t\tViewport\t0 0\n");
139         FPRINTF("\t\tDepth\t\t24\n");
140         FPRINTF("\t\tModes\t\t\"%dx%d\"\n", monitor_conf->monitors[i].width,
141                 monitor_conf->monitors[i].height);
142         FPRINTF("\tEndSubSection\n");
143         FPRINTF("EndSection\n\n");
144     }
145
146     /* monitor_conf may contain negative values, convert these to 0 - # */
147     for (i = 0; i < count; i++) {
148         if (monitor_conf->monitors[i].x < min_x) {
149             min_x = monitor_conf->monitors[i].x;
150         }
151         if (monitor_conf->monitors[i].y < min_y) {
152             min_y = monitor_conf->monitors[i].y;
153         }
154     }
155
156     FPRINTF("Section \"ServerLayout\"\n");
157     FPRINTF("\tIdentifier\t\"layout\"\n");
158     for (i = 0; i < count; i++) {
159         FPRINTF("\tScreen\t\t\"Screen%d\" %d %d\n", i,
160                 monitor_conf->monitors[i].x - min_x,
161                 monitor_conf->monitors[i].y - min_y);
162     }
163     FPRINTF("EndSection\n");
164
165     fclose(f);
166     pci_system_cleanup();
167 #endif
168 }