/*
 *Copyright (C) 1994-2000 The XFree86 Project, 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 XFREE86 PROJECT 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 of the XFree86 Project
 *shall not be used in advertising or otherwise to promote the sale, use
 *or other dealings in this Software without prior written authorization
 *from the XFree86 Project.
 *
 * Authors:	Kensuke Matsuzaki
 *		Earle F. Philhower, III
 *		Harold L Hunt II
 */

#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#endif
#include "win.h"
#include "winprefs.h"

#if 0
/*
 * winMWExtWMReorderWindows
 */

void
winMWExtWMReorderWindows (ScreenPtr pScreen)
{
  winScreenPriv(pScreen);
  HWND hwnd = NULL;
  win32RootlessWindowPtr pRLWin = NULL;
  win32RootlessWindowPtr pRLWinSib = NULL;
  DWORD dwCurrentProcessID = GetCurrentProcessId ();
  DWORD dwWindowProcessID = 0;
  XID vlist[2];

#if CYGMULTIWINDOW_DEBUG && FALSE
  winDebug ("winMWExtWMReorderWindows\n");
#endif

  pScreenPriv->fRestacking = TRUE;

  if (pScreenPriv->fWindowOrderChanged)
    {
#if CYGMULTIWINDOW_DEBUG
      winDebug ("winMWExtWMReorderWindows - Need to restack\n");
#endif
      hwnd = GetTopWindow (NULL);

      while (hwnd)
	{
	  GetWindowThreadProcessId (hwnd, &dwWindowProcessID);

	  if ((dwWindowProcessID == dwCurrentProcessID)
	      && GetProp (hwnd, WIN_WINDOW_PROP))
	    {
	      pRLWinSib = pRLWin;
	      pRLWin = (win32RootlessWindowPtr)GetProp (hwnd, WIN_WINDOW_PROP);
	      
	      if (pRLWinSib)
		{
		  vlist[0] = pRLWinSib->pFrame->win->drawable.id;
		  vlist[1] = Below;

		  ConfigureWindow (pRLWin->pFrame->win, CWSibling | CWStackMode,
				   vlist, wClient(pRLWin->pFrame->win));
		}
	      else
		{
		  /* 1st window - raise to the top */
		  vlist[0] = Above;

		  ConfigureWindow (pRLWin->pFrame->win, CWStackMode,
				   vlist, wClient(pRLWin->pFrame->win));
		}
	    }
	  hwnd = GetNextWindow (hwnd, GW_HWNDNEXT);
	}
    }

  pScreenPriv->fRestacking = FALSE;
  pScreenPriv->fWindowOrderChanged = FALSE;
}
#endif


/*
 * winMWExtWMMoveXWindow
 */

void
winMWExtWMMoveXWindow (WindowPtr pWin, int x, int y)
{
  CARD32 *vlist = malloc(sizeof(CARD32)*2);

  vlist[0] = x;
  vlist[1] = y;
  ConfigureWindow (pWin, CWX | CWY, vlist, wClient(pWin));
  free(vlist);
}


/*
 * winMWExtWMResizeXWindow
 */

void
winMWExtWMResizeXWindow (WindowPtr pWin, int w, int h)
{
  CARD32 *vlist = malloc(sizeof(CARD32)*2);

  vlist[0] = w;
  vlist[1] = h;
  ConfigureWindow (pWin, CWWidth | CWHeight, vlist, wClient(pWin));
  free(vlist);
}


/*
 * winMWExtWMMoveResizeXWindow
 */

void
winMWExtWMMoveResizeXWindow (WindowPtr pWin, int x, int y, int w, int h)
{
  CARD32 *vlist = malloc(sizeof(long)*4);

  vlist[0] = x;
  vlist[1] = y;
  vlist[2] = w;
  vlist[3] = h;

  ConfigureWindow (pWin, CWX | CWY | CWWidth | CWHeight, vlist, wClient(pWin));
  free(vlist);
}


/*
 * winMWExtWMUpdateIcon
 * Change the Windows window icon
 */

