/* Widget set category implementation of Window class
 *
 * Copyright (C)  1994  The Board of Trustees of  
 * The Leland Stanford Junior University.  All Rights Reserved.
 *
 * Authors: Scott Francis, Paul Kunz, Tom Pavel, 
 *	    Imran Qureshi, and Libing Wang
 *          Mike Kienenberger (Alaska)
 *
 * This file is part of an Objective-C class library for X/Motif
 *
 * xmWindow.m,v 1.36 1995/12/13 22:33:32 fedor Exp
 */

#include "Window.h"
#include "xtResponder.h"

/* Required for implementation: */
#include "Motif.h"
#include "Application.h"
#include "Menu.h"

#ifdef	RESIZE_DEBUG
#include <Xm/Xm.h>	/* Position, Dimension type declarations */
#endif	/* RESIZE_DEBUG */
#include <Xm/MainW.h>
#include <Xm/DialogS.h>

#ifdef HAVE_EDITRES
#include <X11/Xmu/Editres.h>
#endif

#define String X11String
#ifdef MOTIF12			/* MOTIF 1.2 */
#include <Xm/Protocols.h>
#else				/* MOTIF 1.1 */
#include <Xm/VendorE.h>		/* for XmIsMotifWMRunning() */
#include <X11/Protocols.h>	/* for mwm DELETE WINDOW protocol */
#include <Xm/AtomMgr.h>		/* for XmInternAtom() */
#endif
#undef String

#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <stdlib.h>             /* for free() */
#include "Scroller.h"
#include "dpsclient/dpsclient.h"	/* for backing types */
#include "dpsclient/xwfriends.h"
#include "appkit/stdmacros.h"
#include "objc/typedstream2.h"
#include <objc/List.h>

char *WindowInstanceName( void )
{
    return "Window";
}

/**************** comment out for now, until we use it *******************
static void
_window_will_resize_callback(Widget w, XtPointer client_data,
                          XmAnyCallbackStruct *cb)
{
    XConfigureEvent *config_event = (XConfigureEvent *) cb;
    Window *windowid = (Window *) client_data;

    NXRect aRect;
    
    if (config_event->type != ConfigureNotify) return;
    
    aRect.size.height = config_event->height;
    aRect.size.width = config_event->width;
    aRect.origin.x = config_event->x;
    aRect.origin.y = config_event->y;
    
    [windowid _resizeWindow:&aRect];
    return;
}
***************************************************************************/
static void
_window_will_close_callback(Widget w, XtPointer client_data,
			    XmAnyCallbackStruct *cb)
{
    Window *windowid = (Window *) client_data;

    if (nil == [windowid performClose:windowid])  return;
    
    /* else check to see if this is the last window -- if so exit()
     * since the application may be "lost" under X-windows otherwise
     */
    
    if (0 == [[NXApp windowList] count])  [NXApp terminate:windowid];
    
    return;
}

@interface View(WidgetSet)
- _flushView;
@end

@implementation Window(WidgetSet)

/* private methods not declared in interface file. */

- _setTitle
{
    if ( _shell ) {
        XtVaSetValues(_shell,
		      XtNiconName, title,
		      XtNtitle, title,
		      NULL);
    }
    return self;
} 

