property.c (19792B)
1 /*********************************************************** 2 3 Copyright 1987, 1998 The Open Group 4 5 Permission to use, copy, modify, distribute, and sell this software and its 6 documentation for any purpose is hereby granted without fee, provided that 7 the above copyright notice appear in all copies and that both that 8 copyright notice and this permission notice appear in supporting 9 documentation. 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21 Except as contained in this notice, the name of The Open Group shall not be 22 used in advertising or otherwise to promote the sale, use or other dealings 23 in this Software without prior written authorization from The Open Group. 24 25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 26 27 All Rights Reserved 28 29 Permission to use, copy, modify, and distribute this software and its 30 documentation for any purpose and without fee is hereby granted, 31 provided that the above copyright notice appear in all copies and that 32 both that copyright notice and this permission notice appear in 33 supporting documentation, and that the name of Digital not be 34 used in advertising or publicity pertaining to distribution of the 35 software without specific, written prior permission. 36 37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 43 SOFTWARE. 44 45 ******************************************************************/ 46 47 #ifdef HAVE_DIX_CONFIG_H 48 #include <dix-config.h> 49 #endif 50 51 #include <X11/X.h> 52 #include <X11/Xproto.h> 53 #include "windowstr.h" 54 #include "propertyst.h" 55 #include "dixstruct.h" 56 #include "dispatch.h" 57 #include "swaprep.h" 58 #include "xace.h" 59 60 /***************************************************************** 61 * Property Stuff 62 * 63 * dixLookupProperty, dixChangeProperty, DeleteProperty 64 * 65 * Properties belong to windows. The list of properties should not be 66 * traversed directly. Instead, use the three functions listed above. 67 * 68 *****************************************************************/ 69 70 #ifdef notdef 71 static void 72 PrintPropertys(WindowPtr pWin) 73 { 74 PropertyPtr pProp; 75 int j; 76 77 pProp = pWin->userProps; 78 while (pProp) { 79 ErrorF("[dix] %x %x\n", pProp->propertyName, pProp->type); 80 ErrorF("[dix] property format: %d\n", pProp->format); 81 ErrorF("[dix] property data: \n"); 82 for (j = 0; j < (pProp->format / 8) * pProp->size; j++) 83 ErrorF("[dix] %c\n", pProp->data[j]); 84 pProp = pProp->next; 85 } 86 } 87 #endif 88 89 int 90 dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName, 91 ClientPtr client, Mask access_mode) 92 { 93 PropertyPtr pProp; 94 int rc = BadMatch; 95 96 client->errorValue = propertyName; 97 98 for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) 99 if (pProp->propertyName == propertyName) 100 break; 101 102 if (pProp) 103 rc = XaceHookPropertyAccess(client, pWin, &pProp, access_mode); 104 *result = pProp; 105 return rc; 106 } 107 108 CallbackListPtr PropertyStateCallback; 109 110 static void 111 deliverPropertyNotifyEvent(WindowPtr pWin, int state, PropertyPtr pProp) 112 { 113 xEvent event; 114 PropertyStateRec rec = { 115 .win = pWin, 116 .prop = pProp, 117 .state = state 118 }; 119 UpdateCurrentTimeIf(); 120 event = (xEvent) { 121 .u.property.window = pWin->drawable.id, 122 .u.property.state = state, 123 .u.property.atom = pProp->propertyName, 124 .u.property.time = currentTime.milliseconds, 125 }; 126 event.u.u.type = PropertyNotify; 127 128 CallCallbacks(&PropertyStateCallback, &rec); 129 DeliverEvents(pWin, &event, 1, (WindowPtr) NULL); 130 } 131 132 int 133 ProcRotateProperties(ClientPtr client) 134 { 135 int i, j, delta, rc; 136 137 REQUEST(xRotatePropertiesReq); 138 WindowPtr pWin; 139 Atom *atoms; 140 PropertyPtr *props; /* array of pointer */ 141 PropertyPtr pProp, saved; 142 143 REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2); 144 UpdateCurrentTime(); 145 rc = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); 146 if (rc != Success || stuff->nAtoms <= 0) 147 return rc; 148 149 atoms = (Atom *) &stuff[1]; 150 props = xallocarray(stuff->nAtoms, sizeof(PropertyPtr)); 151 saved = xallocarray(stuff->nAtoms, sizeof(PropertyRec)); 152 if (!props || !saved) { 153 rc = BadAlloc; 154 goto out; 155 } 156 157 for (i = 0; i < stuff->nAtoms; i++) { 158 if (!ValidAtom(atoms[i])) { 159 rc = BadAtom; 160 client->errorValue = atoms[i]; 161 goto out; 162 } 163 for (j = i + 1; j < stuff->nAtoms; j++) 164 if (atoms[j] == atoms[i]) { 165 rc = BadMatch; 166 goto out; 167 } 168 169 rc = dixLookupProperty(&pProp, pWin, atoms[i], client, 170 DixReadAccess | DixWriteAccess); 171 if (rc != Success) 172 goto out; 173 174 props[i] = pProp; 175 saved[i] = *pProp; 176 } 177 delta = stuff->nPositions; 178 179 /* If the rotation is a complete 360 degrees, then moving the properties 180 around and generating PropertyNotify events should be skipped. */ 181 182 if (abs(delta) % stuff->nAtoms) { 183 while (delta < 0) /* faster if abs value is small */ 184 delta += stuff->nAtoms; 185 for (i = 0; i < stuff->nAtoms; i++) { 186 j = (i + delta) % stuff->nAtoms; 187 deliverPropertyNotifyEvent(pWin, PropertyNewValue, props[i]); 188 189 /* Preserve name and devPrivates */ 190 props[j]->type = saved[i].type; 191 props[j]->format = saved[i].format; 192 props[j]->size = saved[i].size; 193 props[j]->data = saved[i].data; 194 } 195 } 196 out: 197 free(saved); 198 free(props); 199 return rc; 200 } 201 202 int 203 ProcChangeProperty(ClientPtr client) 204 { 205 WindowPtr pWin; 206 char format, mode; 207 unsigned long len; 208 int sizeInBytes, totalSize, err; 209 210 REQUEST(xChangePropertyReq); 211 212 REQUEST_AT_LEAST_SIZE(xChangePropertyReq); 213 UpdateCurrentTime(); 214 format = stuff->format; 215 mode = stuff->mode; 216 if ((mode != PropModeReplace) && (mode != PropModeAppend) && 217 (mode != PropModePrepend)) { 218 client->errorValue = mode; 219 return BadValue; 220 } 221 if ((format != 8) && (format != 16) && (format != 32)) { 222 client->errorValue = format; 223 return BadValue; 224 } 225 len = stuff->nUnits; 226 if (len > bytes_to_int32(0xffffffff - sizeof(xChangePropertyReq))) 227 return BadLength; 228 sizeInBytes = format >> 3; 229 totalSize = len * sizeInBytes; 230 REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize); 231 232 err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); 233 if (err != Success) 234 return err; 235 if (!ValidAtom(stuff->property)) { 236 client->errorValue = stuff->property; 237 return BadAtom; 238 } 239 if (!ValidAtom(stuff->type)) { 240 client->errorValue = stuff->type; 241 return BadAtom; 242 } 243 244 err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type, 245 (int) format, (int) mode, len, &stuff[1], 246 TRUE); 247 if (err != Success) 248 return err; 249 else 250 return Success; 251 } 252 253 int 254 dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property, 255 Atom type, int format, int mode, unsigned long len, 256 const void *value, Bool sendevent) 257 { 258 PropertyPtr pProp; 259 PropertyRec savedProp; 260 int sizeInBytes, totalSize, rc; 261 unsigned char *data; 262 Mask access_mode; 263 264 sizeInBytes = format >> 3; 265 totalSize = len * sizeInBytes; 266 access_mode = (mode == PropModeReplace) ? DixWriteAccess : DixBlendAccess; 267 268 /* first see if property already exists */ 269 rc = dixLookupProperty(&pProp, pWin, property, pClient, access_mode); 270 271 if (rc == BadMatch) { /* just add to list */ 272 if (!pWin->optional && !MakeWindowOptional(pWin)) 273 return BadAlloc; 274 pProp = dixAllocateObjectWithPrivates(PropertyRec, PRIVATE_PROPERTY); 275 if (!pProp) 276 return BadAlloc; 277 data = malloc(totalSize); 278 if (!data && len) { 279 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 280 return BadAlloc; 281 } 282 memcpy(data, value, totalSize); 283 pProp->propertyName = property; 284 pProp->type = type; 285 pProp->format = format; 286 pProp->data = data; 287 pProp->size = len; 288 rc = XaceHookPropertyAccess(pClient, pWin, &pProp, 289 DixCreateAccess | DixWriteAccess); 290 if (rc != Success) { 291 free(data); 292 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 293 pClient->errorValue = property; 294 return rc; 295 } 296 pProp->next = pWin->optional->userProps; 297 pWin->optional->userProps = pProp; 298 } 299 else if (rc == Success) { 300 /* To append or prepend to a property the request format and type 301 must match those of the already defined property. The 302 existing format and type are irrelevant when using the mode 303 "PropModeReplace" since they will be written over. */ 304 305 if ((format != pProp->format) && (mode != PropModeReplace)) 306 return BadMatch; 307 if ((pProp->type != type) && (mode != PropModeReplace)) 308 return BadMatch; 309 310 /* save the old values for later */ 311 savedProp = *pProp; 312 313 if (mode == PropModeReplace) { 314 data = malloc(totalSize); 315 if (!data && len) 316 return BadAlloc; 317 memcpy(data, value, totalSize); 318 pProp->data = data; 319 pProp->size = len; 320 pProp->type = type; 321 pProp->format = format; 322 } 323 else if (len == 0) { 324 /* do nothing */ 325 } 326 else if (mode == PropModeAppend) { 327 data = xallocarray(pProp->size + len, sizeInBytes); 328 if (!data) 329 return BadAlloc; 330 memcpy(data, pProp->data, pProp->size * sizeInBytes); 331 memcpy(data + pProp->size * sizeInBytes, value, totalSize); 332 pProp->data = data; 333 pProp->size += len; 334 } 335 else if (mode == PropModePrepend) { 336 data = xallocarray(len + pProp->size, sizeInBytes); 337 if (!data) 338 return BadAlloc; 339 memcpy(data + totalSize, pProp->data, pProp->size * sizeInBytes); 340 memcpy(data, value, totalSize); 341 pProp->data = data; 342 pProp->size += len; 343 } 344 345 /* Allow security modules to check the new content */ 346 access_mode |= DixPostAccess; 347 rc = XaceHookPropertyAccess(pClient, pWin, &pProp, access_mode); 348 if (rc == Success) { 349 if (savedProp.data != pProp->data) 350 free(savedProp.data); 351 } 352 else { 353 if (savedProp.data != pProp->data) 354 free(pProp->data); 355 *pProp = savedProp; 356 return rc; 357 } 358 } 359 else 360 return rc; 361 362 if (sendevent) 363 deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp); 364 365 return Success; 366 } 367 368 int 369 DeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName) 370 { 371 PropertyPtr pProp, prevProp; 372 int rc; 373 374 rc = dixLookupProperty(&pProp, pWin, propName, client, DixDestroyAccess); 375 if (rc == BadMatch) 376 return Success; /* Succeed if property does not exist */ 377 378 if (rc == Success) { 379 if (pWin->optional->userProps == pProp) { 380 /* Takes care of head */ 381 if (!(pWin->optional->userProps = pProp->next)) 382 CheckWindowOptionalNeed(pWin); 383 } 384 else { 385 /* Need to traverse to find the previous element */ 386 prevProp = pWin->optional->userProps; 387 while (prevProp->next != pProp) 388 prevProp = prevProp->next; 389 prevProp->next = pProp->next; 390 } 391 392 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp); 393 free(pProp->data); 394 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 395 } 396 return rc; 397 } 398 399 void 400 DeleteAllWindowProperties(WindowPtr pWin) 401 { 402 PropertyPtr pProp, pNextProp; 403 404 pProp = wUserProps(pWin); 405 while (pProp) { 406 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp); 407 pNextProp = pProp->next; 408 free(pProp->data); 409 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 410 pProp = pNextProp; 411 } 412 413 if (pWin->optional) 414 pWin->optional->userProps = NULL; 415 } 416 417 static int 418 NullPropertyReply(ClientPtr client, ATOM propertyType, int format) 419 { 420 xGetPropertyReply reply = { 421 .type = X_Reply, 422 .format = format, 423 .sequenceNumber = client->sequence, 424 .length = 0, 425 .propertyType = propertyType, 426 .bytesAfter = 0, 427 .nItems = 0 428 }; 429 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 430 return Success; 431 } 432 433 /***************** 434 * GetProperty 435 * If type Any is specified, returns the property from the specified 436 * window regardless of its type. If a type is specified, returns the 437 * property only if its type equals the specified type. 438 * If delete is True and a property is returned, the property is also 439 * deleted from the window and a PropertyNotify event is generated on the 440 * window. 441 *****************/ 442 443 int 444 ProcGetProperty(ClientPtr client) 445 { 446 PropertyPtr pProp, prevProp; 447 unsigned long n, len, ind; 448 int rc; 449 WindowPtr pWin; 450 xGetPropertyReply reply; 451 Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess; 452 453 REQUEST(xGetPropertyReq); 454 455 REQUEST_SIZE_MATCH(xGetPropertyReq); 456 if (stuff->delete) { 457 UpdateCurrentTime(); 458 win_mode |= DixSetPropAccess; 459 prop_mode |= DixDestroyAccess; 460 } 461 rc = dixLookupWindow(&pWin, stuff->window, client, win_mode); 462 if (rc != Success) 463 return rc; 464 465 if (!ValidAtom(stuff->property)) { 466 client->errorValue = stuff->property; 467 return BadAtom; 468 } 469 if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) { 470 client->errorValue = stuff->delete; 471 return BadValue; 472 } 473 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) { 474 client->errorValue = stuff->type; 475 return BadAtom; 476 } 477 478 rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode); 479 if (rc == BadMatch) 480 return NullPropertyReply(client, None, 0); 481 else if (rc != Success) 482 return rc; 483 484 /* If the request type and actual type don't match. Return the 485 property information, but not the data. */ 486 487 if (((stuff->type != pProp->type) && (stuff->type != AnyPropertyType)) 488 ) { 489 reply = (xGetPropertyReply) { 490 .type = X_Reply, 491 .sequenceNumber = client->sequence, 492 .bytesAfter = pProp->size, 493 .format = pProp->format, 494 .length = 0, 495 .nItems = 0, 496 .propertyType = pProp->type 497 }; 498 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 499 return Success; 500 } 501 502 /* 503 * Return type, format, value to client 504 */ 505 n = (pProp->format / 8) * pProp->size; /* size (bytes) of prop */ 506 ind = stuff->longOffset << 2; 507 508 /* If longOffset is invalid such that it causes "len" to 509 be negative, it's a value error. */ 510 511 if (n < ind) { 512 client->errorValue = stuff->longOffset; 513 return BadValue; 514 } 515 516 len = min(n - ind, 4 * stuff->longLength); 517 518 reply = (xGetPropertyReply) { 519 .type = X_Reply, 520 .sequenceNumber = client->sequence, 521 .bytesAfter = n - (ind + len), 522 .format = pProp->format, 523 .length = bytes_to_int32(len), 524 .nItems = len / (pProp->format / 8), 525 .propertyType = pProp->type 526 }; 527 528 if (stuff->delete && (reply.bytesAfter == 0)) 529 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp); 530 531 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 532 if (len) { 533 switch (reply.format) { 534 case 32: 535 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 536 break; 537 case 16: 538 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 539 break; 540 default: 541 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient; 542 break; 543 } 544 WriteSwappedDataToClient(client, len, (char *) pProp->data + ind); 545 } 546 547 if (stuff->delete && (reply.bytesAfter == 0)) { 548 /* Delete the Property */ 549 if (pWin->optional->userProps == pProp) { 550 /* Takes care of head */ 551 if (!(pWin->optional->userProps = pProp->next)) 552 CheckWindowOptionalNeed(pWin); 553 } 554 else { 555 /* Need to traverse to find the previous element */ 556 prevProp = pWin->optional->userProps; 557 while (prevProp->next != pProp) 558 prevProp = prevProp->next; 559 prevProp->next = pProp->next; 560 } 561 562 free(pProp->data); 563 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 564 } 565 return Success; 566 } 567 568 int 569 ProcListProperties(ClientPtr client) 570 { 571 Atom *pAtoms = NULL, *temppAtoms; 572 xListPropertiesReply xlpr; 573 int rc, numProps = 0; 574 WindowPtr pWin; 575 PropertyPtr pProp, realProp; 576 577 REQUEST(xResourceReq); 578 579 REQUEST_SIZE_MATCH(xResourceReq); 580 rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess); 581 if (rc != Success) 582 return rc; 583 584 for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) 585 numProps++; 586 587 if (numProps && !(pAtoms = xallocarray(numProps, sizeof(Atom)))) 588 return BadAlloc; 589 590 numProps = 0; 591 temppAtoms = pAtoms; 592 for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) { 593 realProp = pProp; 594 rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess); 595 if (rc == Success && realProp == pProp) { 596 *temppAtoms++ = pProp->propertyName; 597 numProps++; 598 } 599 } 600 601 xlpr = (xListPropertiesReply) { 602 .type = X_Reply, 603 .sequenceNumber = client->sequence, 604 .length = bytes_to_int32(numProps * sizeof(Atom)), 605 .nProperties = numProps 606 }; 607 WriteReplyToClient(client, sizeof(xGenericReply), &xlpr); 608 if (numProps) { 609 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; 610 WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); 611 } 612 free(pAtoms); 613 return Success; 614 } 615 616 int 617 ProcDeleteProperty(ClientPtr client) 618 { 619 WindowPtr pWin; 620 621 REQUEST(xDeletePropertyReq); 622 int result; 623 624 REQUEST_SIZE_MATCH(xDeletePropertyReq); 625 UpdateCurrentTime(); 626 result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); 627 if (result != Success) 628 return result; 629 if (!ValidAtom(stuff->property)) { 630 client->errorValue = stuff->property; 631 return BadAtom; 632 } 633 634 return DeleteProperty(client, pWin, stuff->property); 635 }