property.c revision ed6184df
1/*********************************************************** 2 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 26 27 All Rights Reserved 28 29Permission to use, copy, modify, and distribute this software and its 30documentation for any purpose and without fee is hereby granted, 31provided that the above copyright notice appear in all copies and that 32both that copyright notice and this permission notice appear in 33supporting documentation, and that the name of Digital not be 34used in advertising or publicity pertaining to distribution of the 35software without specific, written prior permission. 36 37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 43SOFTWARE. 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 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, 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 253int 254dixChangeWindowProperty(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 368int 369DeleteProperty(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 399void 400DeleteAllWindowProperties(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 417static int 418NullPropertyReply(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 443int 444ProcGetProperty(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 568int 569ProcListProperties(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 616int 617ProcDeleteProperty(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} 636