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