/*
 * topproc.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" 

/* 
 * XSetWindowAttributes
 */

XSetWindowAttributes defAttrs = {
    None,		/* backfround pixmap */ 
    RGB(255, 255, 255),	/* background pixel */
    None, 		/* border pixmap */	
    0L, 		/* border pixel */
    ForgetGravity, 	/* bit gravity */
    NorthWestGravity, 	/* window gravity */
    NotUseful,		/* backing store */
    0, 			/* backing planes */
    0, 			/* backing pixel */
    False, 		/* save under */
    0L, 		/* even tmask */
    0L, 		/* do not propagate mask */
    False, 		/* override redirect */
    None, 		/* colormap */
    None		/* cursor */
};

/* 
 * XWindowChanges
 */

XWindowChanges defChanges = {
    0, 		/* x */
    0, 		/* y */
    1, 		/* width */
    1, 		/* height */
    1, 		/* border width */
    None, 	/* sibling */
    Above,	/* stack mode */
    FALSE	/* pos_changed */
};

/* 
 *	RegisterTopLevelClass -- 
 *	
 *	
 */

void
RegisterTopLevelClass(HINSTANCE hInstance)
{
    WNDCLASS wndclass;

    wndclass.style	   = 0; /* CS_HREDRAW | CS_VREDRAW */
    wndclass.lpfnWndProc   = TopLevelProc;
    wndclass.cbClsExtra    = 0;
    wndclass.cbWndExtra    = LAST_OFFSET;
    wndclass.hInstance     = hInstance;
    // wndclass.hIcon	   = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hIcon	   = NULL;
    wndclass.hCursor       = NULL;
    wndclass.hbrBackground = NULL;
    wndclass.lpszMenuName  = NULL;
    wndclass.lpszClassName = "TopLevel";

    RegisterClass(&wndclass);
}

/*
 *----------------------------------------------------------------------
 * SendActivate	--
 *
 *	Callback function for EnumChildWindows.
 *----------------------------------------------------------------------
 */
static BOOL 
SendActivate(HWND hwnd, LPARAM lParam)	
{
    SendMessage(hwnd, WM_ACTIVATE,  0, 0L);
    return 1;
}

/* 
 *----------------------------------------------------------------------
 *
 * DeleteProperty --
 * 
 *	Callback function for EnumProp
 *
 *----------------------------------------------------------------------
 */
static BOOL CALLBACK
DeleteProperty(HWND hwnd, LPCTSTR lpsz, HANDLE hData)	
{
    RemoveProp(hwnd, lpsz);
    GlobalFree(hData);
    return 1;
}

/*
 *----------------------------------------------------------------------
 *
 * TopLevelProc --
 *
 *	Windows messages for Toplevel windows pass through this
 *	routine.
 *
 *----------------------------------------------------------------------
 */
 	
