xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

xprFrame.c (16783B)


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