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