

#include "WINGsP.h"

#include <X11/Xresource.h>

#define EVENT_MASK  \
	KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
	EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
	VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|\
	SubstructureNotifyMask|SubstructureRedirectMask


static XSetWindowAttributes defAtts= {
    None,                       /* background_pixmap */
    0,                          /* background_pixel */
    CopyFromParent,             /* border_pixmap */
    0,                          /* border_pixel */
    NorthWestGravity,           /* bit_gravity */
    NorthWestGravity,           /* win_gravity */
    NotUseful,                  /* backing_store */
    (unsigned) ~0,              /* backing_planes */
    0,                          /* backing_pixel */
    False,                      /* save_under */
    EVENT_MASK,   	         /* event_mask */
    0,                          /* do_not_propagate_mask */
    False,                      /* override_redirect */
    CopyFromParent,             /* colormap */
    None                        /* cursor */
};




static XContext ViewContext=0;	       /* context for views */



W_View*
W_GetViewForXWindow(Display *display, Window window)
{
    W_View *view;
    
    if (XFindContext(display, window, ViewContext, (XPointer*)&view)==0) {
	return view;
    }
    return NULL;
}




static W_View*
createView(W_Screen *screen, W_View *parent)
{
    W_View *view;

    if (ViewContext==0)
	ViewContext = XUniqueContext();
    
    
    view = wmalloc(sizeof(W_View));
    memset(view, 0, sizeof(W_View));
    
    view->screen = screen;
    view->attribFlags = CWEventMask|CWColormap|CWBitGravity;
    view->attribs = defAtts;
    view->parent = parent;

    view->attribFlags |= CWBackPixel;
    view->attribs.background_pixel = screen->lightPixel;

    if (parent!=NULL) {
	if (parent->childrenList == NULL) {
	    parent->childrenList = view;
	} else {
	    W_View *ptr;
	    
	    ptr = parent->childrenList;
	    while (ptr->nextSister!=NULL) 
		ptr = ptr->nextSister;
	    ptr->nextSister = view;
	}
    }
    
    return view;
}



W_View*
W_CreateView(W_View *parent)
{
    
    return createView(parent->screen, parent);
}


W_View*
W_CreateTopView(W_Screen *screen)
{
    W_View *view;
    
    view = createView(screen, NULL);
    if (!view)
	return NULL;
	
    view->attribs.event_mask |= StructureNotifyMask;
    
    return view;
}



void
W_RealizeView(W_View *view)
{
    Window parent;
    Display *dpy = view->screen->display;
    W_View *ptr;
    
    if (view->flags.realized)
	return;
    
    if (view->parent && !view->parent->flags.realized) {
	wWarning("trying to realize a child of a unrealized window");
	return;
    }
    

    if (view->parent == NULL) {
#ifdef WMAKER
	parent = view->wmakerParent;
#else
	parent = view->screen->rootWin;
#endif
    } else
	parent = view->parent->window;
    
    view->window = XCreateWindow(dpy, parent, view->pos.x, view->pos.y,
				 view->size.width, view->size.height, 0, 
				 view->screen->depth, InputOutput,
				 view->screen->visual, view->attribFlags,
				 &view->attribs);
    
    XSaveContext(dpy, view->window, ViewContext, (XPointer)view);
    
    view->flags.realized = 1;
    
    /* realize children */
    ptr = view->childrenList;
    while (ptr!=NULL) {
	W_RealizeView(ptr);
	
	ptr = ptr->nextSister;
    }
}



void
W_DestroyView(W_View *view)
{
    W_View *ptr;
    

    
    /* destroy children recursively */
    while (view->childrenList!=NULL) {
	ptr = view->childrenList;
	ptr->flags.parentDying = 1;
	
	W_DestroyView(ptr);
	
	if (ptr == view->childrenList) {
	    view->childrenList = ptr->nextSister;
	    ptr->parent = NULL;
	}
    }
    
    
    W_CallDestroyHandlers(view);
    

    if (view->flags.realized) {
	XDeleteContext(view->screen->display, view->window, ViewContext);
    
	/* if parent is being destroyed, it will die naturaly */
	if (!view->flags.parentDying || view->parent==NULL)
	    XDestroyWindow(view->screen->display, view->window);
    }
    
    /* remove self from parent's children list */
    if (view->parent!=NULL) {
	ptr = view->parent->childrenList;
	if (ptr == view) {
	    view->parent->childrenList = view->nextSister;
	} else {
	    while (ptr!=NULL) {
		if (ptr->nextSister == view) {
		    ptr->nextSister = view->nextSister;
		    break;
		} 
		ptr = ptr->nextSister;
	    }
	}
    }

    W_CleanUpEvents(view);

    free(view);
}



void
W_MoveView(W_View *view, int x, int y)
{
    if (view->flags.realized) {
	XMoveWindow(view->screen->display, view->window, x, y);
    } else {
	view->pos.x = x;
	view->pos.y = y;
    }
}



int
W_ConfigureViewArg(W_View *view, WMArgument *arg)
{
    switch (arg->argument) {
     case WARG_X:
	view->pos.x = (long)arg->value;
	break;
	
     case WARG_Y:
	view->pos.y = (long)arg->value;
	break;
	
     case WARG_WIDTH:
	if ((long)arg->value < 1) {
	    wWarning(_("invalid %s value for a widget"), _("width"));
	    break;
	}
	view->size.width = (long)arg->value;
	break;
	
     case WARG_HEIGHT:
	if ((long)arg->value < 1) {
	    wWarning(_("invalid %s value for a widget"), _("height"));
	    break;
	}
	view->size.height = (long)arg->value;
	break;
     default:
	return False;
    }
    return True;
}



void 
W_BroadcastMessage(W_View *targetParent, XEvent *event)
{
    W_View *target;
    
    target = targetParent->childrenList;
    while (target!=NULL) {
	W_DispatchMessage(target, event);
	
	target = target->nextSister;
    }
}

void 
W_DispatchMessage(W_View *target, XEvent *event)
{
    if (target->window==None)
	return;
    event->xclient.window = target->window;
    XSendEvent(target->screen->display, target->window, False,
	       SubstructureNotifyMask, event);
}
