X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-osx%2Ftrunk%2Flauncher%2Frootless-window.c;fp=synfig-osx%2Ftrunk%2Flauncher%2Frootless-window.c;h=2ae8a44465d11eab724f8353928a5057da467f86;hb=4f638c4f8e5dc642a92d62da31233654eca397b2;hp=0000000000000000000000000000000000000000;hpb=7bf63b38a939d592d8a7c0c1f52aadfda2229427;p=synfig.git diff --git a/synfig-osx/trunk/launcher/rootless-window.c b/synfig-osx/trunk/launcher/rootless-window.c new file mode 100644 index 0000000..2ae8a44 --- /dev/null +++ b/synfig-osx/trunk/launcher/rootless-window.c @@ -0,0 +1,2056 @@ +/* + * Rootless window management + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, Inc. 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. + */ +/* Portions of this file are based on fbwindow.c, which contains the + * following copyright: + * + * Copyright © 1998 Keith Packard + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.c,v 1.11 2002/09/28 00:43:39 torrey Exp $ */ + +#include "rootless-common.h" +#include "rootless-window.h" +#include "darwin.h" +#include "Xplugin.h" +#include "x-hash.h" +#include "x-list.h" +#define _APPLEWM_SERVER_ +#include "applewmstr.h" + +#include "fb.h" +#include "propertyst.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +#include +#include + +#define DEFINE_ATOM_HELPER(func,atom_name) \ +static Atom func (void) { \ + static unsigned 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_screen_origin, "_NATIVE_SCREEN_ORIGIN") +DEFINE_ATOM_HELPER (xa_native_window_id, "_NATIVE_WINDOW_ID") +DEFINE_ATOM_HELPER (xa_apple_no_order_in, "_APPLE_NO_ORDER_IN") + +/* Maps xp_window_id -> AquaWindowRec */ +static x_hash_table *window_hash; +static pthread_mutex_t window_hash_mutex; + +static Bool no_configure_window; +static Bool windows_hidden; + +static const int normal_window_levels[AppleWMNumWindowLevels+1] = { + 0, 3, 4, 5, LONG_MIN + 30, LONG_MIN + 29, +}; +static const int rooted_window_levels[AppleWMNumWindowLevels+1] = { + 202, 203, 204, 205, 201, 200 +}; + +static inline xp_error +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 inline unsigned long +current_time_in_seconds (void) +{ + unsigned long t = 0; + + t += currentTime.milliseconds / 1000; + t += currentTime.months * 4294967; + + return t; +} + +static inline Bool +rootlessHasRoot (ScreenPtr pScreen) +{ + return WINREC (WindowTable[pScreen->myNum]) != NULL; +} + +void +RootlessNativeWindowStateChanged (xp_window_id id, unsigned int state) +{ + WindowPtr pWin; + RootlessWindowRec *winRec; + + pWin = RootlessGetXWindow (id); + if (pWin == NULL) + return; + + winRec = WINREC (pWin); + if (winRec == NULL) + return; + + winRec->is_offscreen = (state & XP_WINDOW_STATE_OFFSCREEN) != 0; + winRec->is_obscured = (state & XP_WINDOW_STATE_OBSCURED) != 0; + +#ifdef ROOTLESS + pWin->rootlessUnhittable = winRec->is_offscreen; +#endif +} + +void +RootlessNativeWindowMoved (xp_window_id id) +{ + WindowPtr pWin; + xp_box bounds; + int sx, sy; + XID vlist[2]; + Mask mask; + ClientPtr client; + + pWin = RootlessGetXWindow (id); + if (pWin == NULL) + return; + + if (xp_get_window_bounds (id, &bounds) != Success) + return; + + sx = dixScreenOrigins[pWin->drawable.pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pWin->drawable.pScreen->myNum].y + darwinMainScreenY; + + /* Fake up a ConfigureWindow packet to resize the window to the + current bounds. */ + + vlist[0] = (INT16) bounds.x1 - sx; + vlist[1] = (INT16) bounds.y1 - sy; + mask = CWX | CWY; + + /* pretend we're the owner of the window! */ + client = LookupClient (pWin->drawable.id, NullClient); + + /* Don't want to do anything to the physical window (avoids + notification-response feedback loops) */ + + no_configure_window = TRUE; + ConfigureWindow (pWin, mask, vlist, client); + no_configure_window = FALSE; +} + +/* Updates the _NATIVE_SCREEN_ORIGIN property on the given root window. */ +static void +set_screen_origin (WindowPtr pWin) +{ + long data[2]; + + if (!IsRoot (pWin)) + return; + + /* FIXME: move this to an extension? */ + + data[0] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].x + + darwinMainScreenX); + data[1] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].y + + darwinMainScreenY); + + ChangeWindowProperty (pWin, xa_native_screen_origin (), XA_INTEGER, + 32, PropModeReplace, 2, data, TRUE); +} + +/* For now, don't create a physical window until either the window is + realized, or we really need it (e.g. to attach VRAM surfaces to). + Do reset the window size so it's not clipped by the root window. */ +Bool +RootlessCreateWindow (WindowPtr pWin) +{ + Bool result; + RegionRec saveRoot; + + SCREEN_UNWRAP (pWin->drawable.pScreen, CreateWindow); + + if (!IsRoot (pWin)) + { + /* win/border size set by DIX, not by wrapped CreateWindow, so + correct it here. Don't HUGE_ROOT when pWin is the root! */ + + HUGE_ROOT (pWin); + SetWinSize (pWin); + SetBorderSize (pWin); + } + else + { + set_screen_origin (pWin); + } + + result = pWin->drawable.pScreen->CreateWindow (pWin); + + if (pWin->parent) + NORMAL_ROOT (pWin); + + SCREEN_WRAP (pWin->drawable.pScreen, CreateWindow); + + return result; +} + +/* Destroy the physical window associated with the given window */ +static void +rootlessDestroyFrame (WindowPtr pWin, RootlessWindowRec *winRec) +{ + RootlessStopDrawing (pWin, FALSE); + + pthread_mutex_lock (&window_hash_mutex); + x_hash_table_remove (window_hash, (void *) winRec->wid); + pthread_mutex_unlock (&window_hash_mutex); + + xp_destroy_window (winRec->wid); + + xfree (winRec); + WINREC (pWin) = NULL; +} + +Bool +RootlessDestroyWindow (WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + Bool result; + + if (winRec != NULL) + rootlessDestroyFrame (pWin, winRec); + + /* winRec is gone now */ + + SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow); + + result = pWin->drawable.pScreen->DestroyWindow (pWin); + + SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow); + + return result; +} + +#ifdef SHAPE +static Bool +RootlessGetShape (WindowPtr pWin, RegionPtr pShape) +{ + if (wBoundingShape (pWin) == NULL) + return FALSE; + + /* wBoundingShape is relative to *inner* origin of window. + Translate by borderWidth to get the outside-relative position. */ + + REGION_INIT (pScreen, pShape, NullBox, 0); + REGION_COPY (pScreen, pShape, wBoundingShape (pWin)); + REGION_TRANSLATE (pScreen, pShape, pWin->borderWidth, pWin->borderWidth); + + return TRUE; +} + +/* boundingShape = outside border (like borderClip) + clipShape = inside border (like clipList) + Both are in window-local coordinates + We only care about boundingShape (FIXME true?) + + RootlessReallySetShape is used in several places other than SetShape. + Most importantly, SetShape is often called on unmapped windows, so we + have to wait until the window is mapped to reshape the frame. */ +static void +rootlessSetShape (WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC (pWin); + + RegionRec newShape; + RegionPtr pShape; + xp_window_changes wc; + + if (winRec == NULL) + return; + + RootlessStopDrawing (pWin, FALSE); + + pShape = RootlessGetShape (pWin, &newShape) ? &newShape : NULL; + + RL_DEBUG_MSG("reshaping..."); + RL_DEBUG_MSG("numrects %d, extents %d %d %d %d\n", + REGION_NUM_RECTS(&newShape), + newShape.extents.x1, newShape.extents.y1, + newShape.extents.x2, newShape.extents.y2); + + RootlessDisableUpdate (pWin); + + if (pShape != NULL) + { + wc.shape_nrects = REGION_NUM_RECTS (pShape); + wc.shape_rects = REGION_RECTS (pShape); + } + else + { + wc.shape_nrects = -1; + wc.shape_rects = NULL; + } + + wc.shape_tx = wc.shape_ty = 0; + + configure_window (winRec->wid, XP_SHAPE, &wc); + + if (pShape != NULL) + REGION_UNINIT(pScreen, &newShape); +} + +void +RootlessSetShape (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREEN_UNWRAP (pScreen, SetShape); + + pScreen->SetShape (pWin); + + SCREEN_WRAP (pScreen, SetShape); + + rootlessSetShape (pWin); +} +#endif + +/* Disallow ParentRelative background on top-level windows + because the root window doesn't really have the right background + and fb will try to draw on the root instead of on the window. + ParentRelative prevention is also in PaintWindowBackground/Border() + so it is no longer really needed here. */ +Bool +RootlessChangeWindowAttributes (WindowPtr pWin, unsigned long vmask) +{ + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("change window attributes start\n"); + + SCREEN_UNWRAP (pScreen, ChangeWindowAttributes); + + result = pScreen->ChangeWindowAttributes (pWin, vmask); + + SCREEN_WRAP (pScreen, ChangeWindowAttributes); + + if (WINREC (pWin) != NULL) + { + /* disallow ParentRelative background state */ + + if (pWin->backgroundState == ParentRelative) + { + XID pixel = 0; + ChangeWindowAttributes (pWin, CWBackPixel, &pixel, serverClient); + } + } + + RL_DEBUG_MSG("change window attributes end\n"); + return result; +} + +/* This is a hook for when DIX moves or resizes a window. + Update the frame position now. (x, y) are *inside* position. + After this, mi and fb are expecting the pixmap to be at the new location. */ +Bool +RootlessPositionWindow (WindowPtr pWin, int x, int y) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC (pWin); + Bool result; + + RL_DEBUG_MSG("positionwindow start (win 0x%x)\n", pWin); + + if (winRec != NULL) + { + if (winRec->is_drawing) + { + /* Reset frame's pixmap and move it to the new position. */ + int bw = wBorderWidth (pWin); + + winRec->pixmap->devPrivate.ptr = winRec->data; + TranslatePixmapBase (winRec->pixmap, - (x - bw), - (y - bw)); + } + } + + SCREEN_UNWRAP (pScreen, PositionWindow); + + result = pScreen->PositionWindow (pWin, x, y); + + SCREEN_WRAP(pScreen, PositionWindow); + + RL_DEBUG_MSG("positionwindow end\n"); + return result; +} + +/* Initialize some basic attributes of the frame. Note that winRec + may already have valid data in it, so don't overwrite anything + valuable. */ +static void +rootlessInitializeFrame (WindowPtr pWin, RootlessWindowRec *winRec) +{ + DrawablePtr d = &pWin->drawable; + int bw = wBorderWidth (pWin); + + winRec->win = pWin; + + winRec->x = d->x - bw; + winRec->y = d->y - bw; + winRec->width = d->width + 2*bw; + winRec->height = d->height + 2*bw; + winRec->borderWidth = bw; +} + +static void +rootlessSetNativeProperty (RootlessWindowRec *winRec) +{ + xp_error err; + unsigned int native_id; + long data; + + err = xp_get_native_window (winRec->wid, &native_id); + if (err == Success) + { + /* FIXME: move this to an extension? */ + + data = native_id; + ChangeWindowProperty (winRec->win, xa_native_window_id (), + XA_INTEGER, 32, PropModeReplace, 1, &data, TRUE); + } +} + +static xp_error +rootlessColormapCallback (void *data, int first_color, + int n_colors, uint32_t *colors) +{ + return (RootlessResolveColormap (data, first_color, n_colors, colors) + ? XP_Success : XP_BadMatch); +} + +/* If the given window doesn't have a physical window associated with it, + attempt to create one. If that's unsuccessful, return null. */ +static RootlessWindowRec * +rootlessEnsureFrame (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec; + RegionRec shape; + RegionPtr pShape = NULL; + + xp_window_changes wc; + unsigned int mask; + xp_error err; + int sx, sy; + + if (WINREC (pWin) != NULL) + return WINREC (pWin); + + if (pWin->drawable.class != InputOutput) + return NULL; + + winRec = xalloc (sizeof(RootlessWindowRec)); + + if (!winRec) + return NULL; + + rootlessInitializeFrame (pWin, winRec); + + winRec->is_drawing = FALSE; + winRec->pixmap = NULL; + winRec->wid = 0; + winRec->is_update_disabled = FALSE; + winRec->is_reorder_pending = FALSE; + winRec->level = !IsRoot (pWin) ? 0 : AppleWMNumWindowLevels; + WINREC(pWin) = winRec; + +#ifdef SHAPE + if (RootlessGetShape (pWin, &shape)) + pShape = &shape; +#endif + + sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + mask = 0; + + wc.x = sx + winRec->x; + wc.y = sy + winRec->y; + wc.width = winRec->width; + wc.height = winRec->height; + wc.bit_gravity = XP_GRAVITY_NONE; + mask |= XP_BOUNDS; + + if (pWin->drawable.depth == 8) + { + wc.depth = XP_DEPTH_INDEX8; + wc.colormap = rootlessColormapCallback; + 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 = REGION_NUM_RECTS (pShape); + wc.shape_rects = REGION_RECTS (pShape); + wc.shape_tx = wc.shape_ty = 0; + mask |= XP_SHAPE; + } + + if (!rootlessHasRoot (pScreen)) + wc.window_level = normal_window_levels[winRec->level]; + else + wc.window_level = rooted_window_levels[winRec->level]; + mask |= XP_WINDOW_LEVEL; + + err = xp_create_window (mask, &wc, &winRec->wid); + + if (err != Success) + { + xfree (winRec); + return NULL; + } + + if (window_hash == NULL) + { + window_hash = x_hash_table_new (NULL, NULL, NULL, NULL); + pthread_mutex_init (&window_hash_mutex, NULL); + } + + pthread_mutex_lock (&window_hash_mutex); + x_hash_table_insert (window_hash, (void *) winRec->wid, winRec); + pthread_mutex_unlock (&window_hash_mutex); + + rootlessSetNativeProperty (winRec); + + if (pShape != NULL) + REGION_UNINIT (pScreen, &shape); + + return winRec; +} + +/* The frame is usually created here and not in CreateWindow so that + windows do not eat memory until they are realized. */ +Bool +RootlessRealizeWindow(WindowPtr pWin) +{ + Bool result = FALSE; + RegionRec saveRoot; + ScreenPtr pScreen = pWin->drawable.pScreen; + XID pixel; + + RL_DEBUG_MSG("realizewindow start (win 0x%x)\n", pWin); + + if (IsTopLevel (pWin) && pWin->drawable.class == InputOutput) + { + RootlessWindowRec *winRec; + + winRec = rootlessEnsureFrame (pWin); + if (winRec == NULL) + return NULL; + + winRec->is_reorder_pending = TRUE; + + /* Disallow ParentRelative background state on top-level windows. + This might have been set before the window was mapped. */ + + if (pWin->backgroundState == ParentRelative) + { + pixel = 0; + ChangeWindowAttributes (pWin, CWBackPixel, &pixel, serverClient); + } + } + + if (!IsRoot(pWin)) HUGE_ROOT(pWin); + SCREEN_UNWRAP (pScreen, RealizeWindow); + + result = pScreen->RealizeWindow (pWin); + + SCREEN_WRAP (pScreen, RealizeWindow); + if (!IsRoot(pWin)) NORMAL_ROOT(pWin); + + RL_DEBUG_MSG("realizewindow end\n"); + return result; +} + +void +RootlessEnableRoot (ScreenPtr pScreen) +{ + WindowPtr pRoot; + pRoot = WindowTable[pScreen->myNum]; + + rootlessEnsureFrame (pRoot); + (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE); + RootlessReorderWindow (pRoot); +} + +void +RootlessDisableRoot (ScreenPtr pScreen) +{ + WindowPtr pRoot; + RootlessWindowRec *winRec; + + pRoot = WindowTable[pScreen->myNum]; + winRec = WINREC (pRoot); + + if (winRec != NULL) + { + rootlessDestroyFrame (pRoot, winRec); + DeleteProperty (pRoot, xa_native_window_id ()); + } +} + +void +RootlessHideAllWindows (void) +{ + int i; + ScreenPtr pScreen; + WindowPtr pWin; + RootlessWindowRec *winRec; + xp_window_changes wc; + + if (windows_hidden) + return; + + windows_hidden = TRUE; + + for (i = 0; i < screenInfo.numScreens; i++) + { + pScreen = screenInfo.screens[i]; + pWin = WindowTable[i]; + if (pScreen == NULL || pWin == NULL) + continue; + + for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) + { + if (!pWin->realized) + continue; + + RootlessStopDrawing (pWin, FALSE); + + winRec = WINREC (pWin); + if (winRec != NULL) + { + wc.stack_mode = XP_UNMAPPED; + wc.sibling = 0; + configure_window (winRec->wid, XP_STACKING, &wc); + } + } + } +} + +void +RootlessShowAllWindows (void) +{ + int i; + ScreenPtr pScreen; + WindowPtr pWin; + RootlessWindowRec *winRec; + + if (!windows_hidden) + return; + + windows_hidden = FALSE; + + for (i = 0; i < screenInfo.numScreens; i++) + { + pScreen = screenInfo.screens[i]; + pWin = WindowTable[i]; + if (pScreen == NULL || pWin == NULL) + continue; + + for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) + { + if (!pWin->realized) + continue; + + winRec = rootlessEnsureFrame (pWin); + if (winRec == NULL) + continue; + + RootlessReorderWindow (pWin); + } + + RootlessScreenExpose (pScreen); + } +} + +void +RootlessSetWindowLevel (WindowPtr pWin, int level) +{ + RootlessWindowRec *winRec; + xp_window_changes wc; + + winRec = WINREC (pWin); + if (!IsTopLevel (pWin) || winRec == NULL || winRec->level == level) + return; + + RootlessStopDrawing (pWin, FALSE); + + winRec->level = level; + + if (!rootlessHasRoot (pWin->drawable.pScreen)) + wc.window_level = normal_window_levels[level]; + else + wc.window_level = rooted_window_levels[level]; + + configure_window (winRec->wid, XP_WINDOW_LEVEL, &wc); +} + +/* Return the id of the physical window displaying the given window. If + CREATE is true and the window has no frame, attempt to create one. */ +xp_window_id +RootlessGetPhysicalWindow (WindowPtr pWin, Bool create) +{ + RootlessWindowRec *winRec; + + if (TopLevelParent (pWin) == NULL) + return 0; + + winRec = WINREC (pWin); + + if (winRec == NULL && create && !IsRoot (pWin) + && pWin->drawable.class == InputOutput) + { + rootlessEnsureFrame (pWin); + winRec = WINREC (pWin); + } + + if (winRec == NULL) + return 0; + + return winRec->wid; +} + +/* Given the id of a physical window, try to find the top-level (or root) + X window that it represents. */ +WindowPtr +RootlessGetXWindow (xp_window_id wid) +{ + RootlessWindowRec *winRec; + + if (window_hash == NULL) + return NULL; + + winRec = x_hash_table_lookup (window_hash, (void *) wid, NULL); + + return winRec != NULL ? winRec->win : NULL; +} + +/* Number is an appkit window number. Returns true if X is displaying + a window with that number. */ +int +RootlessKnowsWindowNumber (int number) +{ + Bool ret; + xp_window_id wid; + + /* need to lock, since this function can be called by any thread */ + + if (window_hash == NULL) + return FALSE; + + pthread_mutex_lock (&window_hash_mutex); + + if (xp_lookup_native_window (number, &wid)) + ret = RootlessGetXWindow (wid) != NULL; + else + ret = FALSE; + + pthread_mutex_unlock (&window_hash_mutex); + + return ret; +} + +Bool +RootlessUnrealizeWindow (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + xp_window_changes wc; + Bool result; + + RL_DEBUG_MSG("unrealizewindow start\n"); + + if (winRec != NULL) + { + RootlessStopDrawing (pWin, FALSE); + + wc.stack_mode = XP_UNMAPPED; + wc.sibling = 0; + + configure_window (winRec->wid, XP_STACKING, &wc); + + winRec->unrealize_time = current_time_in_seconds (); + winRec->is_reorder_pending = FALSE; + + RootlessReenableUpdate (pWin); + } + + SCREEN_UNWRAP (pScreen, UnrealizeWindow); + + result = pScreen->UnrealizeWindow (pWin); + + SCREEN_WRAP (pScreen, UnrealizeWindow); + + RL_DEBUG_MSG ("unrealizewindow end\n"); + return result; +} + +void +RootlessReparentWindow (WindowPtr pWin, WindowPtr pPriorParent) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC (pWin); + + WindowPtr pTopWin; + + if (IsRoot (pWin) || IsRoot (pWin->parent) + || IsTopLevel (pWin) || winRec == NULL) + { + return; + } + + /* If the window is moving upwards towards the root has a frame, + we want to try to move it onto its new toplevel parent. If we + can't do that, we'll just have to jettison it.. */ + + pTopWin = TopLevelParent (pWin); + assert (pTopWin != pWin); + + pWin->rootlessUnhittable = FALSE; + + DeleteProperty (pWin, xa_native_window_id ()); + + if (WINREC (pTopWin) != NULL) + { + /* We're screwed. */ + rootlessDestroyFrame (pWin, winRec); + } + else + { + xp_window_changes wc; + int sx, sy; + + if (!pTopWin->realized && pWin->realized) + { + wc.stack_mode = XP_UNMAPPED; + wc.sibling = 0; + + RootlessStopDrawing (pWin, FALSE); + configure_window (winRec->wid, XP_STACKING, &wc); + } + + /* Switch the frame record from one to the other. */ + + WINREC (pWin) = NULL; + WINREC (pTopWin) = winRec; + + rootlessInitializeFrame (pTopWin, winRec); + rootlessSetShape (pTopWin); + + sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + wc.x = sx + winRec->x; + wc.y = sy + winRec->y; + wc.width = winRec->width; + wc.height = winRec->height; + wc.bit_gravity = XP_GRAVITY_NONE; + + RootlessStopDrawing (pWin, FALSE); + configure_window (winRec->wid, XP_BOUNDS, &wc); + + rootlessSetNativeProperty (winRec); + + if (pTopWin->realized && !pWin->realized) + winRec->is_reorder_pending = TRUE; + } +} + +/* Reorder the window associated with the given frame so that it's + physically above the window below it in the X stacking order. */ +void +RootlessReorderWindow (WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC (pWin); + + if (pWin->realized && winRec != NULL + && !winRec->is_reorder_pending && !windows_hidden) + { + WindowPtr newPrevW; + RootlessWindowRec *newPrev; + xp_window_changes wc; + Atom atom; + PropertyPtr prop; + + /* quartz-wm sets the _APPLE_NO_ORDER_IN property on windows + that are being genie-restored from the Dock. We want them to + be mapped but remain ordered-out until the animation + completes (when the Dock will order them in) */ + + atom = xa_apple_no_order_in (); + for (prop = wUserProps (pWin); prop != NULL; prop = prop->next) + { + if (prop->propertyName == atom && prop->type == atom) + return; + } + + RootlessStopDrawing (pWin, FALSE); + + if (IsRoot (pWin)) + { + wc.stack_mode = XP_MAPPED_BELOW; + wc.sibling = 0; + } + else + { + /* Find the next window above this one that has a mapped frame. */ + + newPrevW = pWin->prevSib; + while (newPrevW + && (WINREC (newPrevW) == NULL || !newPrevW->realized)) + { + newPrevW = newPrevW->prevSib; + } + + newPrev = newPrevW != NULL ? WINREC (newPrevW) : NULL; + + /* Then either stack ourselves below it if it exists, or raise + ourselves above everything otherwise. */ + + if (newPrev == NULL) + { + wc.stack_mode = XP_MAPPED_ABOVE; + wc.sibling = 0; + } + else + { + if (newPrev->is_reorder_pending) + { + newPrev->is_reorder_pending = FALSE; + RootlessReorderWindow (newPrevW); + } + + wc.stack_mode = XP_MAPPED_BELOW; + wc.sibling = newPrev->wid; + } + } + + configure_window (winRec->wid, XP_STACKING, &wc); + } +} + +void +RootlessRestackWindow (WindowPtr pWin, WindowPtr pOldNextSib) +{ + RegionRec saveRoot; + RootlessWindowRec *winRec = WINREC (pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("restackwindow start\n"); + if (winRec != NULL) + RL_DEBUG_MSG("restack top level \n"); + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, RestackWindow); + + if (pScreen->RestackWindow != NULL) + pScreen->RestackWindow (pWin, pOldNextSib); + + SCREEN_WRAP(pScreen, RestackWindow); + NORMAL_ROOT(pWin); + + if (winRec != NULL && pWin->viewable) + RootlessReorderWindow (pWin); + + RL_DEBUG_MSG("restackwindow end\n"); +} + +/* + * Specialized window copy procedures + */ + +/* Globals needed during window resize and move. */ +static pointer gResizeDeathBits = NULL; +static int gResizeDeathCount; +static PixmapPtr gResizeDeathPix[2]; +static BoxRec gResizeDeathBounds[2]; +static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL; + +/* CopyWindow () that doesn't do anything. For MoveWindow() of + top-level windows. */ +static void +RootlessNoCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + /* Some code expects the region to be translated */ + + int dx = ptOldOrg.x - pWin->drawable.x; + int dy = ptOldOrg.y - pWin->drawable.y; + + REGION_TRANSLATE (pWin->drawable.pScreen, prgnSrc, -dx, -dy); +} + +/* CopyWindow used during ResizeWindow for gravity moves. (from fbCopyWindow) + The original always draws on the root pixmap (which we don't have). + Instead, draw on the parent window's pixmap. + Resize version: the old location's pixels are in gResizeCopyWindowSource */ +static void +RootlessResizeCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec rgnDst; + int dx, dy; + + RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x)\n", pWin); + + /* Don't unwrap pScreen->CopyWindow. + The bogus rewrap with RootlessCopyWindow causes a crash if + CopyWindow is called again during the same resize. */ + + if (gResizeDeathCount == 0) + return; + + RootlessStartDrawing (pWin); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy); + REGION_INIT (pScreen, &rgnDst, NullBox, 0); + REGION_INTERSECT (pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + if (gResizeDeathCount == 1) + { + /* Simple case, we only have a single source pixmap. */ + + fbCopyRegion (&gResizeDeathPix[0]->drawable, + &pScreen->GetWindowPixmap(pWin)->drawable, 0, + &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + } + else + { + int i; + RegionRec clip, clipped; + + /* More complex case, N source pixmaps (usually two). So we + intersect the destination with each source and copy those bits. */ + + for (i = 0; i < gResizeDeathCount; i++) + { + REGION_INIT (pScreen, &clip, gResizeDeathBounds + 0, 1); + REGION_INIT (pScreen, &clipped, NullBox, 0); + REGION_INTERSECT (pScreen, &rgnDst, &clip, &clipped); + + fbCopyRegion (&gResizeDeathPix[i]->drawable, + &pScreen->GetWindowPixmap(pWin)->drawable, 0, + &clipped, dx, dy, fbCopyWindowProc, 0, 0); + + REGION_UNINIT (pScreen, &clipped); + REGION_UNINIT (pScreen, &clip); + } + } + + /* Don't update - resize will update everything */ + REGION_UNINIT (pScreen, &rgnDst); + + fbValidateDrawable (&pWin->drawable); + + RL_DEBUG_MSG("resizecopywindowFB end\n"); +} + +/* Update *new* location of window. Old location is redrawn with + PaintWindowBackground/Border. Cloned from fbCopyWindow + The original always draws on the root pixmap (which we don't have). + Instead, draw on the parent window's pixmap. */ +void +RootlessCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec; + WindowPtr top; + + RegionRec rgnDst; + int dx, dy; + BoxPtr extents; + unsigned int area; + + RL_DEBUG_MSG("copywindowFB start (win 0x%x)\n", pWin); + + top = TopLevelParent (pWin); + if (top == NULL) + { + RL_DEBUG_MSG("no parent\n"); + return; + } + + winRec = WINREC(top); + if (winRec == NULL) + { + RL_DEBUG_MSG("not framed\n"); + return; + } + + SCREEN_UNWRAP (pScreen, CopyWindow); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy); + + REGION_INIT (pScreen, &rgnDst, NullBox, 0); + REGION_INTERSECT (pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + extents = REGION_EXTENTS (pScreen, &rgnDst); + area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1); + + if (area > xp_scroll_area_threshold) + { + /* Move region to window local coords */ + REGION_TRANSLATE (pScreen, &rgnDst, -winRec->x, -winRec->y); + + RootlessStopDrawing (pWin, FALSE); + + xp_copy_window (winRec->wid, winRec->wid, + REGION_NUM_RECTS (&rgnDst), + REGION_RECTS (&rgnDst), dx, dy); + } + else + { + RootlessStartDrawing (pWin); + + fbCopyRegion ((DrawablePtr) pWin, (DrawablePtr) pWin, + 0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + + /* prgnSrc has been translated to dst position */ + RootlessDamageRegion(pWin, prgnSrc); + } + + REGION_UNINIT (pScreen, &rgnDst); + fbValidateDrawable (&pWin->drawable); + + SCREEN_WRAP (pScreen, CopyWindow); + + RL_DEBUG_MSG("copywindowFB end\n"); +} + +/* + * Window resize procedures + */ + +enum { + WIDTH_SMALLER = 1, + HEIGHT_SMALLER = 2, +}; + +/* Compute which directions the window is resizing in. */ +static inline unsigned int +resize_code (int oldX, int oldY, int oldW, int oldH, + int newX, int newY, int newW, int newH) +{ + unsigned int code = 0; + + /* These comparisons were chosen to avoid setting bits when the sizes + are the same. (So the fastest case automatically gets taken when + dimensions are unchanging.) */ + + if (newW < oldW) + code |= WIDTH_SMALLER; + + if (newH < oldH) + code |= HEIGHT_SMALLER; + + return code; +} + +static inline unsigned int +resize_weighting (int oldX1, int oldY1, int oldX2, int oldY2, int oldBW, + int newX1, int newY1, int newX2, int newY2, int newBW) +{ + /* Choose gravity to avoid local copies. Do that by looking for + a corner that doesn't move _relative to the screen_ */ + + if (newBW != oldBW) + return XP_GRAVITY_NONE; + + if (newX1 == oldX1 && newY1 == oldY1) + return XP_GRAVITY_NORTH_WEST; + else if (newX1 == oldX1 && newY2 == oldY2) + return XP_GRAVITY_SOUTH_WEST; + else if (newX2 == oldX2 && newY2 == oldY2) + return XP_GRAVITY_SOUTH_EAST; + else if (newX2 == oldX2 && newY1 == oldY1) + return XP_GRAVITY_NORTH_EAST; + else + return XP_GRAVITY_NONE; +} + +/* Resize the given window to its new position and size. */ +static void +resize_frame (ScreenPtr pScreen, WindowPtr pWin, + RootlessWindowRec *winRec, int gravity) +{ + int sx, sy; + xp_window_changes wc; + + sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + wc.x = sx + winRec->x; + wc.y = sy + winRec->y; + wc.width = winRec->width; + wc.height = winRec->height; + wc.bit_gravity = gravity; + + /* It's unlikely that being async will save us anything here. + But it can't hurt. */ + + configure_window (winRec->wid, XP_BOUNDS, &wc); +} + +/* Prepare to resize a top-level window. The old window's pixels are + saved and the implementation is told to change the window size. + (x,y,w,h) is outer frame of window (outside border) */ +static Bool +StartFrameResize (WindowPtr pWin, Bool gravity, + int oldX, int oldY, int oldW, int oldH, int oldBW, + int newX, int newY, int newW, int newH, int newBW) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + Bool need_window_source = FALSE, resize_after = FALSE; + + BoxRec rect, copy_rect; + int oldX2, newX2; + int oldY2, newY2; + unsigned int weight; + + oldX2 = oldX + oldW, newX2 = newX + newW; + oldY2 = oldY + oldH, newY2 = newY + newH; + + /* Decide which resize weighting to use */ + weight = resize_weighting (oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + /* Compute intersection between old and new rects */ + rect.x1 = max(oldX, newX); + rect.y1 = max(oldY, newY); + rect.x2 = min(oldX2, newX2); + rect.y2 = min(oldY2, newY2); + + RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity); + RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n", + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + RootlessDisableUpdate (pWin); + RootlessRedisplay (pWin); + + /* If gravity is true, then we need to have a way of recovering all + the original bits in the window for when X rearranges the contents + based on the various gravity settings. The obvious way is to just + snapshot the entire backing store before resizing it, but that + it slow on large windows. + + So the optimization here is to use CG's resize weighting options + to allow us to reason about what is left in the backing store + after the resize. We can then only copy what won't be there after + the resize, and do a two-stage copy operation. + + Most of these optimizations are only applied when the top-left + corner of the window is fixed, since that's the common case. They + could probably be extended with some thought. */ + + gResizeDeathCount = 0; + + if (gravity && weight == XP_GRAVITY_NORTH_WEST) + { + unsigned int code; + + /* Top left corner is anchored. We never need to copy the + entire window. */ + + need_window_source = TRUE; + + code = resize_code (oldX, oldY, oldW, oldH, + newX, newY, newW, newH); + + if (((code ^ (code >> 1)) & 1) == 0) + { + /* Both dimensions are either getting larger, or both + are getting smaller. No need to copy anything. */ + + if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) + { + /* Since the window is getting smaller, we can do gravity + repair on it with it's current size, then resize it + afterwards. */ + + resize_after = TRUE; + } + + gResizeDeathCount = 1; + } + else + { + unsigned int copy_rowbytes, Bpp; + + /* We can get away with a partial copy. 'rect' is the + intersection between old and new bounds, so copy + everything to the right of or below the intersection. */ + + RootlessStartDrawing (pWin); + + if (code == WIDTH_SMALLER) + { + copy_rect.x1 = rect.x2; + copy_rect.y1 = rect.y1; + copy_rect.x2 = oldX2; + copy_rect.y2 = oldY2; + } + else if (code == HEIGHT_SMALLER) + { + copy_rect.x1 = rect.x1; + copy_rect.y1 = rect.y2; + copy_rect.x2 = oldX2; + copy_rect.y2 = oldY2; + } + else + abort (); + + Bpp = winRec->win->drawable.bitsPerPixel / 8; + copy_rowbytes = (((copy_rect.x2 - copy_rect.x1) * Bpp) + 31) & ~31; + gResizeDeathBits = xalloc (copy_rowbytes + * (copy_rect.y2 - copy_rect.y1)); + + xp_copy_bytes ((copy_rect.x2 - copy_rect.x1) * Bpp, + copy_rect.y2 - copy_rect.y1, ((char *) winRec->data) + + ((copy_rect.y1 - oldY) * winRec->rowbytes) + + (copy_rect.x1 - oldX) * Bpp, winRec->rowbytes, + gResizeDeathBits, copy_rowbytes); + + gResizeDeathBounds[1] = copy_rect; + gResizeDeathPix[1] + = GetScratchPixmapHeader(pScreen, copy_rect.x2 - copy_rect.x1, + copy_rect.y2 - copy_rect.y1, + winRec->win->drawable.depth, + winRec->win->drawable.bitsPerPixel, + winRec->rowbytes, + (void *) gResizeDeathBits); + + TranslatePixmapBase (gResizeDeathPix[1], + -copy_rect.x1, -copy_rect.y1); + + gResizeDeathCount = 2; + } + } + else if (gravity) + { + /* The general case. Just copy everything. */ + + RootlessStartDrawing (pWin); + + gResizeDeathBits = xalloc(winRec->rowbytes * winRec->height); + + memcpy(gResizeDeathBits, winRec->data, + winRec->rowbytes * winRec->height); + + gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2}; + gResizeDeathPix[0] + = GetScratchPixmapHeader(pScreen, winRec->width, + winRec->height, + winRec->win->drawable.depth, + winRec->win->drawable.bitsPerPixel, + winRec->rowbytes, + (void *) gResizeDeathBits); + + TranslatePixmapBase (gResizeDeathPix[0], -oldX, -oldY); + gResizeDeathCount = 1; + } + + RootlessStopDrawing (pWin, FALSE); + + winRec->x = newX; + winRec->y = newY; + winRec->width = newW; + winRec->height = newH; + winRec->borderWidth = newBW; + + /* Unless both dimensions are getting smaller, Resize the frame + before doing gravity repair */ + + if (!resize_after) + resize_frame (pScreen, pWin, winRec, weight); + + RootlessStartDrawing(pWin); + + /* If necessary, create a source pixmap pointing at the current + window bits. */ + + if (need_window_source) + { + gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2}; + gResizeDeathPix[0] + = GetScratchPixmapHeader (pScreen, oldW, oldH, + winRec->win->drawable.depth, + winRec->win->drawable.bitsPerPixel, + winRec->rowbytes, winRec->data); + + TranslatePixmapBase (gResizeDeathPix[0], -oldX, -oldY); + } + + /* Use custom CopyWindow when moving gravity bits around + ResizeWindow assumes the old window contents are in the same + pixmap, but here they're in deathPix instead. */ + + if (gravity) + { + gResizeOldCopyWindowProc = pScreen->CopyWindow; + pScreen->CopyWindow = RootlessResizeCopyWindow; + } + + /* If we can't rely on the window server preserving the bits we + need in the position we need, copy the pixels in the + intersection from src to dst. ResizeWindow assumes these pixels + are already present when making gravity adjustments. pWin + currently has new-sized pixmap but is in old position. + + FIXME: border width change! (?) */ + + if (gravity && weight == XP_GRAVITY_NONE) + { + PixmapPtr src, dst; + + assert (gResizeDeathCount == 1); + + src = gResizeDeathPix[0]; + dst = pScreen->GetWindowPixmap(pWin); + + RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n", + rect.x1, rect.y1, rect.x2, rect.y2); + + /* rect is the intersection of the old location and new location */ + if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) + { + int dx, dy; + + /* The window drawable still has the old frame position, which + means that DST doesn't actually point at the origin of our + physical backing store when adjusted by the drawable.x,y + position. So sneakily adjust it temporarily while copying.. */ + + dx = newX - oldX; + dy = newY - oldY; + TranslatePixmapBase (dst, -dx, -dy); + + fbCopyWindowProc(&src->drawable, &dst->drawable, NULL, + &rect, 1, 0, 0, FALSE, FALSE, 0, 0); + + TranslatePixmapBase (dst, dx, dy); + } + } + + return resize_after; +} + +static void +FinishFrameResize (WindowPtr pWin, Bool gravity, int oldX, int oldY, + unsigned int oldW, unsigned int oldH, unsigned int oldBW, + int newX, int newY, unsigned int newW, unsigned int newH, + unsigned int newBW, Bool resize_now) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + BoxRec box; + int i; + + RootlessStopDrawing (pWin, FALSE); + + if (resize_now) + { + unsigned int weight; + + /* We didn't resize anything earlier, so do it now, now that + we've finished gravitating the bits. */ + + weight = resize_weighting (oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + resize_frame (pScreen, pWin, winRec, weight); + } + + /* Redraw everything. FIXME: there must be times when we don't need + to do this. Perhaps when top-left weighting and no gravity? */ + + box.x1 = 0; + box.y1 = 0; + box.x2 = winRec->width; + box.y2 = winRec->height; + + xp_mark_window (winRec->wid, 1, &box, 0, 0); + + for (i = 0; i < 2; i++) + { + if (gResizeDeathPix[i] != NULL) + { + FreeScratchPixmapHeader (gResizeDeathPix[i]); + gResizeDeathPix[i] = NULL; + } + } + + if (gResizeDeathBits != NULL) + { + xfree (gResizeDeathBits); + gResizeDeathBits = NULL; + } + + if (gravity) + pScreen->CopyWindow = gResizeOldCopyWindowProc; +} + +/* If kind==VTOther, window border is resizing (and borderWidth is + already changed!!@#$) This case works like window resize, not move. */ +void +RootlessMoveWindow (WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + CopyWindowProcPtr oldCopyWindowProc = NULL; + + int oldX = 0, oldY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0; + int newX = 0, newY = 0; + unsigned int newW = 0, newH = 0, newBW = 0; + + Bool resize_after = FALSE; + RegionRec saveRoot; + + RL_DEBUG_MSG("movewindow start \n"); + + if (winRec != NULL) + { + if (kind == VTMove) + { + oldX = winRec->x; + oldY = winRec->y; + RootlessRedisplay (pWin); + RootlessStartDrawing (pWin); + } + else + { + RL_DEBUG_MSG("movewindow border resizing "); + + oldBW = winRec->borderWidth; + oldX = winRec->x; + oldY = winRec->y; + oldW = winRec->width; + oldH = winRec->height; + + newBW = wBorderWidth (pWin); + newX = x; + newY = y; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + + resize_after = StartFrameResize (pWin, FALSE, + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + } + + HUGE_ROOT (pWin); + SCREEN_UNWRAP (pScreen, MoveWindow); + + oldCopyWindowProc = pScreen->CopyWindow; + + if (winRec != NULL) + pScreen->CopyWindow = RootlessNoCopyWindow; + + pScreen->MoveWindow (pWin, x, y, pSib, kind); + + if (winRec != NULL) + pScreen->CopyWindow = oldCopyWindowProc; + + NORMAL_ROOT (pWin); + SCREEN_WRAP (pScreen, MoveWindow); + + if (winRec != NULL) + { + if (kind == VTMove) + { + xp_window_changes wc; + int sx, sy; + + RootlessStopDrawing (pWin, FALSE); + + winRec->x = x; + winRec->y = y; + + sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + wc.x = sx + winRec->x; + wc.y = sy + winRec->y; + + configure_window (winRec->wid, XP_ORIGIN, &wc); + } + else + { + FinishFrameResize (pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW, resize_after); + } + } + + RL_DEBUG_MSG("movewindow end\n"); +} + + +/* Note: (x, y, w, h) as passed to this procedure don't match the frame + definition. (x,y) is corner of very outer edge, *outside* border + w,h is width and height *inside* border, *ignoring* border width + The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw) + is total rect (x+bw, y+bw, w, h) is inner rect */ +void +RootlessResizeWindow (WindowPtr pWin, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec saveRoot; + + int oldX = 0, oldY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0; + int newX = 0, newY = 0; + unsigned int newW = 0, newH = 0, newBW = 0; + + Bool resize_after = FALSE; + + RL_DEBUG_MSG("resizewindow start (win 0x%x)\n", pWin); + + if (winRec != NULL) + { + oldBW = winRec->borderWidth; + oldX = winRec->x; + oldY = winRec->y; + oldW = winRec->width; + oldH = winRec->height; + + newBW = oldBW; + newX = x; + newY = y; + newW = w + 2*newBW; + newH = h + 2*newBW; + + resize_after = StartFrameResize (pWin, TRUE, + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT (pWin); + SCREEN_UNWRAP (pScreen, ResizeWindow); + + if (!IsRoot (pWin)) + { + pScreen->ResizeWindow (pWin, x, y, w, h, pSib); + } + else + { + BoxRec box; + + /* mi won't resize the root. So do it ourselves... */ + + pWin->drawable.x = x; + pWin->drawable.y = y; + pWin->drawable.width = w; + pWin->drawable.height = h; + + box.x1 = x; box.y1 = y; + box.x2 = x + w; box.y2 = y + h; + REGION_UNINIT (pScreen, &pWin->winSize); + REGION_INIT (pScreen, &pWin->winSize, &box, 1); + REGION_COPY (pScreen, &pWin->borderSize, &pWin->winSize); + REGION_COPY (pScreen, &pWin->clipList, &pWin->winSize); + REGION_COPY (pScreen, &pWin->borderClip, &pWin->winSize); + + miSendExposures (pWin, &pWin->borderClip, + pWin->drawable.x, pWin->drawable.y); + } + + SCREEN_WRAP (pScreen, ResizeWindow); + NORMAL_ROOT (pWin); + + if (winRec != NULL) + { + FinishFrameResize (pWin, TRUE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW, resize_after); + } + + RL_DEBUG_MSG("resizewindow end\n"); +} + +void +RootlessRepositionWindow (WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC (pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + xp_window_changes wc; + int sx, sy; + + if (IsRoot (pWin)) + set_screen_origin (pWin); + + if (winRec == NULL) + return; + + RootlessStopDrawing (pWin, FALSE); + + sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + wc.x = sx + winRec->x; + wc.y = sy + winRec->y; + + if (!rootlessHasRoot (pScreen)) + wc.window_level = normal_window_levels[winRec->level]; + else + wc.window_level = rooted_window_levels[winRec->level]; + + configure_window (winRec->wid, XP_ORIGIN | XP_WINDOW_LEVEL, &wc); + + RootlessReorderWindow (pWin); +} + +void +RootlessFlushWindowColormap (WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC (pWin); + xp_window_changes wc; + + if (winRec == NULL) + return; + + RootlessStopDrawing (pWin, FALSE); + + /* This is how we tell xp that the colormap may have changed. */ + + wc.colormap = rootlessColormapCallback; + wc.colormap_data = pWin->drawable.pScreen; + + configure_window (winRec->wid, XP_COLORMAP, &wc); +} + +/* Set the Pixmaps on all ParentRelative windows up the ancestor chain. */ +static void +SetPixmapOfAncestors (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr topWin = TopLevelParent (pWin); + RootlessWindowRec *topWinRec = WINREC (topWin); + XID pixel; + + while (pWin->backgroundState == ParentRelative) + { + if (pWin == topWin) + { + /* disallow ParentRelative background state on top level */ + + pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + + RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin); + break; + } + + pWin = pWin->parent; + pScreen->SetWindowPixmap (pWin, topWinRec->pixmap); + } +} + +/* RootlessPaintWindowBackground + Paint the window background while filling in the alpha channel + with all on. */ +void +RootlessPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREEN_UNWRAP (pScreen, PaintWindowBackground); + + RL_DEBUG_MSG("paintwindowbackground start (win 0x%x, framed %i)\n", + pWin, IsFramedWindow(pWin)); + + if (IsFramedWindow (pWin)) + { + /* Don't bother trying to paint the surface background.. */ + rootlessNoDRIDrawing++; + + RootlessStartDrawing (pWin); + RootlessDamageRegion (pWin, pRegion); + + /* For ParentRelative windows, we have to make sure the window + pixmap is set correctly all the way up the ancestor chain. */ + + if (pWin->backgroundState == ParentRelative) + SetPixmapOfAncestors (pWin); + + pScreen->PaintWindowBackground (pWin, pRegion, what); + + rootlessNoDRIDrawing--; + } + + SCREEN_WRAP (pScreen, PaintWindowBackground); + + RL_DEBUG_MSG("paintwindowbackground end\n"); +} + + +/* RootlessPaintWindowBorder + Paint the window border while filling in the alpha channel with all on. */ +void +RootlessPaintWindowBorder (WindowPtr pWin, RegionPtr pRegion, int what) +{ + SCREEN_UNWRAP (pWin->drawable.pScreen, PaintWindowBorder); + + RL_DEBUG_MSG("paintwindowborder start (win 0x%x)\n", pWin); + + if (IsFramedWindow (pWin)) + { + RootlessStartDrawing (pWin); + RootlessDamageRegion (pWin, pRegion); + + /* For ParentRelative windows with tiled borders, we have to make + sure the window pixmap is set correctly all the way up the + ancestor chain. */ + + if (!pWin->borderIsPixel && pWin->backgroundState == ParentRelative) + SetPixmapOfAncestors (pWin); + } + + pWin->drawable.pScreen->PaintWindowBorder (pWin, pRegion, what); + + SCREEN_WRAP (pWin->drawable.pScreen, PaintWindowBorder); + + RL_DEBUG_MSG("paintwindowborder end\n"); +} + + +/* FIXME: untested! + pWin inside corner stays the same; pWin->drawable.[xy] stays the same + frame moves and resizes */ +void +RootlessChangeBorderWidth (WindowPtr pWin, unsigned int width) +{ + RegionRec saveRoot; + Bool resize_after = FALSE; + + RL_DEBUG_MSG("change border width\n"); + + if ((int) width != wBorderWidth (pWin)) + { + RootlessWindowRec *winRec = WINREC(pWin); + + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0; + unsigned int newW = 0, newH = 0, newBW = 0; + + if (winRec != NULL) + { + oldBW = winRec->borderWidth; + oldX = winRec->x; + oldY = winRec->y; + oldW = winRec->width; + oldH = winRec->height; + + newBW = width; + newX = pWin->drawable.x - newBW; + newY = pWin->drawable.y - newBW; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + + resize_after = StartFrameResize (pWin, FALSE, + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT (pWin); + SCREEN_UNWRAP (pWin->drawable.pScreen, ChangeBorderWidth); + + pWin->drawable.pScreen->ChangeBorderWidth (pWin, width); + + SCREEN_WRAP (pWin->drawable.pScreen, ChangeBorderWidth); + NORMAL_ROOT (pWin); + + if (winRec != NULL) + { + FinishFrameResize (pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW, resize_after); + } + } + + RL_DEBUG_MSG("change border width end\n"); +} + +/* + * RootlessFillRegionTiled + * Fill using a tile while leaving the alpha channel untouched. + * Based on fbfillRegionTiled. + */ +static void +RootlessFillRegionTiled( + DrawablePtr pDrawable, + RegionPtr pRegion, + PixmapPtr pTile) +{ + FbBits *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + FbBits *tile; + FbStride tileStride; + int tileBpp; + int tileXoff, tileYoff; /* XXX assumed to be zero */ + int tileWidth, tileHeight; + int n = REGION_NUM_RECTS(pRegion); + BoxPtr pbox = REGION_RECTS(pRegion); + int xRot = pDrawable->x; + int yRot = pDrawable->y; + FbBits planeMask; + +#ifdef PANORAMIX + if(!noPanoramiXExtension) + { + int index = pDrawable->pScreen->myNum; + if(&WindowTable[index]->drawable == pDrawable) + { + xRot -= panoramiXdataPtr[index].x; + yRot -= panoramiXdataPtr[index].y; + } + } +#endif + fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + fbGetDrawable (&pTile->drawable, tile, tileStride, tileBpp, + tileXoff, tileYoff); + tileWidth = pTile->drawable.width; + tileHeight = pTile->drawable.height; + xRot += dstXoff; + yRot += dstYoff; + planeMask = FB_ALLONES & ~RootlessAlphaMask(dstBpp); + + while (n--) + { + fbTile (dst + (pbox->y1 + dstYoff) * dstStride, + dstStride, + (pbox->x1 + dstXoff) * dstBpp, + (pbox->x2 - pbox->x1) * dstBpp, + pbox->y2 - pbox->y1, + tile, + tileStride, + tileWidth * dstBpp, + tileHeight, + GXcopy, + planeMask, + dstBpp, + xRot * dstBpp, + yRot - pbox->y1); + pbox++; + } +} + +/* + * RootlessPaintWindow + * Paint the window while filling in the alpha channel with all on. + * We can't use fbPaintWindow because it zeros the alpha channel. + */ +void +RootlessPaintWindow( + WindowPtr pWin, + RegionPtr pRegion, + int what) +{ + switch (what) { + case PW_BACKGROUND: + + switch (pWin->backgroundState) { + case None: + break; + case ParentRelative: + do { + pWin = pWin->parent; + } while (pWin->backgroundState == ParentRelative); + (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion, + what); + break; + case BackgroundPixmap: + RootlessFillRegionTiled (&pWin->drawable, + pRegion, + pWin->background.pixmap); + break; + case BackgroundPixel: + { + Pixel pixel = pWin->background.pixel | + RootlessAlphaMask(pWin->drawable.bitsPerPixel); + fbFillRegionSolid (&pWin->drawable, pRegion, 0, + fbReplicatePixel (pixel, + pWin->drawable.bitsPerPixel)); + break; + } + } + break; + case PW_BORDER: + if (pWin->borderIsPixel) + { + Pixel pixel = pWin->border.pixel | + RootlessAlphaMask(pWin->drawable.bitsPerPixel); + fbFillRegionSolid (&pWin->drawable, pRegion, 0, + fbReplicatePixel (pixel, + pWin->drawable.bitsPerPixel)); + } + else + { + WindowPtr pBgWin; + for (pBgWin = pWin; pBgWin->backgroundState == ParentRelative; + pBgWin = pBgWin->parent); + + RootlessFillRegionTiled (&pBgWin->drawable, + pRegion, + pWin->border.pixmap); + } + break; + } + fbValidateDrawable (&pWin->drawable); +}