void
winMWExtWMUpdateIcon (Window id)
{
  WindowPtr		pWin;
  HICON			hIcon, hiconOld;

  pWin = LookupIDByType (id, RT_WINDOW);
  hIcon = (HICON)winOverrideIcon ((unsigned long)pWin);

  if (!hIcon)
    hIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXICON));

  if (hIcon)
    {
      win32RootlessWindowPtr pRLWinPriv
	= (win32RootlessWindowPtr) RootlessFrameForWindow (pWin, FALSE);

      if (pRLWinPriv->hWnd)
	{
	  hiconOld = (HICON) SetClassLong (pRLWinPriv->hWnd,
					   GCL_HICON,
					   (int) hIcon);
	  
          winDestroyIcon(hiconOld);
	}
    }
}


/*
 * winMWExtWMDecorateWindow - Update window style. Called by EnumWindows.
 */

wBOOL CALLBACK
winMWExtWMDecorateWindow (HWND hwnd, LPARAM lParam)
{
  win32RootlessWindowPtr pRLWinPriv = NULL;
  ScreenPtr		pScreen = NULL;
  winPrivScreenPtr	pScreenPriv = NULL;
  winScreenInfo		*pScreenInfo = NULL;

  /* Check if the Windows window property for our X window pointer is valid */
  if ((pRLWinPriv = (win32RootlessWindowPtr)GetProp (hwnd, WIN_WINDOW_PROP)) != NULL)
    {
      pScreen				= pRLWinPriv->pFrame->win->drawable.pScreen;
      if (pScreen) pScreenPriv		= winGetScreenPriv(pScreen);
      if (pScreenPriv) pScreenInfo	= pScreenPriv->pScreenInfo;
      if (pRLWinPriv && pScreenInfo) winMWExtWMUpdateWindowDecoration (pRLWinPriv, pScreenInfo);
    }
  return TRUE;
}


/*
 * winMWExtWMUpdateWindowDecoration - Update window style.
 */

