applewm.c revision 706f2543
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 73 74static unsigned char WMReqCode = 0; 75static int WMEventBase = 0; 76 77static RESTYPE ClientType, EventType; /* resource types for event masks */ 78static XID eventResource; 79 80/* Currently selected events */ 81static unsigned int eventMask = 0; 82 83static int WMFreeClient (pointer data, XID id); 84static int WMFreeEvents (pointer data, XID id); 85static void SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to); 86 87typedef struct _WMEvent *WMEventPtr; 88typedef struct _WMEvent { 89 WMEventPtr next; 90 ClientPtr client; 91 XID clientResource; 92 unsigned int mask; 93} WMEventRec; 94 95static inline BoxRec 96make_box (int x, int y, int w, int h) 97{ 98 BoxRec r; 99 r.x1 = x; 100 r.y1 = y; 101 r.x2 = x + w; 102 r.y2 = y + h; 103 return r; 104} 105 106/* Updates the _NATIVE_SCREEN_ORIGIN property on the given root window. */ 107void 108AppleWMSetScreenOrigin( 109 WindowPtr pWin 110) 111{ 112 int32_t data[2]; 113 114 data[0] = pWin->drawable.pScreen->x + darwinMainScreenX; 115 data[1] = pWin->drawable.pScreen->y + darwinMainScreenY; 116 117 dixChangeWindowProperty(serverClient, pWin, xa_native_screen_origin(), 118 XA_INTEGER, 32, PropModeReplace, 2, data, TRUE); 119} 120 121/* Window managers can set the _APPLE_NO_ORDER_IN property on windows 122 that are being genie-restored from the Dock. We want them to 123 be mapped but remain ordered-out until the animation 124 completes (when the Dock will order them in). */ 125Bool 126AppleWMDoReorderWindow( 127 WindowPtr pWin 128) 129{ 130 Atom atom; 131 PropertyPtr prop; 132 int rc; 133 134 atom = xa_apple_no_order_in(); 135 rc = dixLookupProperty(&prop, pWin, atom, serverClient, DixReadAccess); 136 137 if(Success == rc && prop->type == atom) 138 return 0; 139 140 return 1; 141} 142 143 144static int 145ProcAppleWMQueryVersion( 146 register ClientPtr client 147) 148{ 149 xAppleWMQueryVersionReply rep; 150 register int n; 151 152 REQUEST_SIZE_MATCH(xAppleWMQueryVersionReq); 153 rep.type = X_Reply; 154 rep.length = 0; 155 rep.sequenceNumber = client->sequence; 156 rep.majorVersion = SERVER_APPLEWM_MAJOR_VERSION; 157 rep.minorVersion = SERVER_APPLEWM_MINOR_VERSION; 158 rep.patchVersion = SERVER_APPLEWM_PATCH_VERSION; 159 if (client->swapped) { 160 swaps(&rep.sequenceNumber, n); 161 swapl(&rep.length, n); 162 } 163 WriteToClient(client, sizeof(xAppleWMQueryVersionReply), (char *)&rep); 164 return Success; 165} 166 167 168/* events */ 169 170static inline void 171updateEventMask (WMEventPtr *pHead) 172{ 173 WMEventPtr pCur; 174 175 eventMask = 0; 176 for (pCur = *pHead; pCur != NULL; pCur = pCur->next) 177 eventMask |= pCur->mask; 178} 179 180/*ARGSUSED*/ 181static int 182WMFreeClient (pointer data, XID id) { 183 WMEventPtr pEvent; 184 WMEventPtr *pHead, pCur, pPrev; 185 int i; 186 187 pEvent = (WMEventPtr) data; 188 i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, serverClient, DixReadAccess | 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((pointer) pEvent); 202 return 1; 203} 204 205/*ARGSUSED*/ 206static int 207WMFreeEvents (pointer data, XID id) { 208 WMEventPtr *pHead, pCur, pNext; 209 210 pHead = (WMEventPtr *) data; 211 for (pCur = *pHead; pCur; pCur = pNext) { 212 pNext = pCur->next; 213 FreeResource (pCur->clientResource, ClientType); 214 free((pointer) pCur); 215 } 216 free((pointer) pHead); 217 eventMask = 0; 218 return 1; 219} 220 221static int 222ProcAppleWMSelectInput (register ClientPtr client) 223{ 224 REQUEST(xAppleWMSelectInputReq); 225 WMEventPtr pEvent, pNewEvent, *pHead; 226 XID clientResource; 227 int i; 228 229 REQUEST_SIZE_MATCH (xAppleWMSelectInputReq); 230 i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, client, DixWriteAccess); 231 if (stuff->mask != 0) { 232 if (i == Success && pHead) { 233 /* check for existing entry. */ 234 for (pEvent = *pHead; pEvent; pEvent = pEvent->next) 235 { 236 if (pEvent->client == client) 237 { 238 pEvent->mask = stuff->mask; 239 updateEventMask (pHead); 240 return Success; 241 } 242 } 243 } 244 245 /* build the entry */ 246 pNewEvent = (WMEventPtr) malloc(sizeof (WMEventRec)); 247 if (!pNewEvent) 248 return BadAlloc; 249 pNewEvent->next = 0; 250 pNewEvent->client = client; 251 pNewEvent->mask = stuff->mask; 252 /* 253 * add a resource that will be deleted when 254 * the client goes away 255 */ 256 clientResource = FakeClientID (client->index); 257 pNewEvent->clientResource = clientResource; 258 if (!AddResource (clientResource, ClientType, (pointer)pNewEvent)) 259 return BadAlloc; 260 /* 261 * create a resource to contain a pointer to the list 262 * of clients selecting input. This must be indirect as 263 * the list may be arbitrarily rearranged which cannot be 264 * done through the resource database. 265 */ 266 if (i != Success || !pHead) 267 { 268 pHead = (WMEventPtr *) malloc(sizeof (WMEventPtr)); 269 if (!pHead || 270 !AddResource (eventResource, EventType, (pointer)pHead)) 271 { 272 FreeResource (clientResource, RT_NONE); 273 return BadAlloc; 274 } 275 *pHead = 0; 276 } 277 pNewEvent->next = *pHead; 278 *pHead = pNewEvent; 279 updateEventMask (pHead); 280 } else if (stuff->mask == 0) { 281 /* delete the interest */ 282 if (i == Success && pHead) { 283 pNewEvent = 0; 284 for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { 285 if (pEvent->client == client) 286 break; 287 pNewEvent = pEvent; 288 } 289 if (pEvent) { 290 FreeResource (pEvent->clientResource, ClientType); 291 if (pNewEvent) 292 pNewEvent->next = pEvent->next; 293 else 294 *pHead = pEvent->next; 295 free(pEvent); 296 updateEventMask (pHead); 297 } 298 } 299 } else { 300 client->errorValue = stuff->mask; 301 return BadValue; 302 } 303 return Success; 304} 305 306/* 307 * deliver the event 308 */ 309 310void 311AppleWMSendEvent (int type, unsigned int mask, int which, int arg) { 312 WMEventPtr *pHead, pEvent; 313 xAppleWMNotifyEvent se; 314 int i; 315 316 i = dixLookupResourceByType((pointer *)&pHead, eventResource, EventType, serverClient, DixReadAccess); 317 if (i != Success || !pHead) 318 return; 319 for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { 320 if ((pEvent->mask & mask) == 0) 321 continue; 322 se.type = type + WMEventBase; 323 se.kind = which; 324 se.arg = arg; 325 se.time = currentTime.milliseconds; 326 WriteEventsToClient (pEvent->client, 1, (xEvent *) &se); 327 } 328} 329 330/* Safe to call from any thread. */ 331unsigned int 332AppleWMSelectedEvents (void) 333{ 334 return eventMask; 335} 336 337 338/* general utility functions */ 339 340static int 341ProcAppleWMDisableUpdate( 342 register ClientPtr client 343) 344{ 345 REQUEST_SIZE_MATCH(xAppleWMDisableUpdateReq); 346 347 appleWMProcs->DisableUpdate(); 348 349 return Success; 350} 351 352static int 353ProcAppleWMReenableUpdate( 354 register ClientPtr client 355) 356{ 357 REQUEST_SIZE_MATCH(xAppleWMReenableUpdateReq); 358 359 appleWMProcs->EnableUpdate(); 360 361 return Success; 362} 363 364 365/* window functions */ 366 367static int 368ProcAppleWMSetWindowMenu( 369 register ClientPtr client 370) 371{ 372 const char *bytes, **items; 373 char *shortcuts; 374 int max_len, nitems, i, j; 375 REQUEST(xAppleWMSetWindowMenuReq); 376 377 REQUEST_AT_LEAST_SIZE(xAppleWMSetWindowMenuReq); 378 379 nitems = stuff->nitems; 380 items = malloc(sizeof (char *) * nitems); 381 shortcuts = malloc(sizeof (char) * nitems); 382 383 max_len = (stuff->length << 2) - sizeof(xAppleWMSetWindowMenuReq); 384 bytes = (char *) &stuff[1]; 385 386 for (i = j = 0; i < max_len && j < nitems;) 387 { 388 shortcuts[j] = bytes[i++]; 389 items[j++] = bytes + i; 390 391 while (i < max_len) 392 { 393 if (bytes[i++] == 0) 394 break; 395 } 396 } 397 X11ApplicationSetWindowMenu (nitems, items, shortcuts); 398 free(items); 399 free(shortcuts); 400 401 return Success; 402} 403 404static int 405ProcAppleWMSetWindowMenuCheck( 406 register ClientPtr client 407) 408{ 409 REQUEST(xAppleWMSetWindowMenuCheckReq); 410 411 REQUEST_SIZE_MATCH(xAppleWMSetWindowMenuCheckReq); 412 X11ApplicationSetWindowMenuCheck(stuff->index); 413 return Success; 414} 415 416static int 417ProcAppleWMSetFrontProcess( 418 register ClientPtr client 419) 420{ 421 REQUEST_SIZE_MATCH(xAppleWMSetFrontProcessReq); 422 423 X11ApplicationSetFrontProcess(); 424 return Success; 425} 426 427static int 428ProcAppleWMSetWindowLevel(register ClientPtr client) 429{ 430 REQUEST(xAppleWMSetWindowLevelReq); 431 WindowPtr pWin; 432 int err; 433 434 REQUEST_SIZE_MATCH(xAppleWMSetWindowLevelReq); 435 436 if (Success != dixLookupWindow(&pWin, stuff->window, client, 437 DixReadAccess)) 438 return BadValue; 439 440 if (stuff->level < 0 || stuff->level >= AppleWMNumWindowLevels) { 441 return BadValue; 442 } 443 444 err = appleWMProcs->SetWindowLevel(pWin, stuff->level); 445 if (err != Success) { 446 return err; 447 } 448 449 return Success; 450} 451 452static int 453ProcAppleWMSendPSN(register ClientPtr client) 454{ 455 REQUEST(xAppleWMSendPSNReq); 456 int err; 457 458 REQUEST_SIZE_MATCH(xAppleWMSendPSNReq); 459 460 if(!appleWMProcs->SendPSN) 461 return BadRequest; 462 463 err = appleWMProcs->SendPSN(stuff->psn_hi, stuff->psn_lo); 464 if (err != Success) { 465 return err; 466 } 467 468 return Success; 469} 470 471static int 472ProcAppleWMAttachTransient(register ClientPtr client) 473{ 474 WindowPtr pWinChild, pWinParent; 475 REQUEST(xAppleWMAttachTransientReq); 476 int err; 477 478 REQUEST_SIZE_MATCH(xAppleWMAttachTransientReq); 479 480 if(!appleWMProcs->AttachTransient) 481 return BadRequest; 482 483 if (Success != dixLookupWindow(&pWinChild, stuff->child, client, DixReadAccess)) 484 return BadValue; 485 486 if(stuff->parent) { 487 if(Success != dixLookupWindow(&pWinParent, stuff->parent, client, DixReadAccess)) 488 return BadValue; 489 } else { 490 pWinParent = NULL; 491 } 492 493 err = appleWMProcs->AttachTransient(pWinChild, pWinParent); 494 if (err != Success) { 495 return err; 496 } 497 498 return Success; 499} 500 501static int 502ProcAppleWMSetCanQuit( 503 register ClientPtr client 504) 505{ 506 REQUEST(xAppleWMSetCanQuitReq); 507 508 REQUEST_SIZE_MATCH(xAppleWMSetCanQuitReq); 509 510 X11ApplicationSetCanQuit(stuff->state); 511 return Success; 512} 513 514 515/* frame functions */ 516 517static int 518ProcAppleWMFrameGetRect( 519 register ClientPtr client 520) 521{ 522 xAppleWMFrameGetRectReply rep; 523 BoxRec ir, or, rr; 524 REQUEST(xAppleWMFrameGetRectReq); 525 526 REQUEST_SIZE_MATCH(xAppleWMFrameGetRectReq); 527 rep.type = X_Reply; 528 rep.length = 0; 529 rep.sequenceNumber = client->sequence; 530 531 ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); 532 or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); 533 534 if (appleWMProcs->FrameGetRect(stuff->frame_rect, 535 stuff->frame_class, 536 &or, &ir, &rr) != Success) 537 { 538 return BadValue; 539 } 540 541 rep.x = rr.x1; 542 rep.y = rr.y1; 543 rep.w = rr.x2 - rr.x1; 544 rep.h = rr.y2 - rr.y1; 545 546 WriteToClient(client, sizeof(xAppleWMFrameGetRectReply), (char *)&rep); 547 return Success; 548} 549 550static int 551ProcAppleWMFrameHitTest( 552 register ClientPtr client 553) 554{ 555 xAppleWMFrameHitTestReply rep; 556 BoxRec ir, or; 557 int ret; 558 REQUEST(xAppleWMFrameHitTestReq); 559 560 REQUEST_SIZE_MATCH(xAppleWMFrameHitTestReq); 561 rep.type = X_Reply; 562 rep.length = 0; 563 rep.sequenceNumber = client->sequence; 564 565 ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); 566 or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); 567 568 if (appleWMProcs->FrameHitTest(stuff->frame_class, stuff->px, 569 stuff->py, &or, &ir, &ret) != Success) 570 { 571 return BadValue; 572 } 573 574 rep.ret = ret; 575 576 WriteToClient(client, sizeof(xAppleWMFrameHitTestReply), (char *)&rep); 577 return Success; 578} 579 580static int 581ProcAppleWMFrameDraw( 582 register ClientPtr client 583) 584{ 585 BoxRec ir, or; 586 unsigned int title_length, title_max; 587 unsigned char *title_bytes; 588 REQUEST(xAppleWMFrameDrawReq); 589 WindowPtr pWin; 590 591 REQUEST_AT_LEAST_SIZE(xAppleWMFrameDrawReq); 592 593 if (Success != dixLookupWindow(&pWin, stuff->window, client, 594 DixReadAccess)) 595 return BadValue; 596 597 ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); 598 or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); 599 600 title_length = stuff->title_length; 601 title_max = (stuff->length << 2) - sizeof(xAppleWMFrameDrawReq); 602 603 if (title_max < title_length) 604 return BadValue; 605 606 title_bytes = (unsigned char *) &stuff[1]; 607 608 errno = appleWMProcs->FrameDraw(pWin, stuff->frame_class, 609 stuff->frame_attr, &or, &ir, 610 title_length, title_bytes); 611 if (errno != Success) { 612 return errno; 613 } 614 615 return Success; 616} 617 618 619/* dispatch */ 620 621static int 622ProcAppleWMDispatch ( 623 register ClientPtr client 624) 625{ 626 REQUEST(xReq); 627 628 switch (stuff->data) 629 { 630 case X_AppleWMQueryVersion: 631 return ProcAppleWMQueryVersion(client); 632 } 633 634 if (!LocalClient(client)) 635 return WMErrorBase + AppleWMClientNotLocal; 636 637 switch (stuff->data) 638 { 639 case X_AppleWMSelectInput: 640 return ProcAppleWMSelectInput(client); 641 case X_AppleWMDisableUpdate: 642 return ProcAppleWMDisableUpdate(client); 643 case X_AppleWMReenableUpdate: 644 return ProcAppleWMReenableUpdate(client); 645 case X_AppleWMSetWindowMenu: 646 return ProcAppleWMSetWindowMenu(client); 647 case X_AppleWMSetWindowMenuCheck: 648 return ProcAppleWMSetWindowMenuCheck(client); 649 case X_AppleWMSetFrontProcess: 650 return ProcAppleWMSetFrontProcess(client); 651 case X_AppleWMSetWindowLevel: 652 return ProcAppleWMSetWindowLevel(client); 653 case X_AppleWMSetCanQuit: 654 return ProcAppleWMSetCanQuit(client); 655 case X_AppleWMFrameGetRect: 656 return ProcAppleWMFrameGetRect(client); 657 case X_AppleWMFrameHitTest: 658 return ProcAppleWMFrameHitTest(client); 659 case X_AppleWMFrameDraw: 660 return ProcAppleWMFrameDraw(client); 661 case X_AppleWMSendPSN: 662 return ProcAppleWMSendPSN(client); 663 case X_AppleWMAttachTransient: 664 return ProcAppleWMAttachTransient(client); 665 default: 666 return BadRequest; 667 } 668} 669 670static void 671SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to) { 672 to->type = from->type; 673 to->kind = from->kind; 674 cpswaps (from->sequenceNumber, to->sequenceNumber); 675 cpswapl (from->time, to->time); 676 cpswapl (from->arg, to->arg); 677} 678 679static int 680SProcAppleWMQueryVersion( 681 register ClientPtr client 682) 683{ 684 register int n; 685 REQUEST(xAppleWMQueryVersionReq); 686 swaps(&stuff->length, n); 687 return ProcAppleWMQueryVersion(client); 688} 689 690static int 691SProcAppleWMDispatch ( 692 register ClientPtr client 693) 694{ 695 REQUEST(xReq); 696 697 /* It is bound to be non-local when there is byte swapping */ 698 if (!LocalClient(client)) 699 return WMErrorBase + AppleWMClientNotLocal; 700 701 /* only local clients are allowed WM access */ 702 switch (stuff->data) 703 { 704 case X_AppleWMQueryVersion: 705 return SProcAppleWMQueryVersion(client); 706 default: 707 return BadRequest; 708 } 709} 710 711void 712AppleWMExtensionInit( 713 AppleWMProcsPtr procsPtr) 714{ 715 ExtensionEntry* extEntry; 716 717 ClientType = CreateNewResourceType(WMFreeClient, "WMClient"); 718 EventType = CreateNewResourceType(WMFreeEvents, "WMEvent"); 719 eventResource = FakeClientID(0); 720 721 if (ClientType && EventType && 722 (extEntry = AddExtension(APPLEWMNAME, 723 AppleWMNumberEvents, 724 AppleWMNumberErrors, 725 ProcAppleWMDispatch, 726 SProcAppleWMDispatch, 727 NULL, 728 StandardMinorOpcode))) 729 { 730 size_t i; 731 WMReqCode = (unsigned char)extEntry->base; 732 WMErrorBase = extEntry->errorBase; 733 WMEventBase = extEntry->eventBase; 734 for (i=0; i < AppleWMNumberEvents; i++) 735 EventSwapVector[WMEventBase + i] = (EventSwapPtr) SNotifyEvent; 736 appleWMProcs = procsPtr; 737 } 738} 739