diff options
author | Keith Packard <keithp@keithp.com> | 2014-12-16 01:59:03 -0800 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-03-31 12:32:04 +1000 |
commit | 7e1f86d42b54fb7f6492875e47a718eaeca3069b (patch) | |
tree | 5af781974f9bf0fd6ebfab80ad5b384a30090045 /randr | |
parent | 9c2b4f8e0e2b5d4b5e1102d6eea7bdb4211baa68 (diff) |
randr: Add Monitor support (v1.1)
Store the user-defined monitors in the RandR screen private.
Generate a list of monitors from both the user-defined ones and from
any outputs not mentioned in one of the user-defined monitors. This list
covers both the outputs in the main screen as well as any slaves.
v1.1: airlied: fix up primary skipping bug,
fix wrong height initialiser
add get_active flag from updated protocol.
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'randr')
-rw-r--r-- | randr/Makefile.am | 1 | ||||
-rw-r--r-- | randr/randr.c | 4 | ||||
-rw-r--r-- | randr/randrstr.h | 44 | ||||
-rw-r--r-- | randr/rrdispatch.c | 3 | ||||
-rw-r--r-- | randr/rrmonitor.c | 748 | ||||
-rw-r--r-- | randr/rrsdispatch.c | 38 |
6 files changed, 838 insertions, 0 deletions
diff --git a/randr/Makefile.am b/randr/Makefile.am index ccaff3f02..90dc9ec9a 100644 --- a/randr/Makefile.am +++ b/randr/Makefile.am @@ -15,6 +15,7 @@ librandr_la_SOURCES = \ rrdispatch.c \ rrinfo.c \ rrmode.c \ + rrmonitor.c \ rroutput.c \ rrpointer.c \ rrproperty.c \ diff --git a/randr/randr.c b/randr/randr.c index 6e3f14b4e..ad1dda227 100644 --- a/randr/randr.c +++ b/randr/randr.c @@ -98,6 +98,8 @@ RRCloseScreen(ScreenPtr pScreen) if (pScrPriv->provider) RRProviderDestroy(pScrPriv->provider); + RRMonitorClose(pScreen); + free(pScrPriv->crtcs); free(pScrPriv->outputs); free(pScrPriv); @@ -333,6 +335,8 @@ RRScreenInit(ScreenPtr pScreen) pScrPriv->numCrtcs = 0; pScrPriv->crtcs = NULL; + RRMonitorInit(pScreen); + RRNScreens += 1; /* keep count of screens that implement randr */ return TRUE; } diff --git a/randr/randrstr.h b/randr/randrstr.h index 13e6a8596..438a52aeb 100644 --- a/randr/randrstr.h +++ b/randr/randrstr.h @@ -80,6 +80,7 @@ typedef struct _rrProperty RRPropertyRec, *RRPropertyPtr; typedef struct _rrCrtc RRCrtcRec, *RRCrtcPtr; typedef struct _rrOutput RROutputRec, *RROutputPtr; typedef struct _rrProvider RRProviderRec, *RRProviderPtr; +typedef struct _rrMonitor RRMonitorRec, *RRMonitorPtr; struct _rrMode { int refcnt; @@ -169,6 +170,22 @@ struct _rrProvider { struct _rrProvider *output_source; }; +typedef struct _rrMonitorGeometry { + BoxRec box; + CARD32 mmWidth; + CARD32 mmHeight; +} RRMonitorGeometryRec, *RRMonitorGeometryPtr; + +struct _rrMonitor { + Atom name; + ScreenPtr pScreen; + int numOutputs; + RROutput *outputs; + Bool primary; + Bool automatic; + RRMonitorGeometryRec geometry; +}; + #if RANDR_12_INTERFACE typedef Bool (*RRScreenSetSizeProcPtr) (ScreenPtr pScreen, CARD16 width, @@ -338,6 +355,9 @@ typedef struct _rrScrPriv { RRProviderDestroyProcPtr rrProviderDestroy; + int numMonitors; + RRMonitorPtr *monitors; + } rrScrPrivRec, *rrScrPrivPtr; extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec; @@ -981,6 +1001,30 @@ extern _X_EXPORT void RRXineramaExtensionInit(void); #endif +void +RRMonitorInit(ScreenPtr screen); + +Bool +RRMonitorMakeList(ScreenPtr screen, Bool get_active, RRMonitorPtr *monitors_ret, int *nmon_ret); + +int +RRMonitorCountList(ScreenPtr screen); + +void +RRMonitorFreeList(RRMonitorPtr monitors, int nmon); + +void +RRMonitorClose(ScreenPtr screen); + +int +ProcRRGetMonitors(ClientPtr client); + +int +ProcRRSetMonitor(ClientPtr client); + +int +ProcRRDeleteMonitor(ClientPtr client); + #endif /* _RANDRSTR_H_ */ /* diff --git a/randr/rrdispatch.c b/randr/rrdispatch.c index b9346d3f9..13ac6b117 100644 --- a/randr/rrdispatch.c +++ b/randr/rrdispatch.c @@ -254,4 +254,7 @@ int (*ProcRandrVector[RRNumberRequests]) (ClientPtr) = { ProcRRChangeProviderProperty, /* 39 */ ProcRRDeleteProviderProperty, /* 40 */ ProcRRGetProviderProperty, /* 41 */ + ProcRRGetMonitors, /* 42 */ + ProcRRSetMonitor, /* 43 */ + ProcRRDeleteMonitor, /* 44 */ }; diff --git a/randr/rrmonitor.c b/randr/rrmonitor.c new file mode 100644 index 000000000..fbdd352f6 --- /dev/null +++ b/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); +} diff --git a/randr/rrsdispatch.c b/randr/rrsdispatch.c index 47558cf75..cf2a3b024 100644 --- a/randr/rrsdispatch.c +++ b/randr/rrsdispatch.c @@ -565,6 +565,41 @@ static int SProcRRGetProviderProperty(ClientPtr client) return ProcRandrVector[stuff->randrReqType] (client); } +static int SProcRRGetMonitors(ClientPtr client) { + REQUEST(xRRGetMonitorsReq); + + REQUEST_SIZE_MATCH(xRRGetMonitorsReq); + swaps(&stuff->length); + swapl(&stuff->window); + return ProcRandrVector[stuff->randrReqType] (client); +} + +static int SProcRRSetMonitor(ClientPtr client) { + REQUEST(xRRSetMonitorReq); + + REQUEST_AT_LEAST_SIZE(xRRGetMonitorsReq); + swaps(&stuff->length); + swapl(&stuff->window); + swapl(&stuff->monitor.name); + swaps(&stuff->monitor.noutput); + swaps(&stuff->monitor.x); + swaps(&stuff->monitor.y); + swaps(&stuff->monitor.width); + swaps(&stuff->monitor.height); + SwapRestL(stuff); + return ProcRandrVector[stuff->randrReqType] (client); +} + +static int SProcRRDeleteMonitor(ClientPtr client) { + REQUEST(xRRDeleteMonitorReq); + + REQUEST_SIZE_MATCH(xRRDeleteMonitorReq); + swaps(&stuff->length); + swapl(&stuff->window); + swapl(&stuff->name); + return ProcRandrVector[stuff->randrReqType] (client); +} + int (*SProcRandrVector[RRNumberRequests]) (ClientPtr) = { SProcRRQueryVersion, /* 0 */ /* we skip 1 to make old clients fail pretty immediately */ @@ -614,4 +649,7 @@ int (*SProcRandrVector[RRNumberRequests]) (ClientPtr) = { SProcRRChangeProviderProperty, /* 39 */ SProcRRDeleteProviderProperty, /* 40 */ SProcRRGetProviderProperty, /* 41 */ + SProcRRGetMonitors, /* 42 */ + SProcRRSetMonitor, /* 43 */ + SProcRRDeleteMonitor, /* 44 */ }; |