LRESULT CALLBACK
TopLevelProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HGLOBAL hXSWAttrs, hXWChanges, hWork;
    XSetWindowAttributes * pXSWAttrs;
    XWindowChanges * pXWChanges;
    WINDOWPOS * pWndPos;
    HCURSOR cs;
    MSG msg;
    XEvent xev;
    Display *display;
    UINT newmessage;
    char propName[8];
    char *ptr;

    switch(message) {
    case WM_SYSCOLORCHANGE:
	PostMessage(hwnd, SYSCOLORNOTIFY, (WPARAM) hwnd, 0L); 
	break;

    case WM_SYSCOMMAND:
	switch (wParam & 0xFFF0) {
	case SC_MINIMIZE:
	    PostMessage(hwnd, UNMAPNOTIFY, 0, 0L); 
	    break;
	case SC_MAXIMIZE:
	case SC_RESTORE:
	    if (IsIconic(hwnd)) {
		PostMessage(hwnd, MAPNOTIFY, 0, 0L); 
	    }
	    break;
	}
	break;

    case WM_CREATE:
	/* XSetWindowAttributes */
    	hXSWAttrs = GlobalAlloc(GHND, sizeof(XSetWindowAttributes));
	pXSWAttrs = (XSetWindowAttributes *) GlobalLock(hXSWAttrs);
	memcpy(pXSWAttrs, &defAttrs, sizeof(XSetWindowAttributes));
	GlobalUnlock(hXSWAttrs);
	/* XWindowChanges */
	hXWChanges = GlobalAlloc(GHND, sizeof(XWindowChanges));
	pXWChanges = (XWindowChanges *) GlobalLock(hXWChanges);
	memcpy(pXWChanges, &defChanges, sizeof(XWindowChanges));
	GlobalUnlock(hXWChanges);

    	SetWindowLong(hwnd, XSWA_OFFSET, (LONG) hXSWAttrs);
	SetWindowLong(hwnd, XWCH_OFFSET, (LONG) hXWChanges);
	PostMessage(hwnd, CREATENOTIFY,  wParam, lParam); 
	return 0;
  
    case WM_ACTIVATE:
#if 0
	if (wParam != WA_INACTIVE) { 
    	    PostMessage(hwnd, EXPOSE, 0, 0L);

 	    EnumChildWindows(hwnd, MakeProcInstance(SendActivate, GetAppInstance()), 0L);
	}
#endif
	break;

    case WM_SETFOCUS:
	PostMessage(hwnd, FOCUSIN, wParam, 0L); 
	return 0;
	
    case WM_KILLFOCUS:
	PostMessage(hwnd, FOCUSOUT, wParam, 0L); 
	return 0;

    case WM_WINDOWPOSCHANGED:
	// printf("2. Iconic: 0x%x %d\n", hwnd, (IsIconic(hwnd)? 1 : 0) );
	break;
	
    case WM_WINDOWPOSCHANGING:
	// printf("1. Iconic: 0x%x %d\n", hwnd, (IsIconic(hwnd)? 1 : 0) );
	if (IsIconic(hwnd)) {
	    break;
	}
    	hWork = GlobalAlloc(LHND, sizeof(WINDOWPOS));
	pWndPos = (WINDOWPOS *) GlobalLock(hWork);
	memcpy(pWndPos, (WINDOWPOS *)lParam, sizeof(WINDOWPOS));

	hXWChanges = (HGLOBAL) GetWindowLong(hwnd, XWCH_OFFSET);
	pXWChanges = (XWindowChanges *) GlobalLock(hXWChanges);

    	hXSWAttrs = (HGLOBAL) GetWindowLong(hwnd, XSWA_OFFSET);
	pXSWAttrs = (XSetWindowAttributes *) GlobalLock(hXSWAttrs);
	if (pWndPos->flags & SWP_NOMOVE) {
	     pWndPos->x = pXWChanges->x;
	     pWndPos->y = pXWChanges->y;
	} else {
	     pXWChanges->x = pWndPos->x = ReAdjustX(pWndPos->x, pXSWAttrs->override_redirect);
	     pXWChanges->y = pWndPos->y = ReAdjustY(pWndPos->y, pXSWAttrs->override_redirect);
	}
	if (pWndPos->flags & SWP_NOSIZE) {
	     pWndPos->cx = pXWChanges->width;
	     pWndPos->cy = pXWChanges->height;
	} else {

	     pXWChanges->width = pWndPos->cx = ReAdjustWidth(pWndPos->cx, pXSWAttrs->override_redirect);
	     pXWChanges->height = pWndPos->cy = ReAdjustHeight(pWndPos->cy, pXSWAttrs->override_redirect);
	}
	GlobalUnlock(hWork);
	GlobalUnlock(hXWChanges);
	GlobalUnlock(hXSWAttrs);

	PostMessage(hwnd, CONFIGURENOTIFY, (WPARAM) hWork, XOpenDisplay(NULL)->request); 

	break;

    case WM_GETMINMAXINFO:
	sprintf(propName, "#0x%0.4x", XA_WM_NORMAL_HINTS);
	hWork = GetProp(hwnd, propName);
    	if (hWork != NULL) {
	    XSizeHints *pHints;
	    MINMAXINFO *lpmmi;

	    lpmmi = (MINMAXINFO *) lParam;
	    ptr = ((char *) GlobalLock(hWork)) + sizeof(Atom);
	    pHints = (XSizeHints *) ptr;

    	    hXSWAttrs = (HGLOBAL) GetWindowLong(hwnd, XSWA_OFFSET);
	    pXSWAttrs = (XSetWindowAttributes *) GlobalLock(hXSWAttrs);
	    if (!(pHints->flags & USSize)) {
	    	if (pHints->flags & PMinSize) {
	    	    lpmmi->ptMinTrackSize.x = 
	    	    	    AdjustWidth(pHints->min_width, pXSWAttrs->override_redirect);
		    lpmmi->ptMinTrackSize.y = 
			    AdjustHeight(pHints->min_height, pXSWAttrs->override_redirect);
	    	}
	    	if (pHints->flags & PMaxSize) {
	    	    lpmmi->ptMaxTrackSize.x = 
			    AdjustWidth(pHints->max_width, pXSWAttrs->override_redirect);
		    lpmmi->ptMaxTrackSize.y = 
			    AdjustHeight(pHints->max_height, pXSWAttrs->override_redirect);
	    	}
	    }
	    GlobalUnlock(hWork);
	    GlobalUnlock(hXSWAttrs);
	}
	break;

    case WM_SIZE:
    	switch (wParam) {
    	case SIZE_MINIMIZED:
	    display = XOpenDisplay(NULL);
	    UpdateXIcon(display, hwnd);
	    sprintf(propName, "#0x%0.4x", XA_WM_ICON_NAME);
	    hWork = GetProp(hwnd, propName);
	    break;
	case SIZE_MAXIMIZED:
	case SIZE_RESTORED: 
	    sprintf(propName, "#0x%0.4x", XA_WM_NAME);
	    hWork = GetProp(hwnd, propName);
	    break;
	default:
	    hWork = NULL;
	}
	if (hWork != NULL) {
	    char * p;

	    p = ((char *) GlobalLock(hWork)) + sizeof(Atom);
	    SetWindowText(hwnd, p);
	    GlobalUnlock(hWork);
	}
	return 0;

    case WM_MOUSEMOVE: 
    	if ((cs = (HGLOBAL) GetWindowLong(hwnd, HCCS_OFFSET)) == NULL) {
	    cs = FindCursor(hwnd);
	    SetWindowLong(hwnd, HCCS_OFFSET, (LONG) cs);
	}
	SetCursor(cs);				    
	return 0; 

    case WM_ACTIVATEAPP:
    	if (wParam == 0) {
	    PostMessage(hwnd, ACTIVATEAPP, 0, 0L);
	}
	return 0;

    case WM_NCLBUTTONUP:
    case WM_NCMBUTTONUP:
    case WM_NCRBUTTONUP:
    case WM_NCLBUTTONDOWN:
    case WM_NCMBUTTONDOWN:
    case WM_NCRBUTTONDOWN:
    case WM_NCLBUTTONDBLCLK:
    case WM_NCMBUTTONDBLCLK:
    case WM_NCRBUTTONDBLCLK:
    	// if (pointerGrabbed) {
	    /* Need to generate a button event that the application can see */
	    msg.message = message;
	    msg.time = GetCurrentTime();
	    msg.wParam = wParam;
	    msg.lParam = lParam;
	    msg.hwnd = hwnd;

	    display = XOpenDisplay(NULL);
	    if (msg3event(display, &msg, &xev)) {
		putEvent(display, &xev);
		PostMessage(hwnd, EVENTADDED, 0, 0L);
	    }
	    switch (message) {
	    case WM_NCLBUTTONDOWN:
	    case WM_NCLBUTTONDBLCLK:
		newmessage = WM_NCLBUTTONUP;
		break;
	    case WM_NCMBUTTONDOWN:
	    case WM_NCMBUTTONDBLCLK:
		newmessage = WM_NCMBUTTONUP;
		break;
	    case WM_NCRBUTTONDOWN:
	    case WM_NCRBUTTONDBLCLK:
		newmessage = WM_NCRBUTTONUP;
		break;
	    default:
		newmessage = 0;
	    }
	    msg.message = newmessage;
	    if (newmessage != 0 && msg3event(display, &msg, &xev)) {
		putEvent(display, &xev);
		PostMessage(hwnd, EVENTADDED, 0, 0L);
	    }
	    
	    // return 0;
	// }
	break;
	 
    case WM_CLOSE:
    	PostMessage(hwnd, CLIENTMESSAGE, (WPARAM) hwnd, 0L);
	return 0;

    case WM_DESTROY: 
    	GlobalFree((HGLOBAL) GetWindowLong(hwnd, XSWA_OFFSET));
	GlobalFree((HGLOBAL) GetWindowLong(hwnd, XWCH_OFFSET));
	EnumProps(hwnd, DeleteProperty);
	return 0;

    case WM_PAINT:
	if (! IsIconic(hwnd)) {
	    /* Non-iconic WM_PAINT events are handled in msg2event.c
	     * (EXPOSE==WM_PAINT)
	     */
	    return 0;
	}
	/* fall through */

    case WM_PAINTICON:
	display = XOpenDisplay(NULL);
	UpdateXIcon(display, hwnd);
	return 0;

    case WM_ERASEBKGND:
	if (IsIconic(hwnd)) {
	    return TRUE;
	}
	break;

    case WM_QUERYDRAGICON:
	display = XOpenDisplay(NULL);
	return ((LRESULT) (UINT) GetXIcon(display, hwnd));


    }

    DefWindowProc(hwnd, message, wParam, lParam);
}
