property.c revision 05b261ec
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#define NEED_REPLIES 54#define NEED_EVENTS 55#include <X11/Xproto.h> 56#include "windowstr.h" 57#include "propertyst.h" 58#include "dixstruct.h" 59#include "dispatch.h" 60#include "swaprep.h" 61#include "xace.h" 62 63/***************************************************************** 64 * Property Stuff 65 * 66 * ChangeProperty, DeleteProperty, GetProperties, 67 * ListProperties 68 * 69 * Properties below to windows. A allocate slots each time 70 * a property is added. No fancy searching done. 71 * 72 *****************************************************************/ 73 74#ifdef notdef 75static void 76PrintPropertys(WindowPtr pWin) 77{ 78 PropertyPtr pProp; 79 int j; 80 81 pProp = pWin->userProps; 82 while (pProp) 83 { 84 ErrorF( "%x %x\n", pProp->propertyName, pProp->type); 85 ErrorF("property format: %d\n", pProp->format); 86 ErrorF("property data: \n"); 87 for (j=0; j<(pProp->format/8)*pProp->size; j++) 88 ErrorF("%c\n", pProp->data[j]); 89 pProp = pProp->next; 90 } 91} 92#endif 93 94static void 95deliverPropertyNotifyEvent(WindowPtr pWin, int state, Atom atom) 96{ 97 xEvent event; 98 99 event.u.u.type = PropertyNotify; 100 event.u.property.window = pWin->drawable.id; 101 event.u.property.state = state; 102 event.u.property.atom = atom; 103 event.u.property.time = currentTime.milliseconds; 104 DeliverEvents(pWin, &event, 1, (WindowPtr)NULL); 105} 106 107int 108ProcRotateProperties(ClientPtr client) 109{ 110 int i, j, delta, rc; 111 REQUEST(xRotatePropertiesReq); 112 WindowPtr pWin; 113 Atom * atoms; 114 PropertyPtr * props; /* array of pointer */ 115 PropertyPtr pProp; 116 117 REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2); 118 UpdateCurrentTime(); 119 rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess); 120 if (rc != Success) 121 return rc; 122 if (!stuff->nAtoms) 123 return(Success); 124 atoms = (Atom *) & stuff[1]; 125 props = (PropertyPtr *)ALLOCATE_LOCAL(stuff->nAtoms * sizeof(PropertyPtr)); 126 if (!props) 127 return(BadAlloc); 128 for (i = 0; i < stuff->nAtoms; i++) 129 { 130 char action = XaceHook(XACE_PROPERTY_ACCESS, client, pWin, atoms[i], 131 DixReadAccess|DixWriteAccess); 132 133 if (!ValidAtom(atoms[i]) || (XaceErrorOperation == action)) { 134 DEALLOCATE_LOCAL(props); 135 client->errorValue = atoms[i]; 136 return BadAtom; 137 } 138 if (XaceIgnoreOperation == action) { 139 DEALLOCATE_LOCAL(props); 140 return Success; 141 } 142 143 for (j = i + 1; j < stuff->nAtoms; j++) 144 if (atoms[j] == atoms[i]) 145 { 146 DEALLOCATE_LOCAL(props); 147 return BadMatch; 148 } 149 pProp = wUserProps (pWin); 150 while (pProp) 151 { 152 if (pProp->propertyName == atoms[i]) 153 goto found; 154 pProp = pProp->next; 155 } 156 DEALLOCATE_LOCAL(props); 157 return BadMatch; 158found: 159 props[i] = pProp; 160 } 161 delta = stuff->nPositions; 162 163 /* If the rotation is a complete 360 degrees, then moving the properties 164 around and generating PropertyNotify events should be skipped. */ 165 166 if ( (stuff->nAtoms != 0) && (abs(delta) % stuff->nAtoms) != 0 ) 167 { 168 while (delta < 0) /* faster if abs value is small */ 169 delta += stuff->nAtoms; 170 for (i = 0; i < stuff->nAtoms; i++) 171 { 172 deliverPropertyNotifyEvent(pWin, PropertyNewValue, 173 props[i]->propertyName); 174 175 props[i]->propertyName = atoms[(i + delta) % stuff->nAtoms]; 176 } 177 } 178 DEALLOCATE_LOCAL(props); 179 return Success; 180} 181 182int 183ProcChangeProperty(ClientPtr client) 184{ 185 WindowPtr pWin; 186 char format, mode; 187 unsigned long len; 188 int sizeInBytes, totalSize, err; 189 REQUEST(xChangePropertyReq); 190 191 REQUEST_AT_LEAST_SIZE(xChangePropertyReq); 192 UpdateCurrentTime(); 193 format = stuff->format; 194 mode = stuff->mode; 195 if ((mode != PropModeReplace) && (mode != PropModeAppend) && 196 (mode != PropModePrepend)) 197 { 198 client->errorValue = mode; 199 return BadValue; 200 } 201 if ((format != 8) && (format != 16) && (format != 32)) 202 { 203 client->errorValue = format; 204 return BadValue; 205 } 206 len = stuff->nUnits; 207 if (len > ((0xffffffff - sizeof(xChangePropertyReq)) >> 2)) 208 return BadLength; 209 sizeInBytes = format>>3; 210 totalSize = len * sizeInBytes; 211 REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize); 212 213 err = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess); 214 if (err != Success) 215 return err; 216 if (!ValidAtom(stuff->property)) 217 { 218 client->errorValue = stuff->property; 219 return(BadAtom); 220 } 221 if (!ValidAtom(stuff->type)) 222 { 223 client->errorValue = stuff->type; 224 return(BadAtom); 225 } 226 227 switch (XaceHook(XACE_PROPERTY_ACCESS, client, pWin, stuff->property, 228 DixWriteAccess)) 229 { 230 case XaceErrorOperation: 231 client->errorValue = stuff->property; 232 return BadAtom; 233 case XaceIgnoreOperation: 234 return Success; 235 } 236 237 err = ChangeWindowProperty(pWin, stuff->property, stuff->type, (int)format, 238 (int)mode, len, (pointer)&stuff[1], TRUE); 239 if (err != Success) 240 return err; 241 else 242 return client->noClientException; 243} 244 245_X_EXPORT int 246ChangeWindowProperty(WindowPtr pWin, Atom property, Atom type, int format, 247 int mode, unsigned long len, pointer value, 248 Bool sendevent) 249{ 250 PropertyPtr pProp; 251 int sizeInBytes; 252 int totalSize; 253 pointer data; 254 255 sizeInBytes = format>>3; 256 totalSize = len * sizeInBytes; 257 258 /* first see if property already exists */ 259 260 pProp = wUserProps (pWin); 261 while (pProp) 262 { 263 if (pProp->propertyName == property) 264 break; 265 pProp = pProp->next; 266 } 267 if (!pProp) /* just add to list */ 268 { 269 if (!pWin->optional && !MakeWindowOptional (pWin)) 270 return(BadAlloc); 271 pProp = (PropertyPtr)xalloc(sizeof(PropertyRec)); 272 if (!pProp) 273 return(BadAlloc); 274 data = (pointer)xalloc(totalSize); 275 if (!data && len) 276 { 277 xfree(pProp); 278 return(BadAlloc); 279 } 280 pProp->propertyName = property; 281 pProp->type = type; 282 pProp->format = format; 283 pProp->data = data; 284 if (len) 285 memmove((char *)data, (char *)value, totalSize); 286 pProp->size = len; 287 pProp->next = pWin->optional->userProps; 288 pWin->optional->userProps = pProp; 289 } 290 else 291 { 292 /* To append or prepend to a property the request format and type 293 must match those of the already defined property. The 294 existing format and type are irrelevant when using the mode 295 "PropModeReplace" since they will be written over. */ 296 297 if ((format != pProp->format) && (mode != PropModeReplace)) 298 return(BadMatch); 299 if ((pProp->type != type) && (mode != PropModeReplace)) 300 return(BadMatch); 301 if (mode == PropModeReplace) 302 { 303 if (totalSize != pProp->size * (pProp->format >> 3)) 304 { 305 data = (pointer)xrealloc(pProp->data, totalSize); 306 if (!data && len) 307 return(BadAlloc); 308 pProp->data = data; 309 } 310 if (len) 311 memmove((char *)pProp->data, (char *)value, totalSize); 312 pProp->size = len; 313 pProp->type = type; 314 pProp->format = format; 315 } 316 else if (len == 0) 317 { 318 /* do nothing */ 319 } 320 else if (mode == PropModeAppend) 321 { 322 data = (pointer)xrealloc(pProp->data, 323 sizeInBytes * (len + pProp->size)); 324 if (!data) 325 return(BadAlloc); 326 pProp->data = data; 327 memmove(&((char *)data)[pProp->size * sizeInBytes], 328 (char *)value, 329 totalSize); 330 pProp->size += len; 331 } 332 else if (mode == PropModePrepend) 333 { 334 data = (pointer)xalloc(sizeInBytes * (len + pProp->size)); 335 if (!data) 336 return(BadAlloc); 337 memmove(&((char *)data)[totalSize], (char *)pProp->data, 338 (int)(pProp->size * sizeInBytes)); 339 memmove((char *)data, (char *)value, totalSize); 340 xfree(pProp->data); 341 pProp->data = data; 342 pProp->size += len; 343 } 344 } 345 346 if (sendevent) 347 deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp->propertyName); 348 349 return(Success); 350} 351 352int 353DeleteProperty(WindowPtr pWin, Atom propName) 354{ 355 PropertyPtr pProp, prevProp; 356 357 if (!(pProp = wUserProps (pWin))) 358 return(Success); 359 prevProp = (PropertyPtr)NULL; 360 while (pProp) 361 { 362 if (pProp->propertyName == propName) 363 break; 364 prevProp = pProp; 365 pProp = pProp->next; 366 } 367 if (pProp) 368 { 369 if (prevProp == (PropertyPtr)NULL) /* takes care of head */ 370 { 371 if (!(pWin->optional->userProps = pProp->next)) 372 CheckWindowOptionalNeed (pWin); 373 } 374 else 375 { 376 prevProp->next = pProp->next; 377 } 378 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName); 379 xfree(pProp->data); 380 xfree(pProp); 381 } 382 return(Success); 383} 384 385void 386DeleteAllWindowProperties(WindowPtr pWin) 387{ 388 PropertyPtr pProp, pNextProp; 389 390 pProp = wUserProps (pWin); 391 while (pProp) 392 { 393 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName); 394 pNextProp = pProp->next; 395 xfree(pProp->data); 396 xfree(pProp); 397 pProp = pNextProp; 398 } 399} 400 401static int 402NullPropertyReply( 403 ClientPtr client, 404 ATOM propertyType, 405 int format, 406 xGetPropertyReply *reply) 407{ 408 reply->nItems = 0; 409 reply->length = 0; 410 reply->bytesAfter = 0; 411 reply->propertyType = propertyType; 412 reply->format = format; 413 WriteReplyToClient(client, sizeof(xGenericReply), reply); 414 return(client->noClientException); 415} 416 417/***************** 418 * GetProperty 419 * If type Any is specified, returns the property from the specified 420 * window regardless of its type. If a type is specified, returns the 421 * property only if its type equals the specified type. 422 * If delete is True and a property is returned, the property is also 423 * deleted from the window and a PropertyNotify event is generated on the 424 * window. 425 *****************/ 426 427int 428ProcGetProperty(ClientPtr client) 429{ 430 PropertyPtr pProp, prevProp; 431 unsigned long n, len, ind, rc; 432 WindowPtr pWin; 433 xGetPropertyReply reply; 434 Mask access_mode = DixReadAccess; 435 REQUEST(xGetPropertyReq); 436 437 REQUEST_SIZE_MATCH(xGetPropertyReq); 438 if (stuff->delete) 439 UpdateCurrentTime(); 440 rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); 441 if (rc != Success) 442 return rc; 443 444 if (!ValidAtom(stuff->property)) 445 { 446 client->errorValue = stuff->property; 447 return(BadAtom); 448 } 449 if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) 450 { 451 client->errorValue = stuff->delete; 452 return(BadValue); 453 } 454 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) 455 { 456 client->errorValue = stuff->type; 457 return(BadAtom); 458 } 459 460 pProp = wUserProps (pWin); 461 prevProp = (PropertyPtr)NULL; 462 while (pProp) 463 { 464 if (pProp->propertyName == stuff->property) 465 break; 466 prevProp = pProp; 467 pProp = pProp->next; 468 } 469 470 reply.type = X_Reply; 471 reply.sequenceNumber = client->sequence; 472 if (!pProp) 473 return NullPropertyReply(client, None, 0, &reply); 474 475 if (stuff->delete) 476 access_mode |= DixDestroyAccess; 477 switch (XaceHook(XACE_PROPERTY_ACCESS, client, pWin, stuff->property, 478 access_mode)) 479 { 480 case XaceErrorOperation: 481 client->errorValue = stuff->property; 482 return BadAtom;; 483 case XaceIgnoreOperation: 484 return NullPropertyReply(client, pProp->type, pProp->format, &reply); 485 } 486 487 /* If the request type and actual type don't match. Return the 488 property information, but not the data. */ 489 490 if (((stuff->type != pProp->type) && 491 (stuff->type != AnyPropertyType)) 492 ) 493 { 494 reply.bytesAfter = pProp->size; 495 reply.format = pProp->format; 496 reply.length = 0; 497 reply.nItems = 0; 498 reply.propertyType = pProp->type; 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 { 514 client->errorValue = stuff->longOffset; 515 return BadValue; 516 } 517 518 len = min(n - ind, 4 * stuff->longLength); 519 520 reply.bytesAfter = n - (ind + len); 521 reply.format = pProp->format; 522 reply.length = (len + 3) >> 2; 523 reply.nItems = len / (pProp->format / 8 ); 524 reply.propertyType = pProp->type; 525 526 if (stuff->delete && (reply.bytesAfter == 0)) 527 deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName); 528 529 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 530 if (len) 531 { 532 switch (reply.format) { 533 case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break; 534 case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break; 535 default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break; 536 } 537 WriteSwappedDataToClient(client, len, 538 (char *)pProp->data + ind); 539 } 540 541 if (stuff->delete && (reply.bytesAfter == 0)) 542 { /* delete the Property */ 543 if (prevProp == (PropertyPtr)NULL) /* takes care of head */ 544 { 545 if (!(pWin->optional->userProps = pProp->next)) 546 CheckWindowOptionalNeed (pWin); 547 } 548 else 549 prevProp->next = pProp->next; 550 xfree(pProp->data); 551 xfree(pProp); 552 } 553 return(client->noClientException); 554} 555 556int 557ProcListProperties(ClientPtr client) 558{ 559 Atom *pAtoms = NULL, *temppAtoms; 560 xListPropertiesReply xlpr; 561 int rc, numProps = 0; 562 WindowPtr pWin; 563 PropertyPtr pProp; 564 REQUEST(xResourceReq); 565 566 REQUEST_SIZE_MATCH(xResourceReq); 567 rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess); 568 if (rc != Success) 569 return rc; 570 571 pProp = wUserProps (pWin); 572 while (pProp) 573 { 574 pProp = pProp->next; 575 numProps++; 576 } 577 if (numProps) 578 if(!(pAtoms = (Atom *)ALLOCATE_LOCAL(numProps * sizeof(Atom)))) 579 return(BadAlloc); 580 581 xlpr.type = X_Reply; 582 xlpr.nProperties = numProps; 583 xlpr.length = (numProps * sizeof(Atom)) >> 2; 584 xlpr.sequenceNumber = client->sequence; 585 pProp = wUserProps (pWin); 586 temppAtoms = pAtoms; 587 while (pProp) 588 { 589 *temppAtoms++ = pProp->propertyName; 590 pProp = pProp->next; 591 } 592 WriteReplyToClient(client, sizeof(xGenericReply), &xlpr); 593 if (numProps) 594 { 595 client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; 596 WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); 597 DEALLOCATE_LOCAL(pAtoms); 598 } 599 return(client->noClientException); 600} 601 602int 603ProcDeleteProperty(ClientPtr client) 604{ 605 WindowPtr pWin; 606 REQUEST(xDeletePropertyReq); 607 int result; 608 609 REQUEST_SIZE_MATCH(xDeletePropertyReq); 610 UpdateCurrentTime(); 611 result = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess); 612 if (result != Success) 613 return result; 614 if (!ValidAtom(stuff->property)) 615 { 616 client->errorValue = stuff->property; 617 return (BadAtom); 618 } 619 620 switch (XaceHook(XACE_PROPERTY_ACCESS, client, pWin, stuff->property, 621 DixDestroyAccess)) 622 { 623 case XaceErrorOperation: 624 client->errorValue = stuff->property; 625 return BadAtom;; 626 case XaceIgnoreOperation: 627 return Success; 628 } 629 630 result = DeleteProperty(pWin, stuff->property); 631 if (client->noClientException != Success) 632 return(client->noClientException); 633 else 634 return(result); 635} 636