rrmode.c revision 1b5d61b8
11.1Sjwise/* 2 * Copyright © 2006 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#include "randrstr.h" 24 25RESTYPE RRModeType; 26 27static Bool 28RRModeEqual(xRRModeInfo * a, xRRModeInfo * b) 29{ 30 if (a->width != b->width) 31 return FALSE; 32 if (a->height != b->height) 33 return FALSE; 34 if (a->dotClock != b->dotClock) 35 return FALSE; 36 if (a->hSyncStart != b->hSyncStart) 37 return FALSE; 38 if (a->hSyncEnd != b->hSyncEnd) 39 return FALSE; 40 if (a->hTotal != b->hTotal) 41 return FALSE; 42 if (a->hSkew != b->hSkew) 43 return FALSE; 44 if (a->vSyncStart != b->vSyncStart) 45 return FALSE; 46 if (a->vSyncEnd != b->vSyncEnd) 47 return FALSE; 48 if (a->vTotal != b->vTotal) 49 return FALSE; 50 if (a->nameLength != b->nameLength) 51 return FALSE; 52 if (a->modeFlags != b->modeFlags) 53 return FALSE; 54 return TRUE; 55} 56 57/* 58 * Keep a list so it's easy to find modes in the resource database. 59 */ 60static int num_modes; 61static RRModePtr *modes; 62 63static RRModePtr 64RRModeCreate(xRRModeInfo * modeInfo, const char *name, ScreenPtr userScreen) 65{ 66 RRModePtr mode, *newModes; 67 68 if (!RRInit()) 69 return NULL; 70 71 mode = malloc(sizeof(RRModeRec) + modeInfo->nameLength + 1); 72 if (!mode) 73 return NULL; 74 mode->refcnt = 1; 75 mode->mode = *modeInfo; 76 mode->name = (char *) (mode + 1); 77 memcpy(mode->name, name, modeInfo->nameLength); 78 mode->name[modeInfo->nameLength] = '\0'; 79 mode->userScreen = userScreen; 80 81 if (num_modes) 82 newModes = reallocarray(modes, num_modes + 1, sizeof(RRModePtr)); 83 else 84 newModes = malloc(sizeof(RRModePtr)); 85 86 if (!newModes) { 87 free(mode); 88 return NULL; 89 } 90 91 mode->mode.id = FakeClientID(0); 92 if (!AddResource(mode->mode.id, RRModeType, (void *) mode)) { 93 free(newModes); 94 return NULL; 95 } 96 modes = newModes; 97 modes[num_modes++] = mode; 98 99 /* 100 * give the caller a reference to this mode 101 */ 102 ++mode->refcnt; 103 return mode; 104} 105 106static RRModePtr 107RRModeFindByName(const char *name, CARD16 nameLength) 108{ 109 int i; 110 RRModePtr mode; 111 112 for (i = 0; i < num_modes; i++) { 113 mode = modes[i]; 114 if (mode->mode.nameLength == nameLength && 115 !memcmp(name, mode->name, nameLength)) { 116 return mode; 117 } 118 } 119 return NULL; 120} 121 122RRModePtr 123RRModeGet(xRRModeInfo * modeInfo, const char *name) 124{ 125 int i; 126 127 for (i = 0; i < num_modes; i++) { 128 RRModePtr mode = modes[i]; 129 130 if (RRModeEqual(&mode->mode, modeInfo) && 131 !memcmp(name, mode->name, modeInfo->nameLength)) { 132 ++mode->refcnt; 133 return mode; 134 } 135 } 136 137 return RRModeCreate(modeInfo, name, NULL); 138} 139 140static RRModePtr 141RRModeCreateUser(ScreenPtr pScreen, 142 xRRModeInfo * modeInfo, const char *name, int *error) 143{ 144 RRModePtr mode; 145 146 mode = RRModeFindByName(name, modeInfo->nameLength); 147 if (mode) { 148 *error = BadName; 149 return NULL; 150 } 151 152 mode = RRModeCreate(modeInfo, name, pScreen); 153 if (!mode) { 154 *error = BadAlloc; 155 return NULL; 156 } 157 *error = Success; 158 return mode; 159} 160 161RRModePtr * 162RRModesForScreen(ScreenPtr pScreen, int *num_ret) 163{ 164 rrScrPriv(pScreen); 165 int o, c, m; 166 RRModePtr *screen_modes; 167 int num_screen_modes = 0; 168 169 screen_modes = xallocarray((num_modes ? num_modes : 1), sizeof(RRModePtr)); 170 if (!screen_modes) 171 return NULL; 172 173 /* 174 * Add modes from all outputs 175 */ 176 for (o = 0; o < pScrPriv->numOutputs; o++) { 177 RROutputPtr output = pScrPriv->outputs[o]; 178 int n; 179 180 for (m = 0; m < output->numModes + output->numUserModes; m++) { 181 RRModePtr mode = (m < output->numModes ? 182 output->modes[m] : 183 output->userModes[m - output->numModes]); 184 for (n = 0; n < num_screen_modes; n++) 185 if (screen_modes[n] == mode) 186 break; 187 if (n == num_screen_modes) 188 screen_modes[num_screen_modes++] = mode; 189 } 190 } 191 /* 192 * Add modes from all crtcs. The goal is to 193 * make sure all available and active modes 194 * are visible to the client 195 */ 196 for (c = 0; c < pScrPriv->numCrtcs; c++) { 197 RRCrtcPtr crtc = pScrPriv->crtcs[c]; 198 RRModePtr mode = crtc->mode; 199 int n; 200 201 if (!mode) 202 continue; 203 for (n = 0; n < num_screen_modes; n++) 204 if (screen_modes[n] == mode) 205 break; 206 if (n == num_screen_modes) 207 screen_modes[num_screen_modes++] = mode; 208 } 209 /* 210 * Add all user modes for this screen 211 */ 212 for (m = 0; m < num_modes; m++) { 213 RRModePtr mode = modes[m]; 214 int n; 215 216 if (mode->userScreen != pScreen) 217 continue; 218 for (n = 0; n < num_screen_modes; n++) 219 if (screen_modes[n] == mode) 220 break; 221 if (n == num_screen_modes) 222 screen_modes[num_screen_modes++] = mode; 223 } 224 225 *num_ret = num_screen_modes; 226 return screen_modes; 227} 228 229void 230RRModeDestroy(RRModePtr mode) 231{ 232 int m; 233 234 if (--mode->refcnt > 0) 235 return; 236 for (m = 0; m < num_modes; m++) { 237 if (modes[m] == mode) { 238 memmove(modes + m, modes + m + 1, 239 (num_modes - m - 1) * sizeof(RRModePtr)); 240 num_modes--; 241 if (!num_modes) { 242 free(modes); 243 modes = NULL; 244 } 245 break; 246 } 247 } 248 249 free(mode); 250} 251 252static int 253RRModeDestroyResource(void *value, XID pid) 254{ 255 RRModeDestroy((RRModePtr) value); 256 return 1; 257} 258 259/* 260 * Initialize mode type 261 */ 262Bool 263RRModeInit(void) 264{ 265 assert(num_modes == 0); 266 assert(modes == NULL); 267 RRModeType = CreateNewResourceType(RRModeDestroyResource, "MODE"); 268 if (!RRModeType) 269 return FALSE; 270 271 return TRUE; 272} 273 274/* 275 * Initialize mode type error value 276 */ 277void 278RRModeInitErrorValue(void) 279{ 280 SetResourceTypeErrorValue(RRModeType, RRErrorBase + BadRRMode); 281} 282 283int 284ProcRRCreateMode(ClientPtr client) 285{ 286 REQUEST(xRRCreateModeReq); 287 xRRCreateModeReply rep; 288 WindowPtr pWin; 289 ScreenPtr pScreen; 290 xRRModeInfo *modeInfo; 291 long units_after; 292 char *name; 293 int error, rc; 294 RRModePtr mode; 295 296 REQUEST_AT_LEAST_SIZE(xRRCreateModeReq); 297 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 298 if (rc != Success) 299 return rc; 300 301 pScreen = pWin->drawable.pScreen; 302 303 modeInfo = &stuff->modeInfo; 304 name = (char *) (stuff + 1); 305 units_after = (stuff->length - bytes_to_int32(sizeof(xRRCreateModeReq))); 306 307 /* check to make sure requested name fits within the data provided */ 308 if (bytes_to_int32(modeInfo->nameLength) > units_after) 309 return BadLength; 310 311 mode = RRModeCreateUser(pScreen, modeInfo, name, &error); 312 if (!mode) 313 return error; 314 315 rep = (xRRCreateModeReply) { 316 .type = X_Reply, 317 .sequenceNumber = client->sequence, 318 .length = 0, 319 .mode = mode->mode.id 320 }; 321 if (client->swapped) { 322 swaps(&rep.sequenceNumber); 323 swapl(&rep.length); 324 swapl(&rep.mode); 325 } 326 WriteToClient(client, sizeof(xRRCreateModeReply), &rep); 327 /* Drop out reference to this mode */ 328 RRModeDestroy(mode); 329 return Success; 330} 331 332int 333ProcRRDestroyMode(ClientPtr client) 334{ 335 REQUEST(xRRDestroyModeReq); 336 RRModePtr mode; 337 338 REQUEST_SIZE_MATCH(xRRDestroyModeReq); 339 VERIFY_RR_MODE(stuff->mode, mode, DixDestroyAccess); 340 341 if (!mode->userScreen) 342 return BadMatch; 343 if (mode->refcnt > 1) 344 return BadAccess; 345 FreeResource(stuff->mode, 0); 346 return Success; 347} 348 349int 350ProcRRAddOutputMode(ClientPtr client) 351{ 352 REQUEST(xRRAddOutputModeReq); 353 RRModePtr mode; 354 RROutputPtr output; 355 356 REQUEST_SIZE_MATCH(xRRAddOutputModeReq); 357 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 358 VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); 359 360 if (RROutputIsLeased(output)) 361 return BadAccess; 362 363 return RROutputAddUserMode(output, mode); 364} 365 366int 367ProcRRDeleteOutputMode(ClientPtr client) 368{ 369 REQUEST(xRRDeleteOutputModeReq); 370 RRModePtr mode; 371 RROutputPtr output; 372 373 REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq); 374 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 375 VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); 376 377 if (RROutputIsLeased(output)) 378 return BadAccess; 379 380 return RROutputDeleteUserMode(output, mode); 381} 382