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