mirror of
https://github.com/X11Libre/xserver.git
synced 2026-03-24 10:14:52 +00:00
Using calloc() instead of malloc() as preventive measure, so there never can be any hidden bugs or leaks due uninitialized memory. The extra cost of using this compiler intrinsic should be practically impossible to measure - in many cases a good compiler can even deduce if certain areas really don't need to be zero'd (because they're written to right after allocation) and create more efficient machine code. The code pathes in question are pretty cold anyways, so it's probably not worth even thinking about potential extra runtime costs. Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
750 lines
22 KiB
C
750 lines
22 KiB
C
/*
|
|
* 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 <dix-config.h>
|
|
|
|
#include "dix/dix_priv.h"
|
|
#include "randr/randrstr_priv.h"
|
|
#include "randr/rrdispatch_priv.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-%08lx", (unsigned long int)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(RROutput));
|
|
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 = ((double)(geometry->box.x2 - geometry->box.x1) / (first.box.x2 - first.box.x1)) * first.mmWidth;
|
|
geometry->mmHeight = ((double)(geometry->box.y2 - geometry->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 secondary;
|
|
|
|
if (!RRGetInfo(screen, FALSE))
|
|
return FALSE;
|
|
|
|
/* Count the number of crtcs in this and any secondary screens */
|
|
numCrtcs = pScrPriv->numCrtcs;
|
|
xorg_list_for_each_entry(secondary, &screen->secondary_list, secondary_head) {
|
|
rrScrPrivPtr pSecondaryPriv;
|
|
|
|
if (!secondary->is_output_secondary)
|
|
continue;
|
|
|
|
pSecondaryPriv = rrGetScrPriv(secondary);
|
|
numCrtcs += pSecondaryPriv->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(secondary, &screen->secondary_list, secondary_head) {
|
|
rrScrPrivPtr pSecondaryPriv;
|
|
|
|
if (!secondary->is_output_secondary)
|
|
continue;
|
|
|
|
pSecondaryPriv = rrGetScrPriv(secondary);
|
|
for (sc = 0; sc < pSecondaryPriv->numCrtcs; sc++, c++) {
|
|
if (pSecondaryPriv->crtcs[sc]->mode != NULL)
|
|
mon_list->server_crtc[c] = pSecondaryPriv->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(list.server_crtc[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 < list.num_crtcs; c++) {
|
|
RRCrtcPtr crtc = list.server_crtc[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;
|
|
}
|
|
|
|
void
|
|
RRMonitorFree(RRMonitorPtr monitor)
|
|
{
|
|
free(monitor);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
int
|
|
RRMonitorAdd(ClientPtr client, ScreenPtr screen, RRMonitorPtr monitor)
|
|
{
|
|
rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
|
|
int m;
|
|
ScreenPtr secondary;
|
|
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(secondary, &screen->secondary_list, secondary_head) {
|
|
if (!secondary->is_output_secondary)
|
|
continue;
|
|
|
|
if (RRMonitorMatchesOutputName(secondary, 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 = reallocarray(pScrPriv->monitors,
|
|
pScrPriv->numMonitors + 1,
|
|
sizeof (RRMonitorPtr));
|
|
else
|
|
monitors = calloc(1, sizeof(RRMonitorPtr));
|
|
|
|
if (!monitors)
|
|
return BadAlloc;
|
|
|
|
pScrPriv->monitors = monitors;
|
|
|
|
for (m = 0; m < pScrPriv->numMonitors; m++) {
|
|
RRMonitorPtr existing = pScrPriv->monitors[m];
|
|
|
|
/* 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;
|
|
}
|
|
|
|
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);
|
|
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;
|
|
|
|
noutputs = 0;
|
|
for (m = 0; m < nmonitors; m++) {
|
|
noutputs += monitors[m].numOutputs;
|
|
}
|
|
|
|
int payload_len = noutputs * sizeof(CARD32) + nmonitors * sizeof(xRRMonitorInfo);
|
|
|
|
xRRGetMonitorsReply rep = {
|
|
.type = X_Reply,
|
|
.sequenceNumber = client->sequence,
|
|
.timestamp = RRMonitorTimestamp(screen),
|
|
.length = bytes_to_int32(payload_len),
|
|
.nmonitors = nmonitors,
|
|
.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);
|
|
|
|
char *payload_buf = calloc(1, payload_len);
|
|
if (!payload_buf) {
|
|
RRMonitorFreeList(monitors, nmonitors);
|
|
return BadAlloc;
|
|
}
|
|
|
|
char *walk = payload_buf;
|
|
|
|
for (m = 0; m < nmonitors; m++) {
|
|
RRMonitorPtr monitor = &monitors[m];
|
|
xRRMonitorInfo *info = (xRRMonitorInfo*) walk;
|
|
*info = (xRRMonitorInfo) {
|
|
.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);
|
|
}
|
|
|
|
walk += sizeof(xRRMonitorInfo);
|
|
memcpy(walk, monitor->outputs, monitor->numOutputs * sizeof (RROutput));
|
|
if (client->swapped)
|
|
SwapLongs((CARD32*)walk, monitor->numOutputs);
|
|
|
|
walk += monitor->numOutputs * sizeof (RROutput);
|
|
}
|
|
|
|
WriteToClient(client, payload_len, payload_buf);
|
|
|
|
free(payload_buf);
|
|
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 != client->req_len - (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)
|
|
RRSendConfigNotify(screen);
|
|
else
|
|
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;
|
|
}
|
|
|
|
r = RRMonitorDelete(client, screen, stuff->name);
|
|
if (r == Success)
|
|
RRSendConfigNotify(screen);
|
|
return r;
|
|
}
|