////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// mark@danks.org
//
// Implementation file
//
//    Copyright (c) 1997-1999 Mark Danks.
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

#include "GemWinCreate.h"
#include <m_pd.h>
#include <X11/cursorfont.h>
#define EVENT_MASK  \
 ExposureMask|StructureNotifyMask|PointerMotionMask|ButtonMotionMask | \
 ButtonReleaseMask | ButtonPressMask


// window creation variables
static int snglBuf24[] = {GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 16, None};
static int dblBuf24[] = {GLX_RGBA, GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None};
static int snglBuf8[] = {GLX_RGBA, GLX_RED_SIZE, 3, GLX_GREEN_SIZE, 3, GLX_BLUE_SIZE, 2, GLX_DEPTH_SIZE, 16, None};
static int dblBuf8[] = {GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 2, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None};


Bool WaitForNotify(Display *, XEvent *e, char *arg)
{
    return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
}

int createGemWindow(WindowInfo &info, WindowHints &hints)
{
    if ( (info.dpy = XOpenDisplay(NULL)) == NULL)
    { 
	    error("GEM: Could not open display");
	    return(0);
    }
    
    XVisualInfo *vi;
    // the user wants double buffer
    if (hints.buffer == 2)
    {
	    // try for a double-buffered on 24bit machine
	    vi = glXChooseVisual(info.dpy, DefaultScreen(info.dpy), dblBuf24);
	    if (vi == NULL)
	    {
	        // try for a double buffered on a 8bit machine
	        vi = glXChooseVisual(info.dpy, DefaultScreen(info.dpy), dblBuf8);
	        if (vi == NULL)
	        {
	    	    error("GEM: Unable to create double buffer window");
                destroyGemWindow(info);
	    	    return(0);
	        }
	        post("GEM: Only using 8 color bits");
	    }
    }
    // the user wants single buffer
    else
    {
	    // try for a single buffered on a 24bit machine
	    vi = glXChooseVisual(info.dpy, DefaultScreen(info.dpy), snglBuf24);
	    if (vi == NULL)
	    {
	        // try for a single buffered on a 8bit machine
	        vi = glXChooseVisual(info.dpy, DefaultScreen(info.dpy), snglBuf8);
	        if (vi == NULL)
	        {
		        error("GEM: Unable to create single buffer window");
                destroyGemWindow(info);
		        return(0);
	        }
	        post("GEM: Only using 8 color bits");
	    }
        hints.buffer = 1;
    }

    if (vi->c_class != TrueColor)
    {
	    error("GEM: TrueColor visual required for this program");
        destroyGemWindow(info);
	    return(0);
    }
    
    // create the rendering context
    info.context = glXCreateContext(info.dpy, vi, hints.shared, GL_TRUE);
    if (info.context == NULL)
    {
	    error("GEM: Could not create rendering context");
        destroyGemWindow(info);
	    return(0);
    }
    
    // create the X color map
    info.cmap = XCreateColormap(info.dpy, RootWindow(info.dpy, vi->screen), 
		vi->visual, AllocNone);
    if (!info.cmap)
    {
        error("GEM: Could not create X colormap");
        destroyGemWindow(info);
        return(0);
    }

    XSetWindowAttributes swa;
    swa.colormap = info.cmap;
    swa.border_pixel = 0;
    // event_mask creates signal that window has been created
    swa.event_mask = EVENT_MASK;
   
    // create the X window
    info.win = XCreateWindow(info.dpy, RootWindow(info.dpy, vi->screen),
	     0, 0, hints.width, hints.height, 0, vi->depth, InputOutput, 
	     vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa);
    if (!info.win)
    {
        error("GEM: Could not create X window");
        destroyGemWindow(info);
        return(0);
    }

    XSelectInput(info.dpy, info.win, EVENT_MASK);   
    XSetStandardProperties(info.dpy, info.win, "gem", "gem", None, 0, 0, NULL);

    glXMakeCurrent(info.dpy, info.win, info.context);   
    
    if (!hints.actuallyDisplay) return(1);

    XMapWindow(info.dpy, info.win);
    XEvent report;
    XIfEvent(info.dpy, &report, WaitForNotify, (char*)info.win);


    return(1);
}

int cursorGemWindow(WindowInfo &info, int state)
{
    if (!state) {
      static char data[1] =
      {0};
      Cursor cursor;
      Pixmap blank;
      XColor dummy;
      
      blank = XCreateBitmapFromData(info.dpy, info.win,
				    data, 1, 1);

      cursor = XCreatePixmapCursor(info.dpy, blank, blank,
				   &dummy, &dummy, 0, 0);
      XFreePixmap(info.dpy, blank);
      
      post("no cursor");
      XDefineCursor(info.dpy, info.win,cursor);
    }
    else
	 XUndefineCursor(info.dpy, info.win);
	 
}

void destroyGemWindow(WindowInfo &info)
{
    if (info.dpy)
    {
        if (info.win)
            XDestroyWindow(info.dpy, info.win);
        if (info.context)
            glXDestroyContext(info.dpy, info.context);
        if (info.cmap)
            XFreeColormap(info.dpy, info.cmap);
        XCloseDisplay(info.dpy);
    }

    info.dpy = NULL;
    info.win = 0;
    info.cmap = 0;
    info.context = NULL;
}