- _initFrame
{
#ifdef	RESIZE_DEBUG
    Position x,y;
    Dimension w,h;
#endif	/* RESIZE_DEBUG */
    Widget wid;
    Atom WM_DELETE_WINDOW;
    
    _shell = XtAppCreateShell( title, "App",
                               applicationShellWidgetClass,
                               [NXApp _X_display], NULL, 0  ); 
#ifdef HAVE_EDITRES
  /* Register the Editres protocol: */
    XtAddEventHandler( _shell, (EventMask) 0, True,
                       _XEditResCheckMessages, NULL);
#endif

    /* The frame includes space for the title bar and resize bar, but
       since the X window managers takes care of this, we subtract it out
       and ignore it */
    NX_X(&frame) += 1;
    NX_Y(&frame) += 9;
    NX_WIDTH(&frame) -= 2;
    NX_HEIGHT(&frame) -= (9 + 23);
    NX_X(&_contentViewFrameRect) -= 1;
    NX_Y(&_contentViewFrameRect) -= 9;
    [contentView setFrame:&_contentViewFrameRect];

    XtVaSetValues(_shell, XmNallowShellResize, False, NULL);
    widgetid = XmCreateMainWindow(_shell, "window1", NULL, 0);
    PSaddwindow(widgetid, NX_X(&frame), NX_Y(&frame), NX_WIDTH(&frame),
		NX_HEIGHT(&frame), wFlags.backing, &windowNum);
    XtManageChild(widgetid);
    XtVaSetValues(widgetid, XmNwidth,   NX_WIDTH(&frame),
		            XmNheight, NX_HEIGHT(&frame), NULL);

    if (!wFlags.visible)
	XtSetMappedWhenManaged((Widget)_shell, NO);

#ifdef	RESIZE_DEBUG
    XtVaGetValues(widgetid, XmNx, &x, NULL);
    XtVaGetValues(widgetid, XmNy, &y, NULL);
    XtVaGetValues(widgetid, XmNwidth, &w, NULL);
    XtVaGetValues(widgetid, XmNheight, &h, NULL);

    fprintf(stderr, "_initContent: widget size was (%d, %d), (%d, %d)\n",
          (int)x, (int)y, (int)w, (int)h);
#endif	/* RESIZE_DEBUG */

#ifndef	ALWAYS_MWM
    /* Might not require mwm at all                
    handle window close button -- currently requires Motif WM */
    if (True == XmIsMotifWMRunning(_shell))
#endif	/* ALWAYS_MWM */
    {
	/* first, disable mwm's default action for close buttons */
	XtVaSetValues(_shell, XmNdeleteResponse, XmDO_NOTHING, NULL);
	/* register WM_DELETE_WINDOW to call _window_will_close_callback */
	WM_DELETE_WINDOW = XmInternAtom([NXApp _X_display], "WM_DELETE_WINDOW",
					False);
	wid = widgetid;
	XmAddWMProtocolCallback(XtParent(wid), WM_DELETE_WINDOW,
	    (XtCallbackProc)_window_will_close_callback, (XtPointer)self);
    }
//    XtAddEventHandler(_shell, StructureNotifyMask, False,
//                  _window_will_resize_callback, (XtPointer)self);

    [self _setTitle];

    return self;
}

- _setWindowAreas
{
#ifdef	RESIZE_DEBUG
    Position x,y;
    Dimension w,h;
#endif	/* RESIZE_DEBUG */
    if (hasMenu) {
        if (!menu ) {
            menu = [NXApp mainMenu];
            [menu _managedBy:self];
	}
    } else {
        menu = nil;
    }
    [contentView _managedBy:self];
	
    XmMainWindowSetAreas(widgetid,
			[menu _widget],	/* Menubar */
                         NULL,          /* Command window */
                         NULL,    	/* Horizontal Scroller*/
                         NULL,          /* Vertical   */
                         [contentView _widget]);       /* Contents */

#ifdef	RESIZE_DEBUG
    XtVaGetValues(widgetid, XmNx, &x, NULL);
    XtVaGetValues(widgetid, XmNy, &y, NULL);
    XtVaGetValues(widgetid, XmNwidth, &w, NULL);
    XtVaGetValues(widgetid, XmNheight, &h, NULL);

    fprintf(stderr, "_setWindowAreas: widget size was (%d, %d), (%d, %d)\n",
          (int)x, (int)y, (int)w, (int)h);

    fprintf(stderr,
          "_setWindowAreas: contentView size was (%d, %d), (%d, %d)\n",
          _contentViewFrameRect.origin.x, _contentViewFrameRect.origin.y,
          _contentViewFrameRect.size.width,
          _contentViewFrameRect.size.height);

    XtVaGetValues([contentView _widget], XmNx, &x, NULL);
    XtVaGetValues([contentView _widget], XmNy, &y, NULL);
    XtVaGetValues([contentView _widget], XmNwidth, &w, NULL);
    XtVaGetValues([contentView _widget], XmNheight, &h, NULL);

    fprintf(stderr, "_setWindowAreas: widget size was (%d, %d), (%d, %d)\n",
          (int)x, (int)y, (int)w, (int)h);
#endif	/* RESIZE_DEBUG */

    return self;
}


