/*
 * window.c --
 *
 * Copyright (c) 1994 Software Research Associates, Inc.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.  Software Research
 * Associates makes no representations about the suitability of this software
 * for any purpose.  It is provided "as is" without express or implied
 * warranty.
 */

#include "xlibInt.h" 

extern HCURSOR hDefaultCursor;

static void ReStack(HWND, HWND, int);

/*
 *----------------------------------------------------------------------
 *
 * _SetWindowChanges --
 *
 *	Modify the XWindowChanges structure that is associated with
 *	the window.  Only the fields that are specified by bits in
 *	'mask' are affected.  The window may be moved, resized, 
 *	repositioned, or restacked.
 *
 * Result:
 *	Success if OK, BadWindow if the window is invalid
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */

unsigned char
_SetWindowChanges(Window w, unsigned long mask, XWindowChanges * changes)
{
    XWindowChanges *pXWChanges;
    HGLOBAL hXWChanges;
    XSetWindowAttributes *pXSWAttrs;
    HGLOBAL hXSWAttrs;
    HWND hwnd = (HWND) w;
    UINT flag = SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOSIZE;

    hXWChanges = (HGLOBAL) GetWindowLong(hwnd, XWCH_OFFSET);
    pXWChanges = (XWindowChanges *) GlobalLock(hXWChanges);
    if (pXWChanges == NULL) {
    	return BadWindow;
    }

    hXSWAttrs = (HGLOBAL) GetWindowLong(hwnd, XSWA_OFFSET);
    pXSWAttrs = (XSetWindowAttributes *) GlobalLock(hXSWAttrs);
    if (pXSWAttrs == NULL) {
    	return BadWindow;
    }

    if (mask & CWX) {
	pXWChanges->x = changes->x;
	flag &= ~SWP_NOMOVE;
    }
    if (mask & CWY) {
	pXWChanges->y = changes->y;
	flag &= ~SWP_NOMOVE;
    }
    if (mask & CWWidth)	{
    	pXWChanges->width = changes->width;
	flag &= ~SWP_NOSIZE;
    }
    if (mask & CWHeight) {
    	pXWChanges->height = changes->height;
	flag &= ~SWP_NOSIZE;
    }
    if (mask & CWBorderWidth) {
	pXWChanges->border_width = changes->border_width;
    }
    if (mask & CWSibling) {
      	pXWChanges->sibling = changes->sibling;
    }
    if (mask & CWStackMode) {
    	pXWChanges->stack_mode = changes->stack_mode;
    }
 	
    if (GetParent(hwnd) == HWND_DESKTOP || pXSWAttrs->override_redirect) {

	/*
	 * If the window is iconic, we need to update the window attributes
	 * here.
	 */
	 
	if (IsIconic(hwnd)) {
	    HGLOBAL hXSWAttrs;
	    XSetWindowAttributes * pXSWAttrs;
	    HGLOBAL *hWndPos;
	    WINDOWPOS *pWndPos;

	    hWndPos = GlobalAlloc(LHND, sizeof(WINDOWPOS));
	    pWndPos = (WINDOWPOS *) GlobalLock(hWndPos);

	    hXSWAttrs = (HGLOBAL) GetWindowLong(hwnd, XSWA_OFFSET);
	    pXSWAttrs = (XSetWindowAttributes *) GlobalLock(hXSWAttrs);

	    pXWChanges->pos_changed = TRUE;
	    pWndPos->x = pXWChanges->x;
	    pWndPos->y = pXWChanges->y;
	    pWndPos->cx = pXWChanges->width;
	    pWndPos->cy = pXWChanges->height;

	    GlobalUnlock(hXSWAttrs);
	    GlobalUnlock(hWndPos);
	    PostMessage(hwnd, CONFIGURENOTIFY, (WPARAM) hWndPos,
			XOpenDisplay(NULL)->request); 
	} else {

	    MoveWindow(hwnd, 
		AdjustX(pXWChanges->x, pXSWAttrs->override_redirect),
		AdjustY(pXWChanges->y, pXSWAttrs->override_redirect),
   		AdjustWidth(pXWChanges->width, pXSWAttrs->override_redirect), 
   	    	AdjustHeight(pXWChanges->height, pXSWAttrs->override_redirect),
		TRUE);
	    EnterLeave(hwnd, 0, 0, 1 /* windowMoved */);
	}
    } else {
   	MoveWindow(hwnd, pXWChanges->x, pXWChanges->y, 
   		pXWChanges->width, pXWChanges->height, TRUE);
	EnterLeave(hwnd, 0, 0, 1 /* windowMoved */);
    }

    if (mask & CWStackMode) {
    	ReStack(hwnd,
		(HWND) (mask&CWSibling?pXWChanges->sibling:None),
		pXWChanges->stack_mode);
    }

    GlobalUnlock(hXWChanges);
    GlobalUnlock(hXSWAttrs);
    return Success;
}