void
winMWExtWMUpdateWindowDecoration (win32RootlessWindowPtr pRLWinPriv,
				  winScreenInfoPtr pScreenInfo)
{
  Bool		fDecorate = FALSE;
  DWORD		dwExStyle = 0;
  DWORD		dwStyle = 0;
  WINDOWPLACEMENT wndPlace;
  UINT		showCmd = 0;

  wndPlace.length = sizeof (WINDOWPLACEMENT);

  /* Get current window placement */
  GetWindowPlacement (pRLWinPriv->hWnd, &wndPlace);

  if (winIsInternalWMRunning(pScreenInfo))
    {
      if (!pRLWinPriv->pFrame->win->overrideRedirect)
	fDecorate = TRUE;
    }
#if 0
  if (wndPlace.showCmd == SW_HIDE)
    return;//showCmd = SWP_HIDEWINDOW;
  else
    showCmd = SWP_SHOWWINDOW;
#else
  if (wndPlace.showCmd == SW_HIDE)
    return;

  if (IsWindowVisible (pRLWinPriv->hWnd))
    showCmd = SWP_SHOWWINDOW;
#endif

  showCmd |= SWP_NOMOVE | SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER;

  winDebug ("winMWExtWMUpdateWindowDecoration %08x %s\n",
	    (int)pRLWinPriv, fDecorate?"Decorate":"Bare");

  /* Get the standard and extended window style information */
  dwExStyle = GetWindowLongPtr (pRLWinPriv->hWnd, GWL_EXSTYLE);
  dwStyle = GetWindowLongPtr (pRLWinPriv->hWnd, GWL_STYLE);

  if (fDecorate)
    {
      RECT		rcNew;
      int		iDx, iDy;
      winWMMessageRec	wmMsg;
      winScreenPriv(pScreenInfo->pScreen);

      /* */
      if (!(dwExStyle & WS_EX_APPWINDOW))
	{
	  winDebug ("\tBare=>Decorate\n");
	  /* Setup a rectangle with the X window position and size */
	  SetRect (&rcNew,
		   pRLWinPriv->pFrame->x,
		   pRLWinPriv->pFrame->y,
		   pRLWinPriv->pFrame->x + pRLWinPriv->pFrame->width,
		   pRLWinPriv->pFrame->y + pRLWinPriv->pFrame->height);

#ifdef CYGMULTIWINDOW_DEBUG
          winDebug("\tWindow extend {%d, %d, %d, %d}, {%d, %d}\n", 
              rcNew.left, rcNew.top, rcNew.right, rcNew.bottom,
              rcNew.right - rcNew.left, rcNew.bottom - rcNew.top);
#endif
	  /* */
	  AdjustWindowRectEx (&rcNew,
			      WS_POPUP | WS_SIZEBOX | WS_OVERLAPPEDWINDOW,
			      FALSE,
			      WS_EX_APPWINDOW);

#ifdef CYGMULTIWINDOW_DEBUG
          winDebug("\tAdjusted {%d, %d, %d, %d}, {%d, %d}\n", 
              rcNew.left, rcNew.top, rcNew.right, rcNew.bottom,
              rcNew.right - rcNew.left, rcNew.bottom - rcNew.top);
#endif
	  /* Calculate position deltas */
	  iDx = pRLWinPriv->pFrame->x - rcNew.left;
	  iDy = pRLWinPriv->pFrame->y - rcNew.top;

	  /* Calculate new rectangle */
	  rcNew.left += iDx;
	  rcNew.right += iDx;
	  rcNew.top += iDy;
	  rcNew.bottom += iDy;

	  /* Set the window extended style flags */
	  SetWindowLongPtr (pRLWinPriv->hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW);

	  /* Set the window standard style flags */
	  SetWindowLongPtr (pRLWinPriv->hWnd, GWL_STYLE,
			    WS_POPUP | WS_SIZEBOX | WS_OVERLAPPEDWINDOW);

#ifdef CYGMULTIWINDOW_DEBUG
          winDebug("\tWindowStyle: %08x %08x\n",
              WS_POPUP | WS_SIZEBOX | WS_OVERLAPPEDWINDOW,
              WS_EX_APPWINDOW);
#endif
	  /* Position the Windows window */
#ifdef CYGMULTIWINDOW_DEBUG
          winDebug("\tMoved {%d, %d, %d, %d}, {%d, %d}\n", 
              rcNew.left, rcNew.top, rcNew.right, rcNew.bottom,
              rcNew.right - rcNew.left, rcNew.bottom - rcNew.top);
#endif
	  SetWindowPos (pRLWinPriv->hWnd, NULL,
			rcNew.left, rcNew.top,
			rcNew.right - rcNew.left, rcNew.bottom - rcNew.top,
			showCmd);
            

	  wmMsg.hwndWindow = pRLWinPriv->hWnd;
	  wmMsg.iWindow	= (Window)pRLWinPriv->pFrame->win->drawable.id;
	  wmMsg.msg = WM_WM_NAME_EVENT;
	  winSendMessageToWM (pScreenPriv->pWMInfo, &wmMsg);

	  winMWExtWMReshapeFrame ((RootlessFrameID)pRLWinPriv ,
				  wBoundingShape(pRLWinPriv->pFrame->win));
	}
    }
  else
    {
      RECT		rcNew;

      /* */
      if (dwExStyle & WS_EX_APPWINDOW)
	{
	  winDebug ("\tDecorate=>Bare\n");
	  /* Setup a rectangle with the X window position and size */
	  SetRect (&rcNew,
		   pRLWinPriv->pFrame->x,
		   pRLWinPriv->pFrame->y,
		   pRLWinPriv->pFrame->x + pRLWinPriv->pFrame->width,
		   pRLWinPriv->pFrame->y + pRLWinPriv->pFrame->height);
#if 0
	  /* */
	  AdjustWindowRectEx (&rcNew,
			      WS_POPUP | WS_CLIPCHILDREN,
			      FALSE,
			      WS_EX_TOOLWINDOW);

	  /* Calculate position deltas */
	  iDx = pRLWinPriv->pFrame->x - rcNew.left;
	  iDy = pRLWinPriv->pFrame->y - rcNew.top;

	  /* Calculate new rectangle */
	  rcNew.left += iDx;
	  rcNew.right += iDx;
	  rcNew.top += iDy;
	  rcNew.bottom += iDy;
#endif

	  /* Hide window temporary to remove from taskbar. */
	  ShowWindow( pRLWinPriv->hWnd, SW_HIDE );

	  /* Set the window extended style flags */
	  SetWindowLongPtr (pRLWinPriv->hWnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);

	  /* Set the window standard style flags */
	  SetWindowLongPtr (pRLWinPriv->hWnd, GWL_STYLE,
			    WS_POPUP | WS_CLIPCHILDREN);

	  /* Position the Windows window */
	  SetWindowPos (pRLWinPriv->hWnd, NULL,
			rcNew.left, rcNew.top,
			rcNew.right - rcNew.left, rcNew.bottom - rcNew.top,
			showCmd);

	  winMWExtWMReshapeFrame ((RootlessFrameID)pRLWinPriv ,
				  wBoundingShape(pRLWinPriv->pFrame->win));
	}
    }
}