- _windowExposed:(NXEvent *)theEvent;
{
 /* We got an expose event for a buffered window, so we
  * try to handle it by copying the backing pixmap to the window.
  * Since not all subviews draw to the backing store, only the
  * views can handle it.   -- Paul and Adam
  */
    if (windowNum == 0)
	return self;
    [contentView _flushView];
    return self;
}
    
/* Public methods */

 /*- closeWindow
{
    if (_holder) {
        XtDestroyWidget([self topLevel]);
        printf("%d\n", [self topLevel]);
    }
}  */
 
- _realize
{
#ifdef	RESIZE_DEBUG
    Position x,y;
    Dimension w,h;
#endif	/* RESIZE_DEBUG */
    XWContext context;

    if (XtIsRealized((Widget)_shell))
	return self;

    if ( !wFlags.visible) 
        return self;
    
    if (_shell) {
	XtRealizeWidget( (Widget)_shell);
    }

    // Change various window attributes
    context = (XWContext)[NXApp context];
    if (context->map && context->map->colormap) {
	XSetWindowColormap(context->display, 
			XtWindow((Widget)_shell), 
			context->map->colormap);
    }
    /* FIXME: why don't exposure events get generated? The man pages suggest 
       event handles need to be added after the widget is realized, but it
       still doesn't seem to work here.
    */
    [contentView display];
    hasRealized = YES;

#ifdef	RESIZE_DEBUG
    XtVaGetValues(widgetid, XmNx, &x, NULL);
    XtVaGetValues(widgetid, XmNy, &y, NULL);
    XtVaGetValues(widgetid, XmNwidth, &w, NULL);
    XtVaGetValues(widgetid, XmNheight, &h, NULL);

    fprintf(stderr, "_realize: widget size was (%d, %d), (%d, %d)\n",
          (int)x, (int)y, (int)w, (int)h);

    fprintf(stderr,
          "_realize: contentView size was (%d, %d), (%d, %d)\n",
          _contentViewFrameRect.origin.x, _contentViewFrameRect.origin.y,
          _contentViewFrameRect.size.width,
          _contentViewFrameRect.size.height);

    XtVaGetValues([contentView _widget], XmNx, &x, NULL);
    XtVaGetValues([contentView _widget], XmNy, &y, NULL);
    XtVaGetValues([contentView _widget], XmNwidth, &w, NULL);
    XtVaGetValues([contentView _widget], XmNheight, &h, NULL);

    fprintf(stderr, "_realize: widget size was (%d, %d), (%d, %d)\n",
          (int)x, (int)y, (int)w, (int)h);
#endif	/* RESIZE_DEBUG */
    return self;
}

- (BOOL) _hasRealized
{
    return hasRealized;
}

- _unrealize
{
    if ( wFlags.visible) 
	return self;

    if (_shell) {
	if (nil != contentView)  [contentView free];
	XtUnrealizeWidget( (Widget)_shell );
	_shell = 0;
    }
    hasRealized = NO;
    return self;
}

- _orderOut
{
    if (_shell)  XtUnmapWidget( (Widget)_shell);
    return self;
}

- _orderFront
{
    if (_shell)  XtMapWidget( (Widget)_shell);
    return self;
}

- (void *)_widget
{
    return widgetid;
}

- (void *)_shell
{
    return _shell;
}

@end

