736 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			736 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 "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 = malloc(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);
 | |
|     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 != 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;
 | |
| }
 |