/*
 * winIsInternalWMRunning (winScreenInfoPtr pScreenInfo)
 */
Bool
winIsInternalWMRunning (winScreenInfoPtr pScreenInfo)
{
  return pScreenInfo->fInternalWM && !pScreenInfo->fAnotherWMRunning;
}


/*
 * winMWExtWMRestackWindows
 */

void
winMWExtWMRestackWindows (ScreenPtr pScreen)
{
  winScreenPriv(pScreen);
  WindowPtr pRoot = WindowTable[pScreen->myNum];
  WindowPtr pWin = NULL;
  WindowPtr pWinPrev = NULL;
  win32RootlessWindowPtr pRLWin = NULL;
  win32RootlessWindowPtr pRLWinPrev = NULL;
  int  nWindow = 0;
  HDWP hWinPosInfo = NULL;

#if CYGMULTIWINDOW_DEBUG
  winDebug ("winMWExtWMRestackWindows\n");
#endif

  pScreenPriv->fRestacking = TRUE;

  if (pRoot != NULL)
    {
      for (pWin = pRoot->firstChild; pWin; pWin = pWin->nextSib)
	nWindow ++;

      hWinPosInfo = BeginDeferWindowPos(nWindow);

      for (pWin = pRoot->firstChild; pWin; pWin = pWin->nextSib)
	{
	  if (pWin->realized)
	    {
	      UINT uFlags;

	      pRLWin = (win32RootlessWindowPtr) RootlessFrameForWindow (pWin, FALSE);
	      if (pRLWin == NULL) continue;

	      if (pWinPrev)
		pRLWinPrev = (win32RootlessWindowPtr) RootlessFrameForWindow (pWinPrev, FALSE);

	      uFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW;
	      if (pRLWinPrev != NULL) uFlags |= SWP_NOACTIVATE;

#if CYGMULTIWINDOW_DEBUG
	      winDebug ("winMWExtWMRestackWindows - DeferWindowPos (%08x, %08x)\n",
			pRLWin->hWnd,
			pRLWinPrev ? pRLWinPrev->hWnd : HWND_TOP);
#endif
	      hWinPosInfo = DeferWindowPos (hWinPosInfo, pRLWin->hWnd,
					    pRLWinPrev ? pRLWinPrev->hWnd : HWND_TOP,
					    0, 0, 0, 0,
					    uFlags);
	      if (hWinPosInfo == NULL)
		{
		  ErrorF ("winMWExtWMRestackWindows - DeferWindowPos () failed: %d\n",
			  (int) GetLastError ());
		  return;
		}
	      pWinPrev = pWin;
	    }
	}
      if (!EndDeferWindowPos (hWinPosInfo))
	{
	  ErrorF ("winMWExtWMRestackWindows - EndDeferWindowPos () failed: %d\n",
		  (int) GetLastError ());
	  return;
	}
    }

#if CYGMULTIWINDOW_DEBUG
  winDebug ("winMWExtWMRestackWindows - done\n");
#endif
  pScreenPriv->fRestacking = FALSE;
}