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