applewm.c revision c8548ba8
1/* 2 * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. 3 * Copyright (c) 2002-2012 Apple Inc. All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person 6 * obtaining a copy of this software and associated documentation files 7 * (the "Software"), to deal in the Software without restriction, 8 * including without limitation the rights to use, copy, modify, merge, 9 * publish, distribute, sublicense, and/or sell copies of the Software, 10 * and to permit persons to whom the Software is furnished to do so, 11 * subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT 20 * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Except as contained in this notice, the name(s) of the above 26 * copyright holders shall not be used in advertising or otherwise to 27 * promote the sale, use or other dealings in this Software without 28 * prior written authorization. 29 */ 30 31#include "sanitizedCarbon.h" 32 33#ifdef HAVE_DIX_CONFIG_H 34#include <dix-config.h> 35#endif 36 37#include "quartz.h" 38 39#include "misc.h" 40#include "dixstruct.h" 41#include "globals.h" 42#include "extnsionst.h" 43#include "colormapst.h" 44#include "cursorstr.h" 45#include "scrnintstr.h" 46#include "windowstr.h" 47#include "servermd.h" 48#include "swaprep.h" 49#include "propertyst.h" 50#include <X11/Xatom.h> 51#include "darwin.h" 52#define _APPLEWM_SERVER_ 53#include <X11/extensions/applewmproto.h> 54#include "applewmExt.h" 55#include "X11Application.h" 56#include "protocol-versions.h" 57 58#define DEFINE_ATOM_HELPER(func, atom_name) \ 59 static Atom func(void) { \ 60 static int generation; \ 61 static Atom atom; \ 62 if (generation != serverGeneration) { \ 63 generation = serverGeneration; \ 64 atom = MakeAtom(atom_name, strlen(atom_name), TRUE); \ 65 } \ 66 return atom; \ 67 } 68 69DEFINE_ATOM_HELPER(xa_native_screen_origin, "_NATIVE_SCREEN_ORIGIN") 70DEFINE_ATOM_HELPER(xa_apple_no_order_in, "_APPLE_NO_ORDER_IN") 71 72static AppleWMProcsPtr appleWMProcs; 73 74static int WMErrorBase; 75 76static unsigned char WMReqCode = 0; 77static int WMEventBase = 0; 78 79static RESTYPE ClientType, EventType; /* resource types for event masks */ 80static XID eventResource; 81 82/* Currently selected events */ 83static unsigned int eventMask = 0; 84 85static int 86WMFreeClient(void *data, XID id); 87static int 88WMFreeEvents(void *data, XID id); 89static void 90SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to); 91 92typedef struct _WMEvent *WMEventPtr; 93typedef struct _WMEvent { 94 WMEventPtr next; 95 ClientPtr client; 96 XID clientResource; 97 unsigned int mask; 98} WMEventRec; 99 100static inline BoxRec 101make_box(int x, int y, int w, int h) 102{ 103 BoxRec r; 104 r.x1 = x; 105 r.y1 = y; 106 r.x2 = x + w; 107 r.y2 = y + h; 108 return r; 109} 110 111/* Updates the _NATIVE_SCREEN_ORIGIN property on the given root window. */ 112void 113AppleWMSetScreenOrigin(WindowPtr pWin) 114{ 115 int32_t data[2]; 116 117 data[0] = pWin->drawable.pScreen->x + darwinMainScreenX; 118 data[1] = pWin->drawable.pScreen->y + darwinMainScreenY; 119 120 dixChangeWindowProperty(serverClient, pWin, xa_native_screen_origin(), 121 XA_INTEGER, 32, PropModeReplace, 2, data, TRUE); 122} 123 124/* Window managers can set the _APPLE_NO_ORDER_IN property on windows 125 that are being genie-restored from the Dock. We want them to 126 be mapped but remain ordered-out until the animation 127 completes (when the Dock will order them in). */ 128Bool 129AppleWMDoReorderWindow(WindowPtr pWin) 130{ 131 Atom atom; 132 PropertyPtr prop; 133 int rc; 134 135 atom = xa_apple_no_order_in(); 136 rc = dixLookupProperty(&prop, pWin, atom, serverClient, DixReadAccess); 137 138 if (Success == rc && prop->type == atom) 139 return 0; 140 141 return 1; 142} 143 144static int 145ProcAppleWMQueryVersion(register ClientPtr client) 146{ 147 xAppleWMQueryVersionReply rep; 148 149 REQUEST_SIZE_MATCH(xAppleWMQueryVersionReq); 150 rep.type = X_Reply; 151 rep.length = 0; 152 rep.sequenceNumber = client->sequence; 153 rep.majorVersion = SERVER_APPLEWM_MAJOR_VERSION; 154 rep.minorVersion = SERVER_APPLEWM_MINOR_VERSION; 155 rep.patchVersion = SERVER_APPLEWM_PATCH_VERSION; 156 if (client->swapped) { 157 swaps(&rep.sequenceNumber); 158 swapl(&rep.length); 159 } 160 WriteToClient(client, sizeof(xAppleWMQueryVersionReply),&rep); 161 return Success; 162} 163 164/* events */ 165 166static inline void 167updateEventMask(WMEventPtr *pHead) 168{ 169 WMEventPtr pCur; 170 171 eventMask = 0; 172 for (pCur = *pHead; pCur != NULL; pCur = pCur->next) 173 eventMask |= pCur->mask; 174} 175 176/*ARGSUSED*/ 177static int 178WMFreeClient(void *data, XID id) 179{ 180 WMEventPtr pEvent; 181 WMEventPtr *pHead, pCur, pPrev; 182 int i; 183 184 pEvent = (WMEventPtr)data; 185 i = dixLookupResourceByType( 186 (void **)&pHead, eventResource, EventType, serverClient, 187 DixReadAccess | 188 DixWriteAccess | DixDestroyAccess); 189 if (i == Success && pHead) { 190 pPrev = 0; 191 for (pCur = *pHead; pCur && pCur != pEvent; pCur = pCur->next) 192 pPrev = pCur; 193 if (pCur) { 194 if (pPrev) 195 pPrev->next = pEvent->next; 196 else 197 *pHead = pEvent->next; 198 } 199 updateEventMask(pHead); 200 } 201 free((void *)pEvent); 202 return 1; 203} 204 205/*ARGSUSED*/ 206static int 207WMFreeEvents(void *data, XID id) 208{ 209 WMEventPtr *pHead, pCur, pNext; 210 211 pHead = (WMEventPtr *)data; 212 for (pCur = *pHead; pCur; pCur = pNext) { 213 pNext = pCur->next; 214 FreeResource(pCur->clientResource, ClientType); 215 free((void *)pCur); 216 } 217 free((void *)pHead); 218 eventMask = 0; 219 return 1; 220} 221 222static int 223ProcAppleWMSelectInput(register ClientPtr client) 224{ 225 REQUEST(xAppleWMSelectInputReq); 226 WMEventPtr pEvent, pNewEvent, *pHead; 227 XID clientResource; 228 int i; 229 230 REQUEST_SIZE_MATCH(xAppleWMSelectInputReq); 231 i = 232 dixLookupResourceByType((void **)&pHead, eventResource, EventType, 233 client, 234 DixWriteAccess); 235 if (stuff->mask != 0) { 236 if (i == Success && pHead) { 237 /* check for existing entry. */ 238 for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { 239 if (pEvent->client == client) { 240 pEvent->mask = stuff->mask; 241 updateEventMask(pHead); 242 return Success; 243 } 244 } 245 } 246 247 /* build the entry */ 248 pNewEvent = (WMEventPtr)malloc(sizeof(WMEventRec)); 249 if (!pNewEvent) 250 return BadAlloc; 251 pNewEvent->next = 0; 252 pNewEvent->client = client; 253 pNewEvent->mask = stuff->mask; 254 /* 255 * add a resource that will be deleted when 256 * the client goes away 257 */ 258 clientResource = FakeClientID(client->index); 259 pNewEvent->clientResource = clientResource; 260 if (!AddResource(clientResource, ClientType, (void *)pNewEvent)) 261 return BadAlloc; 262 /* 263 * create a resource to contain a pointer to the list 264 * of clients selecting input. This must be indirect as 265 * the list may be arbitrarily rearranged which cannot be 266 * done through the resource database. 267 */ 268 if (i != Success || !pHead) { 269 pHead = (WMEventPtr *)malloc(sizeof(WMEventPtr)); 270 if (!pHead || 271 !AddResource(eventResource, EventType, (void *)pHead)) { 272 FreeResource(clientResource, RT_NONE); 273 return BadAlloc; 274 } 275 *pHead = 0; 276 } 277 pNewEvent->next = *pHead; 278 *pHead = pNewEvent; 279 updateEventMask(pHead); 280 } 281 else if (stuff->mask == 0) { 282 /* delete the interest */ 283 if (i == Success && pHead) { 284 pNewEvent = 0; 285 for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { 286 if (pEvent->client == client) 287 break; 288 pNewEvent = pEvent; 289 } 290 if (pEvent) { 291 FreeResource(pEvent->clientResource, ClientType); 292 if (pNewEvent) 293 pNewEvent->next = pEvent->next; 294 else 295 *pHead = pEvent->next; 296 free(pEvent); 297 updateEventMask(pHead); 298 } 299 } 300 } 301 else { 302 client->errorValue = stuff->mask; 303 return BadValue; 304 } 305 return Success; 306} 307 308/* 309 * deliver the event 310 */ 311 312void 313AppleWMSendEvent(int type, unsigned int mask, int which, int arg) 314{ 315 WMEventPtr *pHead, pEvent; 316 xAppleWMNotifyEvent se; 317 int i; 318 319 i = 320 dixLookupResourceByType((void **)&pHead, eventResource, EventType, 321 serverClient, 322 DixReadAccess); 323 if (i != Success || !pHead) 324 return; 325 for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { 326 if ((pEvent->mask & mask) == 0) 327 continue; 328 se.type = type + WMEventBase; 329 se.kind = which; 330 se.arg = arg; 331 se.time = currentTime.milliseconds; 332 WriteEventsToClient(pEvent->client, 1, (xEvent *)&se); 333 } 334} 335 336/* Safe to call from any thread. */ 337unsigned int 338AppleWMSelectedEvents(void) 339{ 340 return eventMask; 341} 342 343/* general utility functions */ 344 345static int 346ProcAppleWMDisableUpdate(register ClientPtr client) 347{ 348 REQUEST_SIZE_MATCH(xAppleWMDisableUpdateReq); 349 350 appleWMProcs->DisableUpdate(); 351 352 return Success; 353} 354 355static int 356ProcAppleWMReenableUpdate(register ClientPtr client) 357{ 358 REQUEST_SIZE_MATCH(xAppleWMReenableUpdateReq); 359 360 appleWMProcs->EnableUpdate(); 361 362 return Success; 363} 364 365/* window functions */ 366 367static int 368ProcAppleWMSetWindowMenu(register ClientPtr client) 369{ 370 const char *bytes, **items; 371 char *shortcuts; 372 int max_len, nitems, i, j; 373 REQUEST(xAppleWMSetWindowMenuReq); 374 375 REQUEST_AT_LEAST_SIZE(xAppleWMSetWindowMenuReq); 376 377 nitems = stuff->nitems; 378 items = malloc(sizeof(char *) * nitems); 379 shortcuts = malloc(sizeof(char) * nitems); 380 381 if (!items || !shortcuts) { 382 free(items); 383 free(shortcuts); 384 385 return BadAlloc; 386 } 387 388 max_len = (stuff->length << 2) - sizeof(xAppleWMSetWindowMenuReq); 389 bytes = (char *)&stuff[1]; 390 391 for (i = j = 0; i < max_len && j < nitems;) { 392 shortcuts[j] = bytes[i++]; 393 items[j++] = bytes + i; 394 395 while (i < max_len) 396 { 397 if (bytes[i++] == 0) 398 break; 399 } 400 } 401 402 /* Check if we bailed out of the above loop due to a request that was too long */ 403 if (j < nitems) { 404 free(items); 405 free(shortcuts); 406 407 return BadRequest; 408 } 409 410 X11ApplicationSetWindowMenu(nitems, items, shortcuts); 411 free(items); 412 free(shortcuts); 413 414 return Success; 415} 416 417static int 418ProcAppleWMSetWindowMenuCheck(register ClientPtr client) 419{ 420 REQUEST(xAppleWMSetWindowMenuCheckReq); 421 422 REQUEST_SIZE_MATCH(xAppleWMSetWindowMenuCheckReq); 423 X11ApplicationSetWindowMenuCheck(stuff->index); 424 return Success; 425} 426 427static int 428ProcAppleWMSetFrontProcess(register ClientPtr client) 429{ 430 REQUEST_SIZE_MATCH(xAppleWMSetFrontProcessReq); 431 432 X11ApplicationSetFrontProcess(); 433 return Success; 434} 435 436static int 437ProcAppleWMSetWindowLevel(register ClientPtr client) 438{ 439 REQUEST(xAppleWMSetWindowLevelReq); 440 WindowPtr pWin; 441 int err; 442 443 REQUEST_SIZE_MATCH(xAppleWMSetWindowLevelReq); 444 445 if (Success != dixLookupWindow(&pWin, stuff->window, client, 446 DixReadAccess)) 447 return BadValue; 448 449 if (stuff->level >= AppleWMNumWindowLevels) { 450 return BadValue; 451 } 452 453 err = appleWMProcs->SetWindowLevel(pWin, stuff->level); 454 if (err != Success) { 455 return err; 456 } 457 458 return Success; 459} 460 461static int 462ProcAppleWMSendPSN(register ClientPtr client) 463{ 464 REQUEST(xAppleWMSendPSNReq); 465 int err; 466 467 REQUEST_SIZE_MATCH(xAppleWMSendPSNReq); 468 469 if (!appleWMProcs->SendPSN) 470 return BadRequest; 471 472 err = appleWMProcs->SendPSN(stuff->psn_hi, stuff->psn_lo); 473 if (err != Success) { 474 return err; 475 } 476 477 return Success; 478} 479 480static int 481ProcAppleWMAttachTransient(register ClientPtr client) 482{ 483 WindowPtr pWinChild, pWinParent; 484 REQUEST(xAppleWMAttachTransientReq); 485 int err; 486 487 REQUEST_SIZE_MATCH(xAppleWMAttachTransientReq); 488 489 if (!appleWMProcs->AttachTransient) 490 return BadRequest; 491 492 if (Success != 493 dixLookupWindow(&pWinChild, stuff->child, client, DixReadAccess)) 494 return BadValue; 495 496 if (stuff->parent) { 497 if (Success != 498 dixLookupWindow(&pWinParent, stuff->parent, client, DixReadAccess)) 499 return BadValue; 500 } 501 else { 502 pWinParent = NULL; 503 } 504 505 err = appleWMProcs->AttachTransient(pWinChild, pWinParent); 506 if (err != Success) { 507 return err; 508 } 509 510 return Success; 511} 512 513static int 514ProcAppleWMSetCanQuit(register ClientPtr client) 515{ 516 REQUEST(xAppleWMSetCanQuitReq); 517 518 REQUEST_SIZE_MATCH(xAppleWMSetCanQuitReq); 519 520 X11ApplicationSetCanQuit(stuff->state); 521 return Success; 522} 523 524/* frame functions */ 525 526static int 527ProcAppleWMFrameGetRect(register ClientPtr client) 528{ 529 xAppleWMFrameGetRectReply rep; 530 BoxRec ir, or, rr; 531 REQUEST(xAppleWMFrameGetRectReq); 532 533 REQUEST_SIZE_MATCH(xAppleWMFrameGetRectReq); 534 rep.type = X_Reply; 535 rep.length = 0; 536 rep.sequenceNumber = client->sequence; 537 538 ir = make_box(stuff->ix, stuff->iy, stuff->iw, stuff->ih); 539 or = make_box(stuff->ox, stuff->oy, stuff->ow, stuff->oh); 540 541 if (appleWMProcs->FrameGetRect(stuff->frame_rect, 542 stuff->frame_class, 543 &or, &ir, &rr) != Success) { 544 return BadValue; 545 } 546 547 rep.x = rr.x1; 548 rep.y = rr.y1; 549 rep.w = rr.x2 - rr.x1; 550 rep.h = rr.y2 - rr.y1; 551 552 WriteToClient(client, sizeof(xAppleWMFrameGetRectReply),&rep); 553 return Success; 554} 555 556static int 557ProcAppleWMFrameHitTest(register ClientPtr client) 558{ 559 xAppleWMFrameHitTestReply rep; 560 BoxRec ir, or; 561 int ret; 562 REQUEST(xAppleWMFrameHitTestReq); 563 564 REQUEST_SIZE_MATCH(xAppleWMFrameHitTestReq); 565 rep.type = X_Reply; 566 rep.length = 0; 567 rep.sequenceNumber = client->sequence; 568 569 ir = make_box(stuff->ix, stuff->iy, stuff->iw, stuff->ih); 570 or = make_box(stuff->ox, stuff->oy, stuff->ow, stuff->oh); 571 572 if (appleWMProcs->FrameHitTest(stuff->frame_class, stuff->px, 573 stuff->py, &or, &ir, &ret) != Success) { 574 return BadValue; 575 } 576 577 rep.ret = ret; 578 579 WriteToClient(client, sizeof(xAppleWMFrameHitTestReply),&rep); 580 return Success; 581} 582 583static int 584ProcAppleWMFrameDraw(register ClientPtr client) 585{ 586 BoxRec ir, or; 587 unsigned int title_length, title_max; 588 unsigned char *title_bytes; 589 REQUEST(xAppleWMFrameDrawReq); 590 WindowPtr pWin; 591 592 REQUEST_AT_LEAST_SIZE(xAppleWMFrameDrawReq); 593 594 if (Success != dixLookupWindow(&pWin, stuff->window, client, 595 DixReadAccess)) 596 return BadValue; 597 598 ir = make_box(stuff->ix, stuff->iy, stuff->iw, stuff->ih); 599 or = make_box(stuff->ox, stuff->oy, stuff->ow, stuff->oh); 600 601 title_length = stuff->title_length; 602 title_max = (stuff->length << 2) - sizeof(xAppleWMFrameDrawReq); 603 604 if (title_max < title_length) 605 return BadValue; 606 607 title_bytes = (unsigned char *)&stuff[1]; 608 609 errno = appleWMProcs->FrameDraw(pWin, stuff->frame_class, 610 stuff->frame_attr, &or, &ir, 611 title_length, title_bytes); 612 if (errno != Success) { 613 return errno; 614 } 615 616 return Success; 617} 618 619/* dispatch */ 620 621static int 622ProcAppleWMDispatch(register ClientPtr client) 623{ 624 REQUEST(xReq); 625 626 switch (stuff->data) { 627 case X_AppleWMQueryVersion: 628 return ProcAppleWMQueryVersion(client); 629 } 630 631 if (!client->local) 632 return WMErrorBase + AppleWMClientNotLocal; 633 634 switch (stuff->data) { 635 case X_AppleWMSelectInput: 636 return ProcAppleWMSelectInput(client); 637 638 case X_AppleWMDisableUpdate: 639 return ProcAppleWMDisableUpdate(client); 640 641 case X_AppleWMReenableUpdate: 642 return ProcAppleWMReenableUpdate(client); 643 644 case X_AppleWMSetWindowMenu: 645 return ProcAppleWMSetWindowMenu(client); 646 647 case X_AppleWMSetWindowMenuCheck: 648 return ProcAppleWMSetWindowMenuCheck(client); 649 650 case X_AppleWMSetFrontProcess: 651 return ProcAppleWMSetFrontProcess(client); 652 653 case X_AppleWMSetWindowLevel: 654 return ProcAppleWMSetWindowLevel(client); 655 656 case X_AppleWMSetCanQuit: 657 return ProcAppleWMSetCanQuit(client); 658 659 case X_AppleWMFrameGetRect: 660 return ProcAppleWMFrameGetRect(client); 661 662 case X_AppleWMFrameHitTest: 663 return ProcAppleWMFrameHitTest(client); 664 665 case X_AppleWMFrameDraw: 666 return ProcAppleWMFrameDraw(client); 667 668 case X_AppleWMSendPSN: 669 return ProcAppleWMSendPSN(client); 670 671 case X_AppleWMAttachTransient: 672 return ProcAppleWMAttachTransient(client); 673 674 default: 675 return BadRequest; 676 } 677} 678 679static void 680SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to) 681{ 682 to->type = from->type; 683 to->kind = from->kind; 684 cpswaps(from->sequenceNumber, to->sequenceNumber); 685 cpswapl(from->time, to->time); 686 cpswapl(from->arg, to->arg); 687} 688 689static int 690SProcAppleWMQueryVersion(register ClientPtr client) 691{ 692 REQUEST(xAppleWMQueryVersionReq); 693 swaps(&stuff->length); 694 return ProcAppleWMQueryVersion(client); 695} 696 697static int 698SProcAppleWMDispatch(register ClientPtr client) 699{ 700 REQUEST(xReq); 701 702 /* It is bound to be non-local when there is byte swapping */ 703 if (!client->local) 704 return WMErrorBase + AppleWMClientNotLocal; 705 706 /* only local clients are allowed WM access */ 707 switch (stuff->data) { 708 case X_AppleWMQueryVersion: 709 return SProcAppleWMQueryVersion(client); 710 711 default: 712 return BadRequest; 713 } 714} 715 716void 717AppleWMExtensionInit(AppleWMProcsPtr procsPtr) 718{ 719 ExtensionEntry* extEntry; 720 721 ClientType = CreateNewResourceType(WMFreeClient, "WMClient"); 722 EventType = CreateNewResourceType(WMFreeEvents, "WMEvent"); 723 eventResource = FakeClientID(0); 724 725 if (ClientType && EventType && 726 (extEntry = AddExtension(APPLEWMNAME, 727 AppleWMNumberEvents, 728 AppleWMNumberErrors, 729 ProcAppleWMDispatch, 730 SProcAppleWMDispatch, 731 NULL, 732 StandardMinorOpcode))) { 733 size_t i; 734 WMReqCode = (unsigned char)extEntry->base; 735 WMErrorBase = extEntry->errorBase; 736 WMEventBase = extEntry->eventBase; 737 for (i = 0; i < AppleWMNumberEvents; i++) 738 EventSwapVector[WMEventBase + i] = (EventSwapPtr)SNotifyEvent; 739 appleWMProcs = procsPtr; 740 } 741} 742