aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/randr/rrmonitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/randr/rrmonitor.c')
-rw-r--r--xorg-server/randr/rrmonitor.c748
1 files changed, 748 insertions, 0 deletions
diff --git a/xorg-server/randr/rrmonitor.c b/xorg-server/randr/rrmonitor.c
new file mode 100644
index 000000000..fbdd352f6
--- /dev/null
+++ b/xorg-server/randr/rrmonitor.c
@@ -0,0 +1,748 @@
+/*
+ * Copyright © 2014 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "randrstr.h"
+#include "swaprep.h"
+
+static Atom
+RRMonitorCrtcName(RRCrtcPtr crtc)
+{
+ char name[20];
+
+ if (crtc->numOutputs) {
+ RROutputPtr output = crtc->outputs[0];
+ return MakeAtom(output->name, output->nameLength, TRUE);
+ }
+ sprintf(name, "Monitor-%08x", crtc->id);
+ return MakeAtom(name, strlen(name), TRUE);
+}
+
+static Bool
+RRMonitorCrtcPrimary(RRCrtcPtr crtc)
+{
+ ScreenPtr screen = crtc->pScreen;
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+ int o;
+
+ for (o = 0; o < crtc->numOutputs; o++)
+ if (crtc->outputs[o] == pScrPriv->primaryOutput)
+ return TRUE;
+ return FALSE;
+}
+
+#define DEFAULT_PIXELS_PER_MM (96.0 / 25.4)
+
+static void
+RRMonitorGetCrtcGeometry(RRCrtcPtr crtc, RRMonitorGeometryPtr geometry)
+{
+ ScreenPtr screen = crtc->pScreen;
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+ BoxRec panned_area;
+
+ /* Check to see if crtc is panned and return the full area when applicable. */
+ if (pScrPriv && pScrPriv->rrGetPanning &&
+ pScrPriv->rrGetPanning(screen, crtc, &panned_area, NULL, NULL) &&
+ (panned_area.x2 > panned_area.x1) &&
+ (panned_area.y2 > panned_area.y1)) {
+ geometry->box = panned_area;
+ }
+ else {
+ int width, height;
+
+ RRCrtcGetScanoutSize(crtc, &width, &height);
+ geometry->box.x1 = crtc->x;
+ geometry->box.y1 = crtc->y;
+ geometry->box.x2 = geometry->box.x1 + width;
+ geometry->box.y2 = geometry->box.y1 + height;
+ }
+ if (crtc->numOutputs && crtc->outputs[0]->mmWidth && crtc->outputs[0]->mmHeight) {
+ RROutputPtr output = crtc->outputs[0];
+ geometry->mmWidth = output->mmWidth;
+ geometry->mmHeight = output->mmHeight;
+ } else {
+ geometry->mmWidth = floor ((geometry->box.x2 - geometry->box.x1) / DEFAULT_PIXELS_PER_MM + 0.5);
+ geometry->mmHeight = floor ((geometry->box.y2 - geometry->box.y1) / DEFAULT_PIXELS_PER_MM + 0.5);
+ }
+}
+
+static Bool
+RRMonitorSetFromServer(RRCrtcPtr crtc, RRMonitorPtr monitor)
+{
+ int o;
+
+ monitor->name = RRMonitorCrtcName(crtc);
+ monitor->pScreen = crtc->pScreen;
+ monitor->numOutputs = crtc->numOutputs;
+ monitor->outputs = calloc(crtc->numOutputs, sizeof(RRCrtc));
+ if (!monitor->outputs)
+ return FALSE;
+ for (o = 0; o < crtc->numOutputs; o++)
+ monitor->outputs[o] = crtc->outputs[o]->id;
+ monitor->primary = RRMonitorCrtcPrimary(crtc);
+ monitor->automatic = TRUE;
+ RRMonitorGetCrtcGeometry(crtc, &monitor->geometry);
+ return TRUE;
+}
+
+static Bool
+RRMonitorAutomaticGeometry(RRMonitorPtr monitor)
+{
+ return (monitor->geometry.box.x1 == 0 &&
+ monitor->geometry.box.y1 == 0 &&
+ monitor->geometry.box.x2 == 0 &&
+ monitor->geometry.box.y2 == 0);
+}
+
+static void
+RRMonitorGetGeometry(RRMonitorPtr monitor, RRMonitorGeometryPtr geometry)
+{
+ if (RRMonitorAutomaticGeometry(monitor) && monitor->numOutputs > 0) {
+ ScreenPtr screen = monitor->pScreen;
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+ RRMonitorGeometryRec first = { .box = { 0, 0, 0, 0 }, .mmWidth = 0, .mmHeight = 0 };
+ RRMonitorGeometryRec this;
+ int c, o, co;
+ int active_crtcs = 0;
+
+ *geometry = first;
+ for (o = 0; o < monitor->numOutputs; o++) {
+ RRCrtcPtr crtc = NULL;
+ Bool in_use = FALSE;
+
+ for (c = 0; !in_use && c < pScrPriv->numCrtcs; c++) {
+ crtc = pScrPriv->crtcs[c];
+ if (!crtc->mode)
+ continue;
+ for (co = 0; !in_use && co < crtc->numOutputs; co++)
+ if (monitor->outputs[o] == crtc->outputs[co]->id)
+ in_use = TRUE;
+ }
+
+ if (!in_use)
+ continue;
+
+ RRMonitorGetCrtcGeometry(crtc, &this);
+
+ if (active_crtcs == 0) {
+ first = this;
+ *geometry = this;
+ } else {
+ geometry->box.x1 = min(this.box.x1, geometry->box.x1);
+ geometry->box.x2 = max(this.box.x2, geometry->box.x2);
+ geometry->box.y1 = min(this.box.y1, geometry->box.y1);
+ geometry->box.y2 = max(this.box.y2, geometry->box.y2);
+ }
+ active_crtcs++;
+ }
+
+ /* Adjust physical sizes to account for total area */
+ if (active_crtcs > 1 && first.box.x2 != first.box.x1 && first.box.y2 != first.box.y1) {
+ geometry->mmWidth = (this.box.x2 - this.box.x1) / (first.box.x2 - first.box.x1) * first.mmWidth;
+ geometry->mmHeight = (this.box.y2 - this.box.y1) / (first.box.y2 - first.box.y1) * first.mmHeight;
+ }
+ } else {
+ *geometry = monitor->geometry;
+ }
+}
+
+static Bool
+RRMonitorSetFromClient(RRMonitorPtr client_monitor, RRMonitorPtr monitor)
+{
+ monitor->name = client_monitor->name;
+ monitor->pScreen = client_monitor->pScreen;
+ monitor->numOutputs = client_monitor->numOutputs;
+ monitor->outputs = calloc(client_monitor->numOutputs, sizeof (RROutput));
+ if (!monitor->outputs && client_monitor->numOutputs)
+ return FALSE;
+ memcpy(monitor->outputs, client_monitor->outputs, client_monitor->numOutputs * sizeof (RROutput));
+ monitor->primary = client_monitor->primary;
+ monitor->automatic = client_monitor->automatic;
+ RRMonitorGetGeometry(client_monitor, &monitor->geometry);
+ return TRUE;
+}
+
+typedef struct _rrMonitorList {
+ int num_client;
+ int num_server;
+ RRCrtcPtr *server_crtc;
+ int num_crtcs;
+ int client_primary;
+ int server_primary;
+} RRMonitorListRec, *RRMonitorListPtr;
+
+static Bool
+RRMonitorInitList(ScreenPtr screen, RRMonitorListPtr mon_list, Bool get_active)
+{
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+ int m, o, c, sc;
+ int numCrtcs;
+ ScreenPtr slave;
+
+ if (!RRGetInfo(screen, FALSE))
+ return FALSE;
+
+ /* Count the number of crtcs in this and any slave screens */
+ numCrtcs = pScrPriv->numCrtcs;
+ xorg_list_for_each_entry(slave, &screen->output_slave_list, output_head) {
+ rrScrPrivPtr pSlavePriv;
+ pSlavePriv = rrGetScrPriv(slave);
+ numCrtcs += pSlavePriv->numCrtcs;
+ }
+ mon_list->num_crtcs = numCrtcs;
+
+ mon_list->server_crtc = calloc(numCrtcs * 2, sizeof (RRCrtcPtr));
+ if (!mon_list->server_crtc)
+ return FALSE;
+
+ /* Collect pointers to all of the active crtcs */
+ c = 0;
+ for (sc = 0; sc < pScrPriv->numCrtcs; sc++, c++) {
+ if (pScrPriv->crtcs[sc]->mode != NULL)
+ mon_list->server_crtc[c] = pScrPriv->crtcs[sc];
+ }
+
+ xorg_list_for_each_entry(slave, &screen->output_slave_list, output_head) {
+ rrScrPrivPtr pSlavePriv;
+ pSlavePriv = rrGetScrPriv(slave);
+ for (sc = 0; sc < pSlavePriv->numCrtcs; sc++, c++) {
+ if (pSlavePriv->crtcs[sc]->mode != NULL)
+ mon_list->server_crtc[c] = pSlavePriv->crtcs[sc];
+ }
+ }
+
+ /* Walk the list of client-defined monitors, clearing the covered
+ * CRTCs from the full list and finding whether one of the
+ * monitors is primary
+ */
+ mon_list->num_client = pScrPriv->numMonitors;
+ mon_list->client_primary = -1;
+
+ for (m = 0; m < pScrPriv->numMonitors; m++) {
+ RRMonitorPtr monitor = pScrPriv->monitors[m];
+ if (get_active) {
+ RRMonitorGeometryRec geom;
+
+ RRMonitorGetGeometry(monitor, &geom);
+ if (geom.box.x2 - geom.box.x1 == 0 ||
+ geom.box.y2 - geom.box.y1 == 0) {
+ mon_list->num_client--;
+ continue;
+ }
+ }
+ if (monitor->primary && mon_list->client_primary == -1)
+ mon_list->client_primary = m;
+ for (o = 0; o < monitor->numOutputs; o++) {
+ for (c = 0; c < numCrtcs; c++) {
+ RRCrtcPtr crtc = mon_list->server_crtc[c];
+ if (crtc) {
+ int co;
+ for (co = 0; co < crtc->numOutputs; co++)
+ if (crtc->outputs[co]->id == monitor->outputs[o]) {
+ mon_list->server_crtc[c] = NULL;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Now look at the active CRTCs, and count
+ * those not covered by a client monitor, as well
+ * as finding whether one of them is marked primary
+ */
+ mon_list->num_server = 0;
+ mon_list->server_primary = -1;
+
+ for (c = 0; c < mon_list->num_crtcs; c++) {
+ RRCrtcPtr crtc = mon_list->server_crtc[c];
+
+ if (!crtc)
+ continue;
+
+ mon_list->num_server++;
+
+ if (RRMonitorCrtcPrimary(crtc) && mon_list->server_primary == -1)
+ mon_list->server_primary = c;
+ }
+ return TRUE;
+}
+
+static void
+RRMonitorFiniList(RRMonitorListPtr list)
+{
+ free(list->server_crtc);
+}
+
+/* Construct a complete list of protocol-visible monitors, including
+ * the manually generated ones as well as those generated
+ * automatically from the remaining CRCTs
+ */
+
+Bool
+RRMonitorMakeList(ScreenPtr screen, Bool get_active, RRMonitorPtr *monitors_ret, int *nmon_ret)
+{
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+ RRMonitorListRec list;
+ int m, c;
+ RRMonitorPtr mon, monitors;
+ Bool has_primary = FALSE;
+
+ if (!pScrPriv)
+ return FALSE;
+
+ if (!RRMonitorInitList(screen, &list, get_active))
+ return FALSE;
+
+ monitors = calloc(list.num_client + list.num_server, sizeof (RRMonitorRec));
+ if (!monitors) {
+ RRMonitorFiniList(&list);
+ return FALSE;
+ }
+
+ mon = monitors;
+
+ /* Fill in the primary monitor data first
+ */
+ if (list.client_primary >= 0) {
+ RRMonitorSetFromClient(pScrPriv->monitors[list.client_primary], mon);
+ mon++;
+ } else if (list.server_primary >= 0) {
+ RRMonitorSetFromServer(pScrPriv->crtcs[list.server_primary], mon);
+ mon++;
+ }
+
+ /* Fill in the client-defined monitors next
+ */
+ for (m = 0; m < pScrPriv->numMonitors; m++) {
+ if (m == list.client_primary)
+ continue;
+ if (get_active) {
+ RRMonitorGeometryRec geom;
+
+ RRMonitorGetGeometry(pScrPriv->monitors[m], &geom);
+ if (geom.box.x2 - geom.box.x1 == 0 ||
+ geom.box.y2 - geom.box.y1 == 0) {
+ continue;
+ }
+ }
+ RRMonitorSetFromClient(pScrPriv->monitors[m], mon);
+ if (has_primary)
+ mon->primary = FALSE;
+ else if (mon->primary)
+ has_primary = TRUE;
+ mon++;
+ }
+
+ /* And finish with the list of crtc-inspired monitors
+ */
+ for (c = 0; c < pScrPriv->numCrtcs; c++) {
+ RRCrtcPtr crtc = pScrPriv->crtcs[c];
+ if (c == list.server_primary && list.client_primary < 0)
+ continue;
+
+ if (!list.server_crtc[c])
+ continue;
+
+ RRMonitorSetFromServer(crtc, mon);
+ if (has_primary)
+ mon->primary = FALSE;
+ else if (mon->primary)
+ has_primary = TRUE;
+ mon++;
+ }
+
+ RRMonitorFiniList(&list);
+ *nmon_ret = list.num_client + list.num_server;
+ *monitors_ret = monitors;
+ return TRUE;
+}
+
+int
+RRMonitorCountList(ScreenPtr screen)
+{
+ RRMonitorListRec list;
+ int nmon;
+
+ if (!RRMonitorInitList(screen, &list, FALSE))
+ return -1;
+ nmon = list.num_client + list.num_server;
+ RRMonitorFiniList(&list);
+ return nmon;
+}
+
+static void
+RRMonitorFree(RRMonitorPtr monitor)
+{
+ free(monitor);
+}
+
+static RRMonitorPtr
+RRMonitorAlloc(int noutput)
+{
+ RRMonitorPtr monitor;
+
+ monitor = calloc(1, sizeof (RRMonitorRec) + noutput * sizeof (RROutput));
+ if (!monitor)
+ return NULL;
+ monitor->numOutputs = noutput;
+ monitor->outputs = (RROutput *) (monitor + 1);
+ return monitor;
+}
+
+static int
+RRMonitorDelete(ClientPtr client, ScreenPtr screen, Atom name)
+{
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+ int m;
+
+ if (!pScrPriv) {
+ client->errorValue = name;
+ return BadAtom;
+ }
+
+ for (m = 0; m < pScrPriv->numMonitors; m++) {
+ RRMonitorPtr monitor = pScrPriv->monitors[m];
+ if (monitor->name == name) {
+ memmove(pScrPriv->monitors + m, pScrPriv->monitors + m + 1,
+ (pScrPriv->numMonitors - (m + 1)) * sizeof (RRMonitorPtr));
+ --pScrPriv->numMonitors;
+ RRMonitorFree(monitor);
+ return Success;
+ }
+ }
+
+ client->errorValue = name;
+ return BadValue;
+}
+
+static Bool
+RRMonitorMatchesOutputName(ScreenPtr screen, Atom name)
+{
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+ int o;
+ const char *str = NameForAtom(name);
+ int len = strlen(str);
+
+ for (o = 0; o < pScrPriv->numOutputs; o++) {
+ RROutputPtr output = pScrPriv->outputs[o];
+
+ if (output->nameLength == len && !memcmp(output->name, str, len))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int
+RRMonitorAdd(ClientPtr client, ScreenPtr screen, RRMonitorPtr monitor)
+{
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+ int m;
+ ScreenPtr slave;
+ RRMonitorPtr *monitors;
+
+ if (!pScrPriv)
+ return BadAlloc;
+
+ /* 'name' must not match the name of any Output on the screen, or
+ * a Value error results.
+ */
+
+ if (RRMonitorMatchesOutputName(screen, monitor->name)) {
+ client->errorValue = monitor->name;
+ return BadValue;
+ }
+
+ xorg_list_for_each_entry(slave, &screen->output_slave_list, output_head) {
+ if (RRMonitorMatchesOutputName(slave, monitor->name)) {
+ client->errorValue = monitor->name;
+ return BadValue;
+ }
+ }
+
+ /* 'name' must not match the name of any Monitor on the screen, or
+ * a Value error results.
+ */
+
+ for (m = 0; m < pScrPriv->numMonitors; m++) {
+ if (pScrPriv->monitors[m]->name == monitor->name) {
+ client->errorValue = monitor->name;
+ return BadValue;
+ }
+ }
+
+ /* Allocate space for the new pointer. This is done before
+ * removing matching monitors as it may fail, and the request
+ * needs to not have any side-effects on failure
+ */
+ if (pScrPriv->numMonitors)
+ monitors = realloc(pScrPriv->monitors,
+ (pScrPriv->numMonitors + 1) * sizeof (RRMonitorPtr));
+ else
+ monitors = malloc(sizeof (RRMonitorPtr));
+
+ if (!monitors)
+ return BadAlloc;
+
+ pScrPriv->monitors = monitors;
+
+ for (m = 0; m < pScrPriv->numMonitors; m++) {
+ RRMonitorPtr existing = pScrPriv->monitors[m];
+ int o, eo;
+
+ /* If 'name' matches an existing Monitor on the screen, the
+ * existing one will be deleted as if RRDeleteMonitor were called.
+ */
+ if (existing->name == monitor->name) {
+ (void) RRMonitorDelete(client, screen, existing->name);
+ continue;
+ }
+
+ /* For each output in 'info.outputs', each one is removed from all
+ * pre-existing Monitors. If removing the output causes the list
+ * of outputs for that Monitor to become empty, then that
+ * Monitor will be deleted as if RRDeleteMonitor were called.
+ */
+
+ for (eo = 0; eo < existing->numOutputs; eo++) {
+ for (o = 0; o < monitor->numOutputs; o++) {
+ if (monitor->outputs[o] == existing->outputs[eo]) {
+ memmove(existing->outputs + eo, existing->outputs + eo + 1,
+ (existing->numOutputs - (eo + 1)) * sizeof (RROutput));
+ --existing->numOutputs;
+ --eo;
+ break;
+ }
+ }
+ if (existing->numOutputs == 0) {
+ (void) RRMonitorDelete(client, screen, existing->name);
+ break;
+ }
+ }
+ if (monitor->primary)
+ existing->primary = FALSE;
+ }
+
+ /* Add the new one to the list
+ */
+ pScrPriv->monitors[pScrPriv->numMonitors++] = monitor;
+
+ return Success;
+}
+
+void
+RRMonitorFreeList(RRMonitorPtr monitors, int nmon)
+{
+ int m;
+
+ for (m = 0; m < nmon; m++)
+ free(monitors[m].outputs);
+ free(monitors);
+}
+
+void
+RRMonitorInit(ScreenPtr screen)
+{
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+
+ if (!pScrPriv)
+ return;
+
+ pScrPriv->numMonitors = 0;
+ pScrPriv->monitors = NULL;
+}
+
+void
+RRMonitorClose(ScreenPtr screen)
+{
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+ int m;
+
+ if (!pScrPriv)
+ return;
+
+ for (m = 0; m < pScrPriv->numMonitors; m++)
+ RRMonitorFree(pScrPriv->monitors[m]);
+ free(pScrPriv->monitors);
+ pScrPriv->monitors = NULL;
+ pScrPriv->numMonitors = 0;
+}
+
+static CARD32
+RRMonitorTimestamp(ScreenPtr screen)
+{
+ rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+
+ /* XXX should take client monitor changes into account */
+ return pScrPriv->lastConfigTime.milliseconds;
+}
+
+int
+ProcRRGetMonitors(ClientPtr client)
+{
+ REQUEST(xRRGetMonitorsReq);
+ xRRGetMonitorsReply rep = {
+ .type = X_Reply,
+ .sequenceNumber = client->sequence,
+ .length = 0,
+ };
+ WindowPtr window;
+ ScreenPtr screen;
+ int r;
+ RRMonitorPtr monitors;
+ int nmonitors;
+ int noutputs;
+ int m;
+ Bool get_active;
+ REQUEST_SIZE_MATCH(xRRGetMonitorsReq);
+ r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
+ if (r != Success)
+ return r;
+ screen = window->drawable.pScreen;
+
+ get_active = stuff->get_active;
+ if (!RRMonitorMakeList(screen, get_active, &monitors, &nmonitors))
+ return BadAlloc;
+
+ rep.timestamp = RRMonitorTimestamp(screen);
+
+ noutputs = 0;
+ for (m = 0; m < nmonitors; m++) {
+ rep.length += SIZEOF(xRRMonitorInfo) >> 2;
+ rep.length += monitors[m].numOutputs;
+ noutputs += monitors[m].numOutputs;
+ }
+
+ rep.nmonitors = nmonitors;
+ rep.noutputs = noutputs;
+
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+ swapl(&rep.timestamp);
+ swapl(&rep.nmonitors);
+ swapl(&rep.noutputs);
+ }
+ WriteToClient(client, sizeof(xRRGetMonitorsReply), &rep);
+
+ client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
+
+ for (m = 0; m < nmonitors; m++) {
+ RRMonitorPtr monitor = &monitors[m];
+ xRRMonitorInfo info = {
+ .name = monitor->name,
+ .primary = monitor->primary,
+ .automatic = monitor->automatic,
+ .noutput = monitor->numOutputs,
+ .x = monitor->geometry.box.x1,
+ .y = monitor->geometry.box.y1,
+ .width = monitor->geometry.box.x2 - monitor->geometry.box.x1,
+ .height = monitor->geometry.box.y2 - monitor->geometry.box.y1,
+ .widthInMillimeters = monitor->geometry.mmWidth,
+ .heightInMillimeters = monitor->geometry.mmHeight,
+ };
+ if (client->swapped) {
+ swapl(&info.name);
+ swaps(&info.noutput);
+ swaps(&info.x);
+ swaps(&info.y);
+ swaps(&info.width);
+ swaps(&info.height);
+ swapl(&info.widthInMillimeters);
+ swapl(&info.heightInMillimeters);
+ }
+
+ WriteToClient(client, sizeof(xRRMonitorInfo), &info);
+ WriteSwappedDataToClient(client, monitor->numOutputs * sizeof (RROutput), monitor->outputs);
+ }
+
+ RRMonitorFreeList(monitors, nmonitors);
+
+ return Success;
+}
+
+int
+ProcRRSetMonitor(ClientPtr client)
+{
+ REQUEST(xRRSetMonitorReq);
+ WindowPtr window;
+ ScreenPtr screen;
+ RRMonitorPtr monitor;
+ int r;
+
+ REQUEST_AT_LEAST_SIZE(xRRSetMonitorReq);
+
+ if (stuff->monitor.noutput != stuff->length - (SIZEOF(xRRSetMonitorReq) >> 2))
+ return BadLength;
+
+ r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
+ if (r != Success)
+ return r;
+ screen = window->drawable.pScreen;
+
+ if (!ValidAtom(stuff->monitor.name))
+ return BadAtom;
+
+ /* Allocate the new monitor */
+ monitor = RRMonitorAlloc(stuff->monitor.noutput);
+ if (!monitor)
+ return BadAlloc;
+
+ /* Fill in the bits from the request */
+ monitor->pScreen = screen;
+ monitor->name = stuff->monitor.name;
+ monitor->primary = stuff->monitor.primary;
+ monitor->automatic = FALSE;
+ memcpy(monitor->outputs, stuff + 1, stuff->monitor.noutput * sizeof (RROutput));
+ monitor->geometry.box.x1 = stuff->monitor.x;
+ monitor->geometry.box.y1 = stuff->monitor.y;
+ monitor->geometry.box.x2 = stuff->monitor.x + stuff->monitor.width;
+ monitor->geometry.box.y2 = stuff->monitor.y + stuff->monitor.height;
+ monitor->geometry.mmWidth = stuff->monitor.widthInMillimeters;
+ monitor->geometry.mmHeight = stuff->monitor.heightInMillimeters;
+
+ r = RRMonitorAdd(client, screen, monitor);
+ if (r != Success)
+ RRMonitorFree(monitor);
+ return r;
+}
+
+int
+ProcRRDeleteMonitor(ClientPtr client)
+{
+ REQUEST(xRRDeleteMonitorReq);
+ WindowPtr window;
+ ScreenPtr screen;
+ int r;
+
+ REQUEST_SIZE_MATCH(xRRDeleteMonitorReq);
+ r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
+ if (r != Success)
+ return r;
+ screen = window->drawable.pScreen;
+
+ if (!ValidAtom(stuff->name)) {
+ client->errorValue = stuff->name;
+ return BadAtom;
+ }
+
+ return RRMonitorDelete(client, screen, stuff->name);
+}