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