Edit

IABSD.fr/xenocara/xserver/hw/xquartz/xpr/xprFrame.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2023-05-01 07:41:17
    Hash : 737e223e
    Message : Merge X server 21.1.8. tested by kn@ and op@.

  • xserver/hw/xquartz/xpr/xprFrame.c
  • /*
     * Xplugin rootless implementation frame functions
     *
     * Copyright (c) 2002-2012 Apple Computer, Inc. All rights reserved.
     * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved.
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     * DEALINGS IN THE SOFTWARE.
     *
     * Except as contained in this notice, the name(s) of the above copyright
     * holders shall not be used in advertising or otherwise to promote the sale,
     * use or other dealings in this Software without prior written authorization.
     */
    
    #ifdef HAVE_DIX_CONFIG_H
    #include <dix-config.h>
    #endif
    
    #include "xpr.h"
    #include "rootlessCommon.h"
    #include <Xplugin.h>
    #include "x-hash.h"
    #include "applewmExt.h"
    
    #include "propertyst.h"
    #include "dix.h"
    #include <X11/Xatom.h>
    #include "windowstr.h"
    #include "quartz.h"
    
    #include <dispatch/dispatch.h>
    
    #define DEFINE_ATOM_HELPER(func, atom_name)                      \
        static Atom func(void) {                                       \
            static int generation;                                      \
            static Atom atom;                                           \
            if (generation != serverGeneration) {                       \
                generation = serverGeneration;                          \
                atom = MakeAtom(atom_name, strlen(atom_name), TRUE);  \
            }                                                           \
            return atom;                                                \
        }
    
    DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID")
    
    /* Maps xp_window_id -> RootlessWindowRec */
    static x_hash_table * window_hash;
    
    /* Need to guard window_hash since xprIsX11Window can be called from any thread. */
    static dispatch_queue_t window_hash_serial_q;
    
    /* Prototypes for static functions */
    static Bool
    xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, int newX,
                   int newY,
                   RegionPtr pShape);
    static void
    xprDestroyFrame(RootlessFrameID wid);
    static void
    xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY);
    static void
    xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY,
                   unsigned int newW, unsigned int newH,
                   unsigned int gravity);
    static void
    xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid);
    static void
    xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape);
    static void
    xprUnmapFrame(RootlessFrameID wid);
    static void
    xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow);
    static void
    xprStopDrawing(RootlessFrameID wid, Bool flush);
    static void
    xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage);
    static void
    xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects,
                   int shift_x,
                   int shift_y);
    static void
    xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin);
    static Bool
    xprDoReorderWindow(RootlessWindowPtr pFrame);
    static void
    xprHideWindow(RootlessFrameID wid);
    static void
    xprUpdateColormap(RootlessFrameID wid, ScreenPtr pScreen);
    static void
    xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects,
                  int dx,
                  int dy);
    
    static inline xp_error
    xprConfigureWindow(xp_window_id id, unsigned int mask,
                       const xp_window_changes *values)
    {
        return xp_configure_window(id, mask, values);
    }
    
    static void
    xprSetNativeProperty(RootlessWindowPtr pFrame)
    {
        xp_error err;
        unsigned int native_id;
        long data;
    
        err = xp_get_native_window(x_cvt_vptr_to_uint(pFrame->wid), &native_id);
        if (err == Success) {
            /* FIXME: move this to AppleWM extension */
    
            data = native_id;
            dixChangeWindowProperty(serverClient, pFrame->win,
                                    xa_native_window_id(),
                                    XA_INTEGER, 32, PropModeReplace, 1, &data,
                                    TRUE);
        }
    }
    
    static xp_error
    xprColormapCallback(void *data, int first_color, int n_colors,
                        uint32_t *colors)
    {
        return (RootlessResolveColormap(data, first_color, n_colors,
                                        colors) ? XP_Success : XP_BadMatch);
    }
    
    /*
     * Create and display a new frame.
     */
    static Bool
    xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
                   int newX, int newY, RegionPtr pShape)
    {
        WindowPtr pWin = pFrame->win;
        xp_window_changes wc;
        unsigned int mask = 0;
        xp_error err;
    
        wc.x = newX;
        wc.y = newY;
        wc.width = pFrame->width;
        wc.height = pFrame->height;
        wc.bit_gravity = XP_GRAVITY_NONE;
        mask |= XP_BOUNDS;
    
        if (pWin->drawable.depth == 8) {
            wc.depth = XP_DEPTH_INDEX8;
            wc.colormap = xprColormapCallback;
            wc.colormap_data = pScreen;
            mask |= XP_COLORMAP;
        }
        else if (pWin->drawable.depth == 15)
            wc.depth = XP_DEPTH_RGB555;
        else if (pWin->drawable.depth == 24)
            wc.depth = XP_DEPTH_ARGB8888;
        else
            wc.depth = XP_DEPTH_NIL;
        mask |= XP_DEPTH;
    
        if (pShape != NULL) {
            wc.shape_nrects = RegionNumRects(pShape);
            wc.shape_rects = RegionRects(pShape);
            wc.shape_tx = wc.shape_ty = 0;
            mask |= XP_SHAPE;
        }
    
        pFrame->level =
            !IsRoot(pWin) ? AppleWMWindowLevelNormal : AppleWMNumWindowLevels;
    
        if (XQuartzIsRootless)
            wc.window_level = normal_window_levels[pFrame->level];
        else if (XQuartzShieldingWindowLevel)
            wc.window_level = XQuartzShieldingWindowLevel + 1;
        else
            wc.window_level = rooted_window_levels[pFrame->level];
        mask |= XP_WINDOW_LEVEL;
    
        err = xp_create_window(mask, &wc, (xp_window_id *)&pFrame->wid);
    
        if (err != Success) {
            return FALSE;
        }
    
        dispatch_async(window_hash_serial_q, ^ {
                           x_hash_table_insert(window_hash, pFrame->wid, pFrame);
                       });
    
        xprSetNativeProperty(pFrame);
    
        return TRUE;
    }
    
    /*
     * Destroy a frame.
     */
    static void
    xprDestroyFrame(RootlessFrameID wid)
    {
        xp_error err;
    
        dispatch_async(window_hash_serial_q, ^ {
                           x_hash_table_remove(window_hash, wid);
                       });
    
        err = xp_destroy_window(x_cvt_vptr_to_uint(wid));
        if (err != Success)
            FatalError("Could not destroy window %d (%d).",
                       (int)x_cvt_vptr_to_uint(
                           wid), (int)err);
    }
    
    /*
     * Move a frame on screen.
     */
    static void
    xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY)
    {
        xp_window_changes wc;
    
        wc.x = newX;
        wc.y = newY;
        //    ErrorF("xprMoveFrame(%d, %p, %d, %d)\n", wid, pScreen, newX, newY);
        xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_ORIGIN, &wc);
    }
    
    /*
     * Resize and move a frame.
     */
    static void
    xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen,
                   int newX, int newY, unsigned int newW, unsigned int newH,
                   unsigned int gravity)
    {
        xp_window_changes wc;
    
        wc.x = newX;
        wc.y = newY;
        wc.width = newW;
        wc.height = newH;
        wc.bit_gravity = gravity;
    
        /* It's unlikely that being async will save us anything here.
           But it can't hurt. */
    
        xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_BOUNDS, &wc);
    }
    
    /*
     * Change frame stacking.
     */
    static void
    xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid)
    {
        xp_window_changes wc;
        unsigned int mask = XP_STACKING;
        __block
        RootlessWindowRec * winRec;
    
        /* Stack frame below nextWid it if it exists, or raise
           frame above everything otherwise. */
    
        if (nextWid == NULL) {
            wc.stack_mode = XP_MAPPED_ABOVE;
            wc.sibling = 0;
        }
        else {
            wc.stack_mode = XP_MAPPED_BELOW;
            wc.sibling = x_cvt_vptr_to_uint(nextWid);
        }
    
        dispatch_sync(window_hash_serial_q, ^ {
                          winRec = x_hash_table_lookup(window_hash, wid, NULL);
                      });
    
        if (winRec) {
            if (XQuartzIsRootless)
                wc.window_level = normal_window_levels[winRec->level];
            else if (XQuartzShieldingWindowLevel)
                wc.window_level = XQuartzShieldingWindowLevel + 1;
            else
                wc.window_level = rooted_window_levels[winRec->level];
            mask |= XP_WINDOW_LEVEL;
        }
    
        xprConfigureWindow(x_cvt_vptr_to_uint(wid), mask, &wc);
    }
    
    /*
     * Change the frame's shape.
     */
    static void
    xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape)
    {
        xp_window_changes wc;
    
        if (pShape != NULL) {
            wc.shape_nrects = RegionNumRects(pShape);
            wc.shape_rects = RegionRects(pShape);
        }
        else {
            wc.shape_nrects = -1;
            wc.shape_rects = NULL;
        }
    
        wc.shape_tx = wc.shape_ty = 0;
    
        xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_SHAPE, &wc);
    }
    
    /*
     * Unmap a frame.
     */
    static void
    xprUnmapFrame(RootlessFrameID wid)
    {
        xp_window_changes wc;
    
        wc.stack_mode = XP_UNMAPPED;
        wc.sibling = 0;
    
        xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_STACKING, &wc);
    }
    
    /*
     * Start drawing to a frame.
     *  Prepare for direct access to its backing buffer.
     */
    static void
    xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow)
    {
        void *data[2];
        unsigned int rowbytes[2];
        xp_error err;
    
    #ifdef DEBUG_XP_LOCK_WINDOW
        ErrorF("=== LOCK %d ===\n", (int)x_cvt_vptr_to_uint(wid));
        xorg_backtrace();
    #endif
    
        err = xp_lock_window(x_cvt_vptr_to_uint(
                                 wid), NULL, NULL, data, rowbytes, NULL);
        if (err != Success)
            FatalError("Could not lock window %d for drawing (%d).",
                       (int)x_cvt_vptr_to_uint(
                           wid), (int)err);
    
    #ifdef DEBUG_XP_LOCK_WINDOW
        ErrorF("  bits: %p\n", *data);
    #endif
    
        *pixelData = data[0];
        *bytesPerRow = rowbytes[0];
    }
    
    /*
     * Stop drawing to a frame.
     */
    static void
    xprStopDrawing(RootlessFrameID wid, Bool flush)
    {
        xp_error err;
    
    #ifdef DEBUG_XP_LOCK_WINDOW
        ErrorF("=== UNLOCK %d ===\n", (int)x_cvt_vptr_to_uint(wid));
        xorg_backtrace();
    #endif
    
        err = xp_unlock_window(x_cvt_vptr_to_uint(wid), flush);
        /* This should be a FatalError, but we started tripping over it.  Make it a
         * FatalError after http://xquartz.macosforge.org/trac/ticket/482 is fixed.
         */
        if (err != Success)
            ErrorF("Could not unlock window %d after drawing (%d).",
                   (int)x_cvt_vptr_to_uint(
                       wid), (int)err);
    }
    
    /*
     * Flush drawing updates to the screen.
     */
    static void
    xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage)
    {
        xp_flush_window(x_cvt_vptr_to_uint(wid));
    }
    
    /*
     * Mark damaged rectangles as requiring redisplay to screen.
     */
    static void
    xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects,
                   int shift_x, int shift_y)
    {
        xp_mark_window(x_cvt_vptr_to_uint(wid), nrects, rects, shift_x, shift_y);
    }
    
    /*
     * Called after the window associated with a frame has been switched
     * to a new top-level parent.
     */
    static void
    xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin)
    {
        DeleteProperty(serverClient, oldWin, xa_native_window_id());
    
        xprSetNativeProperty(pFrame);
    }
    
    /*
     * Called to check if the frame should be reordered when it is restacked.
     */
    static Bool
    xprDoReorderWindow(RootlessWindowPtr pFrame)
    {
        WindowPtr pWin = pFrame->win;
    
        return AppleWMDoReorderWindow(pWin);
    }
    
    /*
     * Copy area in frame to another part of frame.
     *  Used to accelerate scrolling.
     */
    static void
    xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects,
                  int dx, int dy)
    {
        xp_copy_window(x_cvt_vptr_to_uint(wid), x_cvt_vptr_to_uint(wid),
                       dstNrects, dstRects, dx, dy);
    }
    
    static RootlessFrameProcsRec xprRootlessProcs = {
        xprCreateFrame,
        xprDestroyFrame,
        xprMoveFrame,
        xprResizeFrame,
        xprRestackFrame,
        xprReshapeFrame,
        xprUnmapFrame,
        xprStartDrawing,
        xprStopDrawing,
        xprUpdateRegion,
        xprDamageRects,
        xprSwitchWindow,
        xprDoReorderWindow,
        xprHideWindow,
        xprUpdateColormap,
        xp_copy_bytes,
        xprCopyWindow
    };
    
    /*
     * Initialize XPR implementation
     */
    Bool
    xprInit(ScreenPtr pScreen)
    {
        RootlessInit(pScreen, &xprRootlessProcs);
    
        rootless_CopyBytes_threshold = xp_copy_bytes_threshold;
        rootless_CopyWindow_threshold = xp_scroll_area_threshold;
    
        assert((window_hash = x_hash_table_new(NULL, NULL, NULL, NULL)));
        assert((window_hash_serial_q =
                    dispatch_queue_create(BUNDLE_ID_PREFIX ".X11.xpr_window_hash",
                                          NULL)));
    
        return TRUE;
    }
    
    /*
     * Given the id of a physical window, try to find the top-level (or root)
     * X window that it represents.
     */
    WindowPtr
    xprGetXWindow(xp_window_id wid)
    {
        RootlessWindowRec *winRec __block;
        dispatch_sync(window_hash_serial_q, ^ {
                          winRec =
                              x_hash_table_lookup(window_hash,
                                                  x_cvt_uint_to_vptr(wid), NULL);
                      });
    
        return winRec != NULL ? winRec->win : NULL;
    }
    
    /*
     * The windowNumber is an AppKit window number. Returns TRUE if xpr is
     * displaying a window with that number.
     */
    Bool
    xprIsX11Window(int windowNumber)
    {
        Bool ret;
        xp_window_id wid;
    
        if (xp_lookup_native_window(windowNumber, &wid))
            ret = xprGetXWindow(wid) != NULL;
        else
            ret = FALSE;
    
        return ret;
    }
    
    /*
     * xprHideWindows
     *  Hide or unhide all top level windows. This is called for application hide/
     *  unhide events if the window manager is not Apple-WM aware. Xplugin windows
     *  do not hide or unhide themselves.
     */
    void
    xprHideWindows(Bool hide)
    {
        int screen;
        WindowPtr pRoot, pWin;
    
        for (screen = 0; screen < screenInfo.numScreens; screen++) {
            RootlessFrameID prevWid = NULL;
            pRoot = screenInfo.screens[screen]->root;
    
            for (pWin = pRoot->firstChild; pWin; pWin = pWin->nextSib) {
                RootlessWindowRec *winRec = WINREC(pWin);
    
                if (winRec != NULL) {
                    if (hide) {
                        xprUnmapFrame(winRec->wid);
                    }
                    else {
                        BoxRec box;
    
                        xprRestackFrame(winRec->wid, prevWid);
                        prevWid = winRec->wid;
    
                        box.x1 = 0;
                        box.y1 = 0;
                        box.x2 = winRec->width;
                        box.y2 = winRec->height;
    
                        xprDamageRects(winRec->wid, 1, &box, 0, 0);
                        RootlessQueueRedisplay(screenInfo.screens[screen]);
                    }
                }
            }
        }
    }
    
    // XXX: identical to x_cvt_vptr_to_uint ?
    #define MAKE_WINDOW_ID(x) ((xp_window_id)((size_t)(x)))
    
    Bool no_configure_window;
    
    static inline int
    configure_window(xp_window_id id, unsigned int mask,
                     const xp_window_changes *values)
    {
        if (!no_configure_window)
            return xp_configure_window(id, mask, values);
        else
            return XP_Success;
    }
    
    static
    void
    xprUpdateColormap(RootlessFrameID wid, ScreenPtr pScreen)
    {
        /* This is how we tell xp that the colormap may have changed. */
        xp_window_changes wc;
        wc.colormap = xprColormapCallback;
        wc.colormap_data = pScreen;
    
        configure_window(MAKE_WINDOW_ID(wid), XP_COLORMAP, &wc);
    }
    
    static
    void
    xprHideWindow(RootlessFrameID wid)
    {
        xp_window_changes wc;
        wc.stack_mode = XP_UNMAPPED;
        wc.sibling = 0;
        configure_window(MAKE_WINDOW_ID(wid), XP_STACKING, &wc);
    }