xprFrame.c revision 6747b715
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 177 wc.window_level = rooted_window_levels[pFrame->level]; 178 mask |= XP_WINDOW_LEVEL; 179 180 err = xp_create_window(mask, &wc, (xp_window_id *) &pFrame->wid); 181 182 if (err != Success) 183 { 184 return FALSE; 185 } 186 187 if (window_hash == NULL) 188 { 189 window_hash = x_hash_table_new(NULL, NULL, NULL, NULL); 190 pthread_mutex_init(&window_hash_mutex, NULL); 191 } 192 193 pthread_mutex_lock(&window_hash_mutex); 194 x_hash_table_insert(window_hash, pFrame->wid, pFrame); 195 pthread_mutex_unlock(&window_hash_mutex); 196 197 xprSetNativeProperty(pFrame); 198 199 return TRUE; 200} 201 202 203/* 204 * Destroy a frame. 205 */ 206static void 207xprDestroyFrame(RootlessFrameID wid) 208{ 209 xp_error err; 210 TA_SERVER(); 211 212 pthread_mutex_lock(&window_hash_mutex); 213 x_hash_table_remove(window_hash, wid); 214 pthread_mutex_unlock(&window_hash_mutex); 215 216 err = xp_destroy_window(x_cvt_vptr_to_uint(wid)); 217 if (err != Success) 218 FatalError("Could not destroy window %i.", (int)x_cvt_vptr_to_uint(wid)); 219} 220 221 222/* 223 * Move a frame on screen. 224 */ 225static void 226xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY) 227{ 228 xp_window_changes wc; 229 230 TA_SERVER(); 231 232 wc.x = newX; 233 wc.y = newY; 234 // ErrorF("xprMoveFrame(%d, %p, %d, %d)\n", wid, pScreen, newX, newY); 235 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_ORIGIN, &wc); 236} 237 238 239/* 240 * Resize and move a frame. 241 */ 242static void 243xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, 244 int newX, int newY, unsigned int newW, unsigned int newH, 245 unsigned int gravity) 246{ 247 xp_window_changes wc; 248 249 TA_SERVER(); 250 251 wc.x = newX; 252 wc.y = newY; 253 wc.width = newW; 254 wc.height = newH; 255 wc.bit_gravity = gravity; 256 257 /* It's unlikely that being async will save us anything here. 258 But it can't hurt. */ 259 260 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_BOUNDS, &wc); 261} 262 263 264/* 265 * Change frame stacking. 266 */ 267static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) { 268 xp_window_changes wc; 269 unsigned int mask = XP_STACKING; 270 271 TA_SERVER(); 272 273 /* Stack frame below nextWid it if it exists, or raise 274 frame above everything otherwise. */ 275 276 if(nextWid == NULL) { 277 wc.stack_mode = XP_MAPPED_ABOVE; 278 wc.sibling = 0; 279 } else { 280 wc.stack_mode = XP_MAPPED_BELOW; 281 wc.sibling = x_cvt_vptr_to_uint(nextWid); 282 } 283 284 if(window_hash) { 285 RootlessWindowRec *winRec = x_hash_table_lookup(window_hash, wid, NULL); 286 287 if(winRec) { 288 if(XQuartzIsRootless) 289 wc.window_level = normal_window_levels[winRec->level]; 290 else 291 wc.window_level = rooted_window_levels[winRec->level]; 292 mask |= XP_WINDOW_LEVEL; 293 } 294 } 295 296 xprConfigureWindow(x_cvt_vptr_to_uint(wid), mask, &wc); 297} 298 299 300/* 301 * Change the frame's shape. 302 */ 303static void 304xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape) 305{ 306 xp_window_changes wc; 307 308 TA_SERVER(); 309 310 if (pShape != NULL) 311 { 312 wc.shape_nrects = RegionNumRects(pShape); 313 wc.shape_rects = RegionRects(pShape); 314 } 315 else 316 { 317 wc.shape_nrects = -1; 318 wc.shape_rects = NULL; 319 } 320 321 wc.shape_tx = wc.shape_ty = 0; 322 323 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_SHAPE, &wc); 324} 325 326 327/* 328 * Unmap a frame. 329 */ 330static void 331xprUnmapFrame(RootlessFrameID wid) 332{ 333 xp_window_changes wc; 334 335 TA_SERVER(); 336 337 wc.stack_mode = XP_UNMAPPED; 338 wc.sibling = 0; 339 340 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_STACKING, &wc); 341} 342 343 344/* 345 * Start drawing to a frame. 346 * Prepare for direct access to its backing buffer. 347 */ 348static void 349xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow) 350{ 351 void *data[2]; 352 unsigned int rowbytes[2]; 353 xp_error err; 354 355 TA_SERVER(); 356 357 err = xp_lock_window(x_cvt_vptr_to_uint(wid), NULL, NULL, data, rowbytes, NULL); 358 if (err != Success) 359 FatalError("Could not lock window %i for drawing.", (int)x_cvt_vptr_to_uint(wid)); 360 361 *pixelData = data[0]; 362 *bytesPerRow = rowbytes[0]; 363} 364 365 366/* 367 * Stop drawing to a frame. 368 */ 369static void 370xprStopDrawing(RootlessFrameID wid, Bool flush) 371{ 372 xp_error err; 373 TA_SERVER(); 374 375 err = xp_unlock_window(x_cvt_vptr_to_uint(wid), flush); 376 if(err != Success) 377 FatalError("Could not unlock window %i after drawing.", (int)x_cvt_vptr_to_uint(wid)); 378} 379 380 381/* 382 * Flush drawing updates to the screen. 383 */ 384static void 385xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage) 386{ 387 TA_SERVER(); 388 389 xp_flush_window(x_cvt_vptr_to_uint(wid)); 390} 391 392 393/* 394 * Mark damaged rectangles as requiring redisplay to screen. 395 */ 396static void 397xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects, 398 int shift_x, int shift_y) 399{ 400 TA_SERVER(); 401 402 xp_mark_window(x_cvt_vptr_to_uint(wid), nrects, rects, shift_x, shift_y); 403} 404 405 406/* 407 * Called after the window associated with a frame has been switched 408 * to a new top-level parent. 409 */ 410static void 411xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin) 412{ 413 DeleteProperty(serverClient, oldWin, xa_native_window_id()); 414 415 TA_SERVER(); 416 417 xprSetNativeProperty(pFrame); 418} 419 420 421/* 422 * Called to check if the frame should be reordered when it is restacked. 423 */ 424static Bool xprDoReorderWindow(RootlessWindowPtr pFrame) 425{ 426 WindowPtr pWin = pFrame->win; 427 428 TA_SERVER(); 429 430 return AppleWMDoReorderWindow(pWin); 431} 432 433 434/* 435 * Copy area in frame to another part of frame. 436 * Used to accelerate scrolling. 437 */ 438static void 439xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, 440 int dx, int dy) 441{ 442 TA_SERVER(); 443 444 xp_copy_window(x_cvt_vptr_to_uint(wid), x_cvt_vptr_to_uint(wid), 445 dstNrects, dstRects, dx, dy); 446} 447 448 449static RootlessFrameProcsRec xprRootlessProcs = { 450 xprCreateFrame, 451 xprDestroyFrame, 452 xprMoveFrame, 453 xprResizeFrame, 454 xprRestackFrame, 455 xprReshapeFrame, 456 xprUnmapFrame, 457 xprStartDrawing, 458 xprStopDrawing, 459 xprUpdateRegion, 460 xprDamageRects, 461 xprSwitchWindow, 462 xprDoReorderWindow, 463 xprHideWindow, 464 xprUpdateColormap, 465 xp_copy_bytes, 466 xp_fill_bytes, 467 xp_composite_pixels, 468 xprCopyWindow 469}; 470 471 472/* 473 * Initialize XPR implementation 474 */ 475Bool 476xprInit(ScreenPtr pScreen) 477{ 478 RootlessInit(pScreen, &xprRootlessProcs); 479 480 TA_SERVER(); 481 482 rootless_CopyBytes_threshold = xp_copy_bytes_threshold; 483 rootless_FillBytes_threshold = xp_fill_bytes_threshold; 484 rootless_CompositePixels_threshold = xp_composite_area_threshold; 485 rootless_CopyWindow_threshold = xp_scroll_area_threshold; 486 487 return TRUE; 488} 489 490 491/* 492 * Given the id of a physical window, try to find the top-level (or root) 493 * X window that it represents. 494 */ 495WindowPtr 496xprGetXWindow(xp_window_id wid) 497{ 498 RootlessWindowRec *winRec; 499 500 if (window_hash == NULL) 501 return NULL; 502 503 winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL); 504 505 return winRec != NULL ? winRec->win : NULL; 506} 507 508#ifdef UNUSED_CODE 509/* 510 * Given the id of a physical window, try to find the top-level (or root) 511 * X window that it represents. 512 */ 513WindowPtr 514xprGetXWindowFromAppKit(int windowNumber) 515{ 516 RootlessWindowRec *winRec; 517 Bool ret; 518 xp_window_id wid; 519 520 if (window_hash == NULL) 521 return FALSE; 522 523 /* need to lock, since this function can be called by any thread */ 524 525 pthread_mutex_lock(&window_hash_mutex); 526 527 if (xp_lookup_native_window(windowNumber, &wid)) 528 ret = xprGetXWindow(wid) != NULL; 529 else 530 ret = FALSE; 531 532 pthread_mutex_unlock(&window_hash_mutex); 533 534 if (!ret) return NULL; 535 winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL); 536 537 return winRec != NULL ? winRec->win : NULL; 538} 539#endif 540 541/* 542 * The windowNumber is an AppKit window number. Returns TRUE if xpr is 543 * displaying a window with that number. 544 */ 545Bool 546xprIsX11Window(void *nsWindow, int windowNumber) 547{ 548 Bool ret; 549 xp_window_id wid; 550 551 if (window_hash == NULL) 552 return FALSE; 553 554 /* need to lock, since this function can be called by any thread */ 555 556 pthread_mutex_lock(&window_hash_mutex); 557 558 if (xp_lookup_native_window(windowNumber, &wid)) 559 ret = xprGetXWindow(wid) != NULL; 560 else 561 ret = FALSE; 562 563 pthread_mutex_unlock(&window_hash_mutex); 564 565 return ret; 566} 567 568 569/* 570 * xprHideWindows 571 * Hide or unhide all top level windows. This is called for application hide/ 572 * unhide events if the window manager is not Apple-WM aware. Xplugin windows 573 * do not hide or unhide themselves. 574 */ 575void 576xprHideWindows(Bool hide) 577{ 578 int screen; 579 WindowPtr pRoot, pWin; 580 581 TA_SERVER(); 582 583 for (screen = 0; screen < screenInfo.numScreens; screen++) { 584 RootlessFrameID prevWid = NULL; 585 pRoot = screenInfo.screens[screen]->root; 586 587 for (pWin = pRoot->firstChild; pWin; pWin = pWin->nextSib) { 588 RootlessWindowRec *winRec = WINREC(pWin); 589 590 if (winRec != NULL) { 591 if (hide) { 592 xprUnmapFrame(winRec->wid); 593 } else { 594 BoxRec box; 595 596 xprRestackFrame(winRec->wid, prevWid); 597 prevWid = winRec->wid; 598 599 box.x1 = 0; 600 box.y1 = 0; 601 box.x2 = winRec->width; 602 box.y2 = winRec->height; 603 604 xprDamageRects(winRec->wid, 1, &box, 0, 0); 605 RootlessQueueRedisplay(screenInfo.screens[screen]); 606 } 607 } 608 } 609 } 610} 611 612// XXX: identical to x_cvt_vptr_to_uint ? 613#define MAKE_WINDOW_ID(x) ((xp_window_id)((size_t)(x))) 614 615Bool no_configure_window; 616 617static inline int 618configure_window (xp_window_id id, unsigned int mask, 619 const xp_window_changes *values) 620{ 621 if (!no_configure_window) 622 return xp_configure_window (id, mask, values); 623 else 624 return XP_Success; 625} 626 627 628static 629void xprUpdateColormap(RootlessFrameID wid, ScreenPtr pScreen) 630{ 631 /* This is how we tell xp that the colormap may have changed. */ 632 xp_window_changes wc; 633 wc.colormap = xprColormapCallback; 634 wc.colormap_data = pScreen; 635 636 configure_window(MAKE_WINDOW_ID(wid), XP_COLORMAP, &wc); 637} 638 639static 640void xprHideWindow(RootlessFrameID wid) 641{ 642 xp_window_changes wc; 643 wc.stack_mode = XP_UNMAPPED; 644 wc.sibling = 0; 645 configure_window(MAKE_WINDOW_ID(wid), XP_STACKING, &wc); 646} 647