/*
 *----------------------------------------------------------------------
 *
 * ReStack --
 *
 *	Reposition a window in the window stack
 *
 * Result:
 *	None
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
static void
ReStack(HWND hwnd, HWND hwndSibling, int mode)
{
    HWND hwndInsertAfter;

    if (hwndSibling == None) {
	hwndInsertAfter = (mode == Above) ? HWND_TOP : HWND_BOTTOM;
    } else {
        if (mode == Above) {
	    SetWindowPos(hwnd, hwndSibling, 0, 0, 0, 0, 
			 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
	    hwndInsertAfter = hwnd;
	    hwnd = hwndSibling;
        } else {
	    hwndInsertAfter = hwndSibling;
	}
    }
    SetWindowPos(hwnd, hwndInsertAfter, 0, 0, 0, 0, 
		 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
}


/*
 *----------------------------------------------------------------------
 *
 * _SetWindowAttributes --
 *
 *	Modify the XSetWindowAttributes structure that is associated with
 *	the window.  Only the fields that are specified by bits in
 *	'mask' are affected.  No changes that directly affect the window's
 *	appearance on the screen are made here.
 *
 * Result:
 *	Success if OK, BadWindow if the window is invalid
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */

unsigned char 
_SetWindowAttributes(Window w, unsigned long mask, XSetWindowAttributes * attrs)
{
    XSetWindowAttributes * pXSWAttrs;
    HGLOBAL hXSWAttrs;
    HWND hwnd = (HWND) w;

    hXSWAttrs = (HGLOBAL) GetWindowLong(hwnd, XSWA_OFFSET);
    pXSWAttrs = (XSetWindowAttributes *) GlobalLock(hXSWAttrs);
    if (pXSWAttrs == NULL) {
    	return BadWindow;
    }

    if (mask & CWBackPixmap) {
	pXSWAttrs->background_pixmap = attrs->background_pixmap;
    }
    if (mask & CWBackPixel) {
	pXSWAttrs->background_pixel = attrs->background_pixel;
    }
    if (mask & CWBorderPixmap) {
	pXSWAttrs->border_pixmap = attrs->border_pixmap;
    }
    if (mask & CWBorderPixel) {
	pXSWAttrs->border_pixel = attrs->border_pixel;
    }
    if (mask & CWBitGravity) {
	pXSWAttrs->bit_gravity = attrs->bit_gravity;
    }
    if (mask & CWWinGravity) {
	pXSWAttrs->win_gravity = attrs->win_gravity;
    }
    if (mask & CWBackingStore) {
	pXSWAttrs->backing_store = attrs->backing_store;
    }
    if (mask & CWBackingPlanes) {
	pXSWAttrs->backing_planes = attrs->backing_planes;
    }
    if (mask & CWBackingPixel) {
	pXSWAttrs->backing_pixel = attrs->backing_pixel;
    }
    if (mask & CWOverrideRedirect) {
	pXSWAttrs->override_redirect = attrs->override_redirect;
    }
    if (mask & CWSaveUnder) {
	pXSWAttrs->save_under = attrs->save_under;
    }
    if (mask & CWEventMask) {
	pXSWAttrs->event_mask = attrs->event_mask;
    }
    if (mask & CWDontPropagate) {
	pXSWAttrs->do_not_propagate_mask = attrs->do_not_propagate_mask;
    }
    if (mask & CWColormap) {
	pXSWAttrs->colormap = attrs->colormap;
    }
    if (mask & CWCursor) {
    	SetWindowLong(hwnd, HPCS_OFFSET, (LONG) pXSWAttrs->cursor);  
	SetWindowLong(hwnd, HCCS_OFFSET, (LONG) attrs->cursor);
	pXSWAttrs->cursor = attrs->cursor;
    }

    GlobalUnlock(hXSWAttrs);

    return Success;
}

/*
 *----------------------------------------------------------------------
 *
 * _GetWindowAttributes --
 *
 *	Copy the XSetWindowAttributes structure that is associated with
 *	the window to the structure that is passed in.
 *
 * Result:
 *	Success if OK, BadWindow if the window is invalid
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
unsigned char 
_GetWindowAttributes(Window w, XWindowChanges *attrs_return)
{
    XWindowChanges *pXWChanges;
    HGLOBAL hXWChanges;
    HWND hwnd = (HWND) w;

    hXWChanges = (HGLOBAL) GetWindowLong(hwnd, XWCH_OFFSET);
    pXWChanges = (XWindowChanges *) GlobalLock(hXWChanges);
    if (pXWChanges == NULL) {
    	return BadWindow;
    }

    memcpy(attrs_return, pXWChanges, sizeof(XWindowChanges));
    GlobalUnlock(hXWChanges);
    return Success;
}
