1/* 2 * Xplugin rootless implementation frame functions 3 * 4 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. 5 * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, 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 copyright 26 * holders shall not be used in advertising or otherwise to promote the sale, 27 * use or other dealings in this Software without prior written authorization. 28 */ 29 30#ifdef HAVE_DIX_CONFIG_H 31#include <dix-config.h> 32#endif 33 34#include "xpr.h" 35#include "rootlessCommon.h" 36#include <Xplugin.h> 37#include "x-hash.h" 38#include "x-list.h" 39#include "applewmExt.h" 40 41#include "propertyst.h" 42#include "dix.h" 43#include <X11/Xatom.h> 44#include "windowstr.h" 45#include "quartz.h" 46 47#include "threadSafety.h" 48 49#include <pthread.h> 50 51#define DEFINE_ATOM_HELPER(func,atom_name) \ 52static Atom func (void) { \ 53 static int generation; \ 54 static Atom atom; \ 55 if (generation != serverGeneration) { \ 56 generation = serverGeneration; \ 57 atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ 58 } \ 59 return atom; \ 60} 61 62DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID") 63 64/* Maps xp_window_id -> RootlessWindowRec */ 65static x_hash_table *window_hash; 66static pthread_mutex_t window_hash_mutex; 67 68/* Prototypes for static functions */ 69static Bool xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, 70 int newX, int newY, RegionPtr pShape); 71static void xprDestroyFrame(RootlessFrameID wid); 72static void xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY); 73static void xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, 74 int newX, int newY, unsigned int newW, unsigned int newH, 75 unsigned int gravity); 76static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid); 77static void xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape); 78static void xprUnmapFrame(RootlessFrameID wid); 79static void xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow); 80static void xprStopDrawing(RootlessFrameID wid, Bool flush); 81static void xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage); 82static void xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects, 83 int shift_x, int shift_y); 84static void xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin); 85static Bool xprDoReorderWindow(RootlessWindowPtr pFrame); 86static void xprHideWindow(RootlessFrameID wid); 87static void xprUpdateColormap(RootlessFrameID wid, ScreenPtr pScreen); 88static void xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, 89 int dx, int dy); 90 91 92static inline xp_error 93xprConfigureWindow(xp_window_id id, unsigned int mask, 94 const xp_window_changes *values) 95{ 96 TA_SERVER(); 97 98 return xp_configure_window(id, mask, values); 99} 100 101 102static void 103xprSetNativeProperty(RootlessWindowPtr pFrame) 104{ 105 xp_error err; 106 unsigned int native_id; 107 long data; 108 109 TA_SERVER(); 110 111 err = xp_get_native_window(x_cvt_vptr_to_uint(pFrame->wid), &native_id); 112 if (err == Success) 113 { 114 /* FIXME: move this to AppleWM extension */ 115 116 data = native_id; 117 dixChangeWindowProperty(serverClient, pFrame->win, xa_native_window_id(), 118 XA_INTEGER, 32, PropModeReplace, 1, &data, TRUE); 119 } 120} 121 122static xp_error 123xprColormapCallback(void *data, int first_color, int n_colors, uint32_t *colors) 124{ 125 return (RootlessResolveColormap (data, first_color, n_colors, colors) ? XP_Success : XP_BadMatch); 126} 127 128/* 129 * Create and display a new frame. 130 */ 131static Bool 132xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, 133 int newX, int newY, RegionPtr pShape) 134{ 135 WindowPtr pWin = pFrame->win; 136 xp_window_changes wc; 137 unsigned int mask = 0; 138 xp_error err; 139 140 TA_SERVER(); 141 142 wc.x = newX; 143 wc.y = newY; 144 wc.width = pFrame->width; 145 wc.height = pFrame->height; 146 wc.bit_gravity = XP_GRAVITY_NONE; 147 mask |= XP_BOUNDS; 148 149 if (pWin->drawable.depth == 8) 150 { 151 wc.depth = XP_DEPTH_INDEX8; 152 wc.colormap = xprColormapCallback; 153 wc.colormap_data = pScreen; 154 mask |= XP_COLORMAP; 155 } 156 else if (pWin->drawable.depth == 15) 157 wc.depth = XP_DEPTH_RGB555; 158 else if (pWin->drawable.depth == 24) 159 wc.depth = XP_DEPTH_ARGB8888; 160 else 161 wc.depth = XP_DEPTH_NIL; 162 mask |= XP_DEPTH; 163 164 if (pShape != NULL) 165 { 166 wc.shape_nrects = RegionNumRects(pShape); 167 wc.shape_rects = RegionRects(pShape); 168 wc.shape_tx = wc.shape_ty = 0; 169 mask |= XP_SHAPE; 170 } 171 172 pFrame->level = !IsRoot (pWin) ? AppleWMWindowLevelNormal : AppleWMNumWindowLevels; 173 174 if(XQuartzIsRootless) 175 wc.window_level = normal_window_levels[pFrame->level]; 176 else if(XQuartzShieldingWindowLevel) 177 wc.window_level = XQuartzShieldingWindowLevel + 1; 178 else 179 wc.window_level = rooted_window_levels[pFrame->level]; 180 mask |= XP_WINDOW_LEVEL; 181 182 err = xp_create_window(mask, &wc, (xp_window_id *) &pFrame->wid); 183 184 if (err != Success) 185 { 186 return FALSE; 187 } 188 189 if (window_hash == NULL) 190 { 191 window_hash = x_hash_table_new(NULL, NULL, NULL, NULL); 192 pthread_mutex_init(&window_hash_mutex, NULL); 193 } 194 195 pthread_mutex_lock(&window_hash_mutex); 196 x_hash_table_insert(window_hash, pFrame->wid, pFrame); 197 pthread_mutex_unlock(&window_hash_mutex); 198 199 xprSetNativeProperty(pFrame); 200 201 return TRUE; 202} 203 204 205/* 206 * Destroy a frame. 207 */ 208static void 209xprDestroyFrame(RootlessFrameID wid) 210{ 211 xp_error err; 212 TA_SERVER(); 213 214 pthread_mutex_lock(&window_hash_mutex); 215 x_hash_table_remove(window_hash, wid); 216 pthread_mutex_unlock(&window_hash_mutex); 217 218 err = xp_destroy_window(x_cvt_vptr_to_uint(wid)); 219 if (err != Success) 220 FatalError("Could not destroy window %d (%d).", (int)x_cvt_vptr_to_uint(wid), (int)err); 221} 222 223 224/* 225 * Move a frame on screen. 226 */ 227static void 228xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY) 229{ 230 xp_window_changes wc; 231 232 TA_SERVER(); 233 234 wc.x = newX; 235 wc.y = newY; 236 // ErrorF("xprMoveFrame(%d, %p, %d, %d)\n", wid, pScreen, newX, newY); 237 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_ORIGIN, &wc); 238} 239 240 241/* 242 * Resize and move a frame. 243 */ 244static void 245xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, 246 int newX, int newY, unsigned int newW, unsigned int newH, 247 unsigned int gravity) 248{ 249 xp_window_changes wc; 250 251 TA_SERVER(); 252 253 wc.x = newX; 254 wc.y = newY; 255 wc.width = newW; 256 wc.height = newH; 257 wc.bit_gravity = gravity; 258 259 /* It's unlikely that being async will save us anything here. 260 But it can't hurt. */ 261 262 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_BOUNDS, &wc); 263} 264 265 266/* 267 * Change frame stacking. 268 */ 269static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) { 270 xp_window_changes wc; 271 unsigned int mask = XP_STACKING; 272 273 TA_SERVER(); 274 275 /* Stack frame below nextWid it if it exists, or raise 276 frame above everything otherwise. */ 277 278 if(nextWid == NULL) { 279 wc.stack_mode = XP_MAPPED_ABOVE; 280 wc.sibling = 0; 281 } else { 282 wc.stack_mode = XP_MAPPED_BELOW; 283 wc.sibling = x_cvt_vptr_to_uint(nextWid); 284 } 285 286 if(window_hash) { 287 RootlessWindowRec *winRec = x_hash_table_lookup(window_hash, wid, NULL); 288 289 if(winRec) { 290 if(XQuartzIsRootless) 291 wc.window_level = normal_window_levels[winRec->level]; 292 else if(XQuartzShieldingWindowLevel) 293 wc.window_level = XQuartzShieldingWindowLevel + 1; 294 else 295 wc.window_level = rooted_window_levels[winRec->level]; 296 mask |= XP_WINDOW_LEVEL; 297 } 298 } 299 300 xprConfigureWindow(x_cvt_vptr_to_uint(wid), mask, &wc); 301} 302 303 304/* 305 * Change the frame's shape. 306 */ 307static void 308xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape) 309{ 310 xp_window_changes wc; 311 312 TA_SERVER(); 313 314 if (pShape != NULL) 315 { 316 wc.shape_nrects = RegionNumRects(pShape); 317 wc.shape_rects = RegionRects(pShape); 318 } 319 else 320 { 321 wc.shape_nrects = -1; 322 wc.shape_rects = NULL; 323 } 324 325 wc.shape_tx = wc.shape_ty = 0; 326 327 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_SHAPE, &wc); 328} 329 330 331/* 332 * Unmap a frame. 333 */ 334static void 335xprUnmapFrame(RootlessFrameID wid) 336{ 337 xp_window_changes wc; 338 339 TA_SERVER(); 340 341 wc.stack_mode = XP_UNMAPPED; 342 wc.sibling = 0; 343 344 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_STACKING, &wc); 345} 346 347 348/* 349 * Start drawing to a frame. 350 * Prepare for direct access to its backing buffer. 351 */ 352static void 353xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow) 354{ 355 void *data[2]; 356 unsigned int rowbytes[2]; 357 xp_error err; 358 359 TA_SERVER(); 360 361 err = xp_lock_window(x_cvt_vptr_to_uint(wid), NULL, NULL, data, rowbytes, NULL); 362 if (err != Success) 363 FatalError("Could not lock window %d for drawing (%d).", (int)x_cvt_vptr_to_uint(wid), (int)err); 364 365 *pixelData = data[0]; 366 *bytesPerRow = rowbytes[0]; 367} 368 369 370/* 371 * Stop drawing to a frame. 372 */ 373static void 374xprStopDrawing(RootlessFrameID wid, Bool flush) 375{ 376 xp_error err; 377 TA_SERVER(); 378 379 err = xp_unlock_window(x_cvt_vptr_to_uint(wid), flush); 380 /* This should be a FatalError, but we started tripping over it. Make it a 381 * FatalError after http://xquartz.macosforge.org/trac/ticket/482 is fixed. 382 */ 383 if(err != Success) 384 ErrorF("Could not unlock window %d after drawing (%d).", (int)x_cvt_vptr_to_uint(wid), (int)err); 385} 386 387 388/* 389 * Flush drawing updates to the screen. 390 */ 391static void 392xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage) 393{ 394 TA_SERVER(); 395 396 xp_flush_window(x_cvt_vptr_to_uint(wid)); 397} 398 399 400/* 401 * Mark damaged rectangles as requiring redisplay to screen. 402 */ 403static void 404xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects, 405 int shift_x, int shift_y) 406{ 407 TA_SERVER(); 408 409 xp_mark_window(x_cvt_vptr_to_uint(wid), nrects, rects, shift_x, shift_y); 410} 411 412 413/* 414 * Called after the window associated with a frame has been switched 415 * to a new top-level parent. 416 */ 417static void 418xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin) 419{ 420 DeleteProperty(serverClient, oldWin, xa_native_window_id()); 421 422 TA_SERVER(); 423 424 xprSetNativeProperty(pFrame); 425} 426 427 428/* 429 * Called to check if the frame should be reordered when it is restacked. 430 */ 431static Bool xprDoReorderWindow(RootlessWindowPtr pFrame) 432{ 433 WindowPtr pWin = pFrame->win; 434 435 TA_SERVER(); 436 437 return AppleWMDoReorderWindow(pWin); 438} 439 440 441/* 442 * Copy area in frame to another part of frame. 443 * Used to accelerate scrolling. 444 */ 445static void 446xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, 447 int dx, int dy) 448{ 449 TA_SERVER(); 450 451 xp_copy_window(x_cvt_vptr_to_uint(wid), x_cvt_vptr_to_uint(wid), 452 dstNrects, dstRects, dx, dy); 453} 454 455 456static RootlessFrameProcsRec xprRootlessProcs = { 457 xprCreateFrame, 458 xprDestroyFrame, 459 xprMoveFrame, 460 xprResizeFrame, 461 xprRestackFrame, 462 xprReshapeFrame, 463 xprUnmapFrame, 464 xprStartDrawing, 465 xprStopDrawing, 466 xprUpdateRegion, 467 xprDamageRects, 468 xprSwitchWindow, 469 xprDoReorderWindow, 470 xprHideWindow, 471 xprUpdateColormap, 472 xp_copy_bytes, 473 xprCopyWindow 474}; 475 476 477/* 478 * Initialize XPR implementation 479 */ 480Bool 481xprInit(ScreenPtr pScreen) 482{ 483 RootlessInit(pScreen, &xprRootlessProcs); 484 485 TA_SERVER(); 486 487 rootless_CopyBytes_threshold = xp_copy_bytes_threshold; 488 rootless_CopyWindow_threshold = xp_scroll_area_threshold; 489 490 return TRUE; 491} 492 493 494/* 495 * Given the id of a physical window, try to find the top-level (or root) 496 * X window that it represents. 497 */ 498WindowPtr 499xprGetXWindow(xp_window_id wid) 500{ 501 RootlessWindowRec *winRec; 502 503 if (window_hash == NULL) 504 return NULL; 505 506 winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL); 507 508 return winRec != NULL ? winRec->win : NULL; 509} 510 511#ifdef UNUSED_CODE 512/* 513 * Given the id of a physical window, try to find the top-level (or root) 514 * X window that it represents. 515 */ 516WindowPtr 517xprGetXWindowFromAppKit(int windowNumber) 518{ 519 RootlessWindowRec *winRec; 520 Bool ret; 521 xp_window_id wid; 522 523 if (window_hash == NULL) 524 return FALSE; 525 526 /* need to lock, since this function can be called by any thread */ 527 528 pthread_mutex_lock(&window_hash_mutex); 529 530 if (xp_lookup_native_window(windowNumber, &wid)) 531 ret = xprGetXWindow(wid) != NULL; 532 else 533 ret = FALSE; 534 535 pthread_mutex_unlock(&window_hash_mutex); 536 537 if (!ret) return NULL; 538 winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL); 539 540 return winRec != NULL ? winRec->win : NULL; 541} 542#endif 543 544/* 545 * The windowNumber is an AppKit window number. Returns TRUE if xpr is 546 * displaying a window with that number. 547 */ 548Bool 549xprIsX11Window(void *nsWindow, int windowNumber) 550{ 551 Bool ret; 552 xp_window_id wid; 553 554 if (window_hash == NULL) 555 return FALSE; 556 557 /* need to lock, since this function can be called by any thread */ 558 559 pthread_mutex_lock(&window_hash_mutex); 560 561 if (xp_lookup_native_window(windowNumber, &wid)) 562 ret = xprGetXWindow(wid) != NULL; 563 else 564 ret = FALSE; 565 566 pthread_mutex_unlock(&window_hash_mutex); 567 568 return ret; 569} 570 571 572/* 573 * xprHideWindows 574 * Hide or unhide all top level windows. This is called for application hide/ 575 * unhide events if the window manager is not Apple-WM aware. Xplugin windows 576 * do not hide or unhide themselves. 577 */ 578void 579xprHideWindows(Bool hide) 580{ 581 int screen; 582 WindowPtr pRoot, pWin; 583 584 TA_SERVER(); 585 586 for (screen = 0; screen < screenInfo.numScreens; screen++) { 587 RootlessFrameID prevWid = NULL; 588 pRoot = screenInfo.screens[screen]->root; 589 590 for (pWin = pRoot->firstChild; pWin; pWin = pWin->nextSib) { 591 RootlessWindowRec *winRec = WINREC(pWin); 592 593 if (winRec != NULL) { 594 if (hide) { 595 xprUnmapFrame(winRec->wid); 596 } else { 597 BoxRec box; 598 599 xprRestackFrame(winRec->wid, prevWid); 600 prevWid = winRec->wid; 601 602 box.x1 = 0; 603 box.y1 = 0; 604 box.x2 = winRec->width; 605 box.y2 = winRec->height; 606 607 xprDamageRects(winRec->wid, 1, &box, 0, 0); 608 RootlessQueueRedisplay(screenInfo.screens[screen]); 609 } 610 } 611 } 612 } 613} 614 615// XXX: identical to x_cvt_vptr_to_uint ? 616#define MAKE_WINDOW_ID(x) ((xp_window_id)((size_t)(x))) 617 618Bool no_configure_window; 619 620static inline int 621configure_window (xp_window_id id, unsigned int mask, 622 const xp_window_changes *values) 623{ 624 if (!no_configure_window) 625 return xp_configure_window (id, mask, values); 626 else 627 return XP_Success; 628} 629 630 631static 632void xprUpdateColormap(RootlessFrameID wid, ScreenPtr pScreen) 633{ 634 /* This is how we tell xp that the colormap may have changed. */ 635 xp_window_changes wc; 636 wc.colormap = xprColormapCallback; 637 wc.colormap_data = pScreen; 638 639 configure_window(MAKE_WINDOW_ID(wid), XP_COLORMAP, &wc); 640} 641 642static 643void xprHideWindow(RootlessFrameID wid) 644{ 645 xp_window_changes wc; 646 wc.stack_mode = XP_UNMAPPED; 647 wc.sibling = 0; 648 configure_window(MAKE_WINDOW_ID(wid), XP_STACKING, &wc); 649} 650