xprFrame.c revision 9ace9065
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 %i.", (int)x_cvt_vptr_to_uint(wid)); 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 %i for drawing.", (int)x_cvt_vptr_to_uint(wid)); 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 if(err != Success) 381 FatalError("Could not unlock window %i after drawing.", (int)x_cvt_vptr_to_uint(wid)); 382} 383 384 385/* 386 * Flush drawing updates to the screen. 387 */ 388static void 389xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage) 390{ 391 TA_SERVER(); 392 393 xp_flush_window(x_cvt_vptr_to_uint(wid)); 394} 395 396 397/* 398 * Mark damaged rectangles as requiring redisplay to screen. 399 */ 400static void 401xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects, 402 int shift_x, int shift_y) 403{ 404 TA_SERVER(); 405 406 xp_mark_window(x_cvt_vptr_to_uint(wid), nrects, rects, shift_x, shift_y); 407} 408 409 410/* 411 * Called after the window associated with a frame has been switched 412 * to a new top-level parent. 413 */ 414static void 415xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin) 416{ 417 DeleteProperty(serverClient, oldWin, xa_native_window_id()); 418 419 TA_SERVER(); 420 421 xprSetNativeProperty(pFrame); 422} 423 424 425/* 426 * Called to check if the frame should be reordered when it is restacked. 427 */ 428static Bool xprDoReorderWindow(RootlessWindowPtr pFrame) 429{ 430 WindowPtr pWin = pFrame->win; 431 432 TA_SERVER(); 433 434 return AppleWMDoReorderWindow(pWin); 435} 436 437 438/* 439 * Copy area in frame to another part of frame. 440 * Used to accelerate scrolling. 441 */ 442static void 443xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, 444 int dx, int dy) 445{ 446 TA_SERVER(); 447 448 xp_copy_window(x_cvt_vptr_to_uint(wid), x_cvt_vptr_to_uint(wid), 449 dstNrects, dstRects, dx, dy); 450} 451 452 453static RootlessFrameProcsRec xprRootlessProcs = { 454 xprCreateFrame, 455 xprDestroyFrame, 456 xprMoveFrame, 457 xprResizeFrame, 458 xprRestackFrame, 459 xprReshapeFrame, 460 xprUnmapFrame, 461 xprStartDrawing, 462 xprStopDrawing, 463 xprUpdateRegion, 464 xprDamageRects, 465 xprSwitchWindow, 466 xprDoReorderWindow, 467 xprHideWindow, 468 xprUpdateColormap, 469 xp_copy_bytes, 470 xprCopyWindow 471}; 472 473 474/* 475 * Initialize XPR implementation 476 */ 477Bool 478xprInit(ScreenPtr pScreen) 479{ 480 RootlessInit(pScreen, &xprRootlessProcs); 481 482 TA_SERVER(); 483 484 rootless_CopyBytes_threshold = xp_copy_bytes_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