property.c revision c82838c1
11.62Smrg/*********************************************************** 21.48Scgd 31.21SmycroftCopyright 1987, 1998 The Open Group 41.1Scgd 51.1ScgdPermission to use, copy, modify, distribute, and sell this software and its 61.56Sjtcdocumentation for any purpose is hereby granted without fee, provided that 71.58Scgdthe above copyright notice appear in all copies and that both that 81.58Scgdcopyright notice and this permission notice appear in supporting 91.56Sjtcdocumentation. 101.60Sjtc 111.60SjtcThe above copyright notice and this permission notice shall be included in 121.60Sjtcall copies or substantial portions of the Software. 131.60Sjtc 141.58ScgdTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 151.58ScgdIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 161.58ScgdFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 171.58ScgdOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 181.1ScgdAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 191.26ScgdCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 201.1Scgd 211.1ScgdExcept as contained in this notice, the name of The Open Group shall not be 221.1Scgdused in advertising or otherwise to promote the sale, use or other dealings 231.62Smrgin this Software without prior written authorization from The Open Group. 241.1Scgd 251.57SjtcCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 261.1Scgd 271.1Scgd All Rights Reserved 281.1Scgd 291.34ScgdPermission to use, copy, modify, and distribute this software and its 301.1Scgddocumentation for any purpose and without fee is hereby granted, 311.1Scgdprovided that the above copyright notice appear in all copies and that 321.1Scgdboth that copyright notice and this permission notice appear in 331.51Sjtcsupporting documentation, and that the name of Digital not be 341.50Sjtcused in advertising or publicity pertaining to distribution of the 351.1Scgdsoftware without specific, written prior permission. 361.1Scgd 371.34ScgdDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 381.1ScgdALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 391.1ScgdDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 401.34ScgdANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 411.34ScgdWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 421.45ScgdARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 431.45ScgdSOFTWARE. 441.45Scgd 451.57Sjtc******************************************************************/ 461.14Sproven 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 71static void 72PrintPropertys(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 89int 90dixLookupProperty(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 108CallbackListPtr PropertyStateCallback; 109 110static void 111deliverPropertyNotifyEvent(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 132int 133ProcRotateProperties(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 202int 203ProcChangeProperty(ClientPtr client) 204{ 205 WindowPtr pWin; 206 char format, mode; 207 unsigned long len; 208 int sizeInBytes, err; 209 uint64_t totalSize; 210 211 REQUEST(xChangePropertyReq); 212 213 REQUEST_AT_LEAST_SIZE(xChangePropertyReq); 214 UpdateCurrentTime(); 215 format = stuff->format; 216 mode = stuff->mode; 217 if ((mode != PropModeReplace) && (mode != PropModeAppend) && 218 (mode != PropModePrepend)) { 219 client->errorValue = mode; 220 return BadValue; 221 } 222 if ((format != 8) && (format != 16) && (format != 32)) { 223 client->errorValue = format; 224 return BadValue; 225 } 226 len = stuff->nUnits; 227 if (len > bytes_to_int32(0xffffffff - sizeof(xChangePropertyReq))) 228 return BadLength; 229 sizeInBytes = format >> 3; 230 totalSize = len * sizeInBytes; 231 REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize); 232 233 err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); 234 if (err != Success) 235 return err; 236 if (!ValidAtom(stuff->property)) { 237 client->errorValue = stuff->property; 238 return BadAtom; 239 } 240 if (!ValidAtom(stuff->type)) { 241 client->errorValue = stuff->type; 242 return BadAtom; 243 } 244 245 err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type, 246 (int) format, (int) mode, len, &stuff[1], 247 TRUE); 248 if (err != Success) 249 return err; 250 else 251 return Success; 252} 253 254int 255dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property, 256 Atom type, int format, int mode, unsigned long len, 257 const void *value, Bool sendevent) 258{ 259 PropertyPtr pProp; 260 PropertyRec savedProp; 261 int sizeInBytes, totalSize, rc; 262 unsigned char *data; 263 Mask access_mode; 264 265 sizeInBytes = format >> 3; 266 totalSize = len * sizeInBytes; 267 access_mode = (mode == PropModeReplace) ? DixWriteAccess : DixBlendAccess; 268 269 /* first see if property already exists */ 270 rc = dixLookupProperty(&pProp, pWin, property, pClient, access_mode); 271 272 if (rc == BadMatch) { /* just add to list */ 273 if (!pWin->optional && !MakeWindowOptional(pWin)) 274 return BadAlloc; 275 pProp = dixAllocateObjectWithPrivates(PropertyRec, PRIVATE_PROPERTY); 276 if (!pProp) 277 return BadAlloc; 278 data = malloc(totalSize); 279 if (!data && len) { 280 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 281 return BadAlloc; 282 } 283 memcpy(data, value, totalSize); 284 pProp->propertyName = property; 285 pProp->type = type; 286 pProp->format = format; 287 pProp->data = data; 288 pProp->size = len; 289 rc = XaceHookPropertyAccess(pClient, pWin, &pProp, 290 DixCreateAccess | DixWriteAccess); 291 if (rc != Success) { 292 free(data); 293 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 294 pClient->errorValue = property; 295 return rc; 296 } 297 pProp->next = pWin->optional->userProps; 298 pWin->optional->userProps = pProp; 299 } 300 else if (rc == Success) { 301 /* To append or prepend to a property the request format and type 302 must match those of the already defined property. The 303 existing format and type are irrelevant when using the mode 304 "PropModeReplace" since they will be written over. */ 305 306 if ((format != pProp->format) && (mode != PropModeReplace)) 307 return BadMatch; 308 if ((pProp->type != type) && (mode != PropModeReplace)) 309 return BadMatch; 310 311 /* save the old values for later */ 312 savedProp = *pProp; 313 314 if (mode == PropModeReplace) { 315 data = malloc(totalSize); 316 if (!data && len) 317 return BadAlloc; 318 memcpy(data, value, totalSize); 319 pProp->data = data; 320 pProp->size = len; 321 pProp->type = type; 322 pProp->format = format; 323 } 324 else if (len == 0) { 325 /* do nothing */ 326 } 327 else if (mode == PropModeAppend) { 328 data = xallocarray(pProp->size + len, sizeInBytes); 329 if (!data) 330 return BadAlloc; 331 memcpy(data, pProp->data, pProp->size * sizeInBytes); 332 memcpy(data + pProp->size * sizeInBytes, value, totalSize); 333 pProp->data = data; 334 pProp->size += len; 335 } 336 else if (mode == PropModePrepend) { 337 data = xallocarray(len + pProp->size, sizeInBytes); 338 if (!data) 339 return BadAlloc; 340 memcpy(data + totalSize, pProp->data, pProp->size * sizeInBytes); 341 memcpy(data, value, totalSize); 342 pProp->data = data; 343 pProp->size += len; 344 } 345 346 /* Allow security modules to check the new content */ 347 access_mode |= DixPostAccess; 348 rc = XaceHookPropertyAccess(pClient, pWin, &pProp, access_mode); 349 if (rc == Success) { 350 if (savedProp.data != pProp->data) 351 free(savedProp.data); 352 } 353 else { 354 if (savedProp.data != pProp->data) 355 free(pProp->data); 356 *pProp = savedProp; 357 return rc; 358 } 359 } 360 else 361 return rc; 362 363 if (sendevent) 364 deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp); 365 366 return Success; 367} 368 369int 370DeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName) 371{ 372 PropertyPtr pProp, prevProp; 373 int rc; 374 375 rc = dixLookupProperty(&pProp, pWin, propName, client, DixDestroyAccess); 376 if (rc == BadMatch) 377 return Success; /* Succeed if property does not exist */ 378 379 if (rc == Success) { 380 if (pWin->optional->userProps == pProp) { 381 /* Takes care of head */ 382 if (!(pWin->optional->userProps = pProp->next)) 383 CheckWindowOptionalNeed(pWin); 384 } 385 else { 386 /* Need to traverse to find the previous element */ 387 prevProp = pWin->optional->userProps; 388 while (prevProp->next != pProp) 389 prevProp = prevProp->next; 390 prevProp->next = pProp->next; 391 } 392 393 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp); 394 free(pProp->data); 395 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 396 } 397 return rc; 398} 399 400void 401DeleteAllWindowProperties(WindowPtr pWin) 402{ 403 PropertyPtr pProp, pNextProp; 404 405 pProp = wUserProps(pWin); 406 while (pProp) { 407 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp); 408 pNextProp = pProp->next; 409 free(pProp->data); 410 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 411 pProp = pNextProp; 412 } 413 414 if (pWin->optional) 415 pWin->optional->userProps = NULL; 416} 417 418static int 419NullPropertyReply(ClientPtr client, ATOM propertyType, int format) 420{ 421 xGetPropertyReply reply = { 422 .type = X_Reply, 423 .format = format, 424 .sequenceNumber = client->sequence, 425 .length = 0, 426 .propertyType = propertyType, 427 .bytesAfter = 0, 428 .nItems = 0 429 }; 430 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 431 return Success; 432} 433 434/***************** 435 * GetProperty 436 * If type Any is specified, returns the property from the specified 437 * window regardless of its type. If a type is specified, returns the 438 * property only if its type equals the specified type. 439 * If delete is True and a property is returned, the property is also 440 * deleted from the window and a PropertyNotify event is generated on the 441 * window. 442 *****************/ 443 444int 445ProcGetProperty(ClientPtr client) 446{ 447 PropertyPtr pProp, prevProp; 448 unsigned long n, len, ind; 449 int rc; 450 WindowPtr pWin; 451 xGetPropertyReply reply; 452 Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess; 453 454 REQUEST(xGetPropertyReq); 455 456 REQUEST_SIZE_MATCH(xGetPropertyReq); 457 if (stuff->delete) { 458 UpdateCurrentTime(); 459 win_mode |= DixSetPropAccess; 460 prop_mode |= DixDestroyAccess; 461 } 462 rc = dixLookupWindow(&pWin, stuff->window, client, win_mode); 463 if (rc != Success) 464 return rc; 465 466 if (!ValidAtom(stuff->property)) { 467 client->errorValue = stuff->property; 468 return BadAtom; 469 } 470 if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) { 471 client->errorValue = stuff->delete; 472 return BadValue; 473 } 474 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) { 475 client->errorValue = stuff->type; 476 return BadAtom; 477 } 478 479 rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode); 480 if (rc == BadMatch) 481 return NullPropertyReply(client, None, 0); 482 else if (rc != Success) 483 return rc; 484 485 /* If the request type and actual type don't match. Return the 486 property information, but not the data. */ 487 488 if (((stuff->type != pProp->type) && (stuff->type != AnyPropertyType)) 489 ) { 490 reply = (xGetPropertyReply) { 491 .type = X_Reply, 492 .sequenceNumber = client->sequence, 493 .bytesAfter = pProp->size, 494 .format = pProp->format, 495 .length = 0, 496 .nItems = 0, 497 .propertyType = pProp->type 498 }; 499 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 500 return Success; 501 } 502 503/* 504 * Return type, format, value to client 505 */ 506 n = (pProp->format / 8) * pProp->size; /* size (bytes) of prop */ 507 ind = stuff->longOffset << 2; 508 509 /* If longOffset is invalid such that it causes "len" to 510 be negative, it's a value error. */ 511 512 if (n < ind) { 513 client->errorValue = stuff->longOffset; 514 return BadValue; 515 } 516 517 len = min(n - ind, 4 * stuff->longLength); 518 519 reply = (xGetPropertyReply) { 520 .type = X_Reply, 521 .sequenceNumber = client->sequence, 522 .bytesAfter = n - (ind + len), 523 .format = pProp->format, 524 .length = bytes_to_int32(len), 525 .nItems = len / (pProp->format / 8), 526 .propertyType = pProp->type 527 }; 528 529 if (stuff->delete && (reply.bytesAfter == 0)) 530 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp); 531 532 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 533 if (len) { 534 switch (reply.format) { 535 case 32: 536 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 537 break; 538 case 16: 539 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 540 break; 541 default: 542 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient; 543 break; 544 } 545 WriteSwappedDataToClient(client, len, (char *) pProp->data + ind); 546 } 547 548 if (stuff->delete && (reply.bytesAfter == 0)) { 549 /* Delete the Property */ 550 if (pWin->optional->userProps == pProp) { 551 /* Takes care of head */ 552 if (!(pWin->optional->userProps = pProp->next)) 553 CheckWindowOptionalNeed(pWin); 554 } 555 else { 556 /* Need to traverse to find the previous element */ 557 prevProp = pWin->optional->userProps; 558 while (prevProp->next != pProp) 559 prevProp = prevProp->next; 560 prevProp->next = pProp->next; 561 } 562 563 free(pProp->data); 564 dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY); 565 } 566 return Success; 567} 568 569int 570ProcListProperties(ClientPtr client) 571{ 572 Atom *pAtoms = NULL, *temppAtoms; 573 xListPropertiesReply xlpr; 574 int rc, numProps = 0; 575 WindowPtr pWin; 576 PropertyPtr pProp, realProp; 577 578 REQUEST(xResourceReq); 579 580 REQUEST_SIZE_MATCH(xResourceReq); 581 rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess); 582 if (rc != Success) 583 return rc; 584 585 for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) 586 numProps++; 587 588 if (numProps && !(pAtoms = xallocarray(numProps, sizeof(Atom)))) 589 return BadAlloc; 590 591 numProps = 0; 592 temppAtoms = pAtoms; 593 for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) { 594 realProp = pProp; 595 rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess); 596 if (rc == Success && realProp == pProp) { 597 *temppAtoms++ = pProp->propertyName; 598 numProps++; 599 } 600 } 601 602 xlpr = (xListPropertiesReply) { 603 .type = X_Reply, 604 .sequenceNumber = client->sequence, 605 .length = bytes_to_int32(numProps * sizeof(Atom)), 606 .nProperties = numProps 607 }; 608 WriteReplyToClient(client, sizeof(xGenericReply), &xlpr); 609 if (numProps) { 610 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; 611 WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); 612 } 613 free(pAtoms); 614 return Success; 615} 616 617int 618ProcDeleteProperty(ClientPtr client) 619{ 620 WindowPtr pWin; 621 622 REQUEST(xDeletePropertyReq); 623 int result; 624 625 REQUEST_SIZE_MATCH(xDeletePropertyReq); 626 UpdateCurrentTime(); 627 result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); 628 if (result != Success) 629 return result; 630 if (!ValidAtom(stuff->property)) { 631 client->errorValue = stuff->property; 632 return BadAtom; 633 } 634 635 return DeleteProperty(client, pWin, stuff->property); 636} 637