xprFrame.c revision 4642e01f
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 46#include "threadSafety.h" 47 48#include <pthread.h> 49 50#define DEFINE_ATOM_HELPER(func,atom_name) \ 51static Atom func (void) { \ 52 static int generation; \ 53 static Atom atom; \ 54 if (generation != serverGeneration) { \ 55 generation = serverGeneration; \ 56 atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ 57 } \ 58 return atom; \ 59} 60 61DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID") 62 63/* Maps xp_window_id -> RootlessWindowRec */ 64static x_hash_table *window_hash; 65static pthread_mutex_t window_hash_mutex; 66 67/* Prototypes for static functions */ 68static Bool xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, 69 int newX, int newY, RegionPtr pShape); 70static void xprDestroyFrame(RootlessFrameID wid); 71static void xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY); 72static void xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, 73 int newX, int newY, unsigned int newW, unsigned int newH, 74 unsigned int gravity); 75static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid); 76static void xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape); 77static void xprUnmapFrame(RootlessFrameID wid); 78static void xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow); 79static void xprStopDrawing(RootlessFrameID wid, Bool flush); 80static void xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage); 81static void xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects, 82 int shift_x, int shift_y); 83static void xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin); 84static Bool xprDoReorderWindow(RootlessWindowPtr pFrame); 85static void xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, 86 int dx, int dy); 87 88 89static inline xp_error 90xprConfigureWindow(xp_window_id id, unsigned int mask, 91 const xp_window_changes *values) 92{ 93 TA_SERVER(); 94 95 return xp_configure_window(id, mask, values); 96} 97 98 99static void 100xprSetNativeProperty(RootlessWindowPtr pFrame) 101{ 102 xp_error err; 103 unsigned int native_id; 104 long data; 105 106 TA_SERVER(); 107 108 err = xp_get_native_window(x_cvt_vptr_to_uint(pFrame->wid), &native_id); 109 if (err == Success) 110 { 111 /* FIXME: move this to AppleWM extension */ 112 113 data = native_id; 114 dixChangeWindowProperty(serverClient, pFrame->win, xa_native_window_id(), 115 XA_INTEGER, 32, PropModeReplace, 1, &data, TRUE); 116 } 117} 118 119 120/* 121 * Create and display a new frame. 122 */ 123Bool 124xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, 125 int newX, int newY, RegionPtr pShape) 126{ 127 WindowPtr pWin = pFrame->win; 128 xp_window_changes wc; 129 unsigned int mask = 0; 130 xp_error err; 131 132 TA_SERVER(); 133 134 wc.x = newX; 135 wc.y = newY; 136 wc.width = pFrame->width; 137 wc.height = pFrame->height; 138 wc.bit_gravity = XP_GRAVITY_NONE; 139 mask |= XP_BOUNDS; 140 141 if (pWin->drawable.depth == 8) 142 { 143 wc.depth = XP_DEPTH_INDEX8; 144 wc.colormap = RootlessColormapCallback; 145 wc.colormap_data = pScreen; 146 mask |= XP_COLORMAP; 147 } 148 else if (pWin->drawable.depth == 15) 149 wc.depth = XP_DEPTH_RGB555; 150 else if (pWin->drawable.depth == 24) 151 wc.depth = XP_DEPTH_ARGB8888; 152 else 153 wc.depth = XP_DEPTH_NIL; 154 mask |= XP_DEPTH; 155 156 if (pShape != NULL) 157 { 158 wc.shape_nrects = REGION_NUM_RECTS(pShape); 159 wc.shape_rects = REGION_RECTS(pShape); 160 wc.shape_tx = wc.shape_ty = 0; 161 mask |= XP_SHAPE; 162 } 163 164 err = xp_create_window(mask, &wc, (xp_window_id *) &pFrame->wid); 165 166 if (err != Success) 167 { 168 return FALSE; 169 } 170 171 if (window_hash == NULL) 172 { 173 window_hash = x_hash_table_new(NULL, NULL, NULL, NULL); 174 pthread_mutex_init(&window_hash_mutex, NULL); 175 } 176 177 pthread_mutex_lock(&window_hash_mutex); 178 x_hash_table_insert(window_hash, pFrame->wid, pFrame); 179 pthread_mutex_unlock(&window_hash_mutex); 180 181 xprSetNativeProperty(pFrame); 182 183 return TRUE; 184} 185 186 187/* 188 * Destroy a frame. 189 */ 190void 191xprDestroyFrame(RootlessFrameID wid) 192{ 193 TA_SERVER(); 194 195 pthread_mutex_lock(&window_hash_mutex); 196 x_hash_table_remove(window_hash, wid); 197 pthread_mutex_unlock(&window_hash_mutex); 198 199 xp_destroy_window(x_cvt_vptr_to_uint(wid)); 200} 201 202 203/* 204 * Move a frame on screen. 205 */ 206void 207xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY) 208{ 209 TA_SERVER(); 210 211 xp_window_changes wc; 212 213 wc.x = newX; 214 wc.y = newY; 215 // ErrorF("xprMoveFrame(%d, %p, %d, %d)\n", wid, pScreen, newX, newY); 216 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_ORIGIN, &wc); 217} 218 219 220/* 221 * Resize and move a frame. 222 */ 223void 224xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, 225 int newX, int newY, unsigned int newW, unsigned int newH, 226 unsigned int gravity) 227{ 228 xp_window_changes wc; 229 230 TA_SERVER(); 231 232 wc.x = newX; 233 wc.y = newY; 234 wc.width = newW; 235 wc.height = newH; 236 wc.bit_gravity = gravity; 237 238 /* It's unlikely that being async will save us anything here. 239 But it can't hurt. */ 240 241 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_BOUNDS, &wc); 242} 243 244 245/* 246 * Change frame stacking. 247 */ 248void 249xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) 250{ 251 xp_window_changes wc; 252 253 TA_SERVER(); 254 255 /* Stack frame below nextWid it if it exists, or raise 256 frame above everything otherwise. */ 257 258 if (nextWid == NULL) 259 { 260 wc.stack_mode = XP_MAPPED_ABOVE; 261 wc.sibling = 0; 262 } 263 else 264 { 265 wc.stack_mode = XP_MAPPED_BELOW; 266 wc.sibling = x_cvt_vptr_to_uint(nextWid); 267 } 268 269 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_STACKING, &wc); 270} 271 272 273/* 274 * Change the frame's shape. 275 */ 276void 277xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape) 278{ 279 xp_window_changes wc; 280 281 TA_SERVER(); 282 283 if (pShape != NULL) 284 { 285 wc.shape_nrects = REGION_NUM_RECTS(pShape); 286 wc.shape_rects = REGION_RECTS(pShape); 287 } 288 else 289 { 290 wc.shape_nrects = -1; 291 wc.shape_rects = NULL; 292 } 293 294 wc.shape_tx = wc.shape_ty = 0; 295 296 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_SHAPE, &wc); 297} 298 299 300/* 301 * Unmap a frame. 302 */ 303void 304xprUnmapFrame(RootlessFrameID wid) 305{ 306 xp_window_changes wc; 307 308 TA_SERVER(); 309 310 wc.stack_mode = XP_UNMAPPED; 311 wc.sibling = 0; 312 313 xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_STACKING, &wc); 314} 315 316 317/* 318 * Start drawing to a frame. 319 * Prepare for direct access to its backing buffer. 320 */ 321void 322xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow) 323{ 324 void *data[2]; 325 unsigned int rowbytes[2]; 326 xp_error err; 327 328 TA_SERVER(); 329 330 err = xp_lock_window(x_cvt_vptr_to_uint(wid), NULL, NULL, data, rowbytes, NULL); 331 if (err != Success) 332 FatalError("Could not lock window %i for drawing.", (int)x_cvt_vptr_to_uint(wid)); 333 334 *pixelData = data[0]; 335 *bytesPerRow = rowbytes[0]; 336} 337 338 339/* 340 * Stop drawing to a frame. 341 */ 342void 343xprStopDrawing(RootlessFrameID wid, Bool flush) 344{ 345 TA_SERVER(); 346 347 xp_unlock_window(x_cvt_vptr_to_uint(wid), flush); 348} 349 350 351/* 352 * Flush drawing updates to the screen. 353 */ 354void 355xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage) 356{ 357 TA_SERVER(); 358 359 xp_flush_window(x_cvt_vptr_to_uint(wid)); 360} 361 362 363/* 364 * Mark damaged rectangles as requiring redisplay to screen. 365 */ 366void 367xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects, 368 int shift_x, int shift_y) 369{ 370 TA_SERVER(); 371 372 xp_mark_window(x_cvt_vptr_to_uint(wid), nrects, rects, shift_x, shift_y); 373} 374 375 376/* 377 * Called after the window associated with a frame has been switched 378 * to a new top-level parent. 379 */ 380void 381xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin) 382{ 383 DeleteProperty(serverClient, oldWin, xa_native_window_id()); 384 385 TA_SERVER(); 386 387 xprSetNativeProperty(pFrame); 388} 389 390 391/* 392 * Called to check if the frame should be reordered when it is restacked. 393 */ 394Bool xprDoReorderWindow(RootlessWindowPtr pFrame) 395{ 396 WindowPtr pWin = pFrame->win; 397 398 TA_SERVER(); 399 400 return AppleWMDoReorderWindow(pWin); 401} 402 403 404/* 405 * Copy area in frame to another part of frame. 406 * Used to accelerate scrolling. 407 */ 408void 409xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, 410 int dx, int dy) 411{ 412 TA_SERVER(); 413 414 xp_copy_window(x_cvt_vptr_to_uint(wid), x_cvt_vptr_to_uint(wid), 415 dstNrects, dstRects, dx, dy); 416} 417 418 419static RootlessFrameProcsRec xprRootlessProcs = { 420 xprCreateFrame, 421 xprDestroyFrame, 422 xprMoveFrame, 423 xprResizeFrame, 424 xprRestackFrame, 425 xprReshapeFrame, 426 xprUnmapFrame, 427 xprStartDrawing, 428 xprStopDrawing, 429 xprUpdateRegion, 430 xprDamageRects, 431 xprSwitchWindow, 432 xprDoReorderWindow, 433 xp_copy_bytes, 434 xp_fill_bytes, 435 xp_composite_pixels, 436 xprCopyWindow 437}; 438 439 440/* 441 * Initialize XPR implementation 442 */ 443Bool 444xprInit(ScreenPtr pScreen) 445{ 446 RootlessInit(pScreen, &xprRootlessProcs); 447 448 TA_SERVER(); 449 450 rootless_CopyBytes_threshold = xp_copy_bytes_threshold; 451 rootless_FillBytes_threshold = xp_fill_bytes_threshold; 452 rootless_CompositePixels_threshold = xp_composite_area_threshold; 453 rootless_CopyWindow_threshold = xp_scroll_area_threshold; 454 455 return TRUE; 456} 457 458 459/* 460 * Given the id of a physical window, try to find the top-level (or root) 461 * X window that it represents. 462 */ 463WindowPtr 464xprGetXWindow(xp_window_id wid) 465{ 466 RootlessWindowRec *winRec; 467 468 if (window_hash == NULL) 469 return NULL; 470 471 winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL); 472 473 return winRec != NULL ? winRec->win : NULL; 474} 475 476/* 477 * Given the id of a physical window, try to find the top-level (or root) 478 * X window that it represents. 479 */ 480WindowPtr 481xprGetXWindowFromAppKit(int windowNumber) 482{ 483 RootlessWindowRec *winRec; 484 Bool ret; 485 xp_window_id wid; 486 487 if (window_hash == NULL) 488 return FALSE; 489 490 /* need to lock, since this function can be called by any thread */ 491 492 pthread_mutex_lock(&window_hash_mutex); 493 494 if (xp_lookup_native_window(windowNumber, &wid)) 495 ret = xprGetXWindow(wid) != NULL; 496 else 497 ret = FALSE; 498 499 pthread_mutex_unlock(&window_hash_mutex); 500 501 if (!ret) return NULL; 502 winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL); 503 504 return winRec != NULL ? winRec->win : NULL; 505} 506 507 508/* 509 * The windowNumber is an AppKit window number. Returns TRUE if xpr is 510 * displaying a window with that number. 511 */ 512Bool 513xprIsX11Window(void *nsWindow, int windowNumber) 514{ 515 Bool ret; 516 xp_window_id wid; 517 518 if (window_hash == NULL) 519 return FALSE; 520 521 /* need to lock, since this function can be called by any thread */ 522 523 pthread_mutex_lock(&window_hash_mutex); 524 525 if (xp_lookup_native_window(windowNumber, &wid)) 526 ret = xprGetXWindow(wid) != NULL; 527 else 528 ret = FALSE; 529 530 pthread_mutex_unlock(&window_hash_mutex); 531 532 return ret; 533} 534 535 536/* 537 * xprHideWindows 538 * Hide or unhide all top level windows. This is called for application hide/ 539 * unhide events if the window manager is not Apple-WM aware. Xplugin windows 540 * do not hide or unhide themselves. 541 */ 542void 543xprHideWindows(Bool hide) 544{ 545 int screen; 546 WindowPtr pRoot, pWin; 547 548 TA_SERVER(); 549 550 for (screen = 0; screen < screenInfo.numScreens; screen++) { 551 pRoot = WindowTable[screenInfo.screens[screen]->myNum]; 552 RootlessFrameID prevWid = NULL; 553 554 for (pWin = pRoot->firstChild; pWin; pWin = pWin->nextSib) { 555 RootlessWindowRec *winRec = WINREC(pWin); 556 557 if (winRec != NULL) { 558 if (hide) { 559 xprUnmapFrame(winRec->wid); 560 } else { 561 BoxRec box; 562 563 xprRestackFrame(winRec->wid, prevWid); 564 prevWid = winRec->wid; 565 566 box.x1 = 0; 567 box.y1 = 0; 568 box.x2 = winRec->width; 569 box.y2 = winRec->height; 570 571 xprDamageRects(winRec->wid, 1, &box, 0, 0); 572 RootlessQueueRedisplay(screenInfo.screens[screen]); 573 } 574 } 575 } 576 } 577} 578