/*
 * glxf.c: subroutines to make it easier to use opengl and xforms together
 * This code is meant to be generic and should not have to be changed (much).
 *
 * Adapted from Andrew Willmott's glxforms.cc,
 * which is currently in /afs/cs/project/anim/ajw/public/glxforms.tar.gz
 *
 * Paul Heckbert	16 Oct 1995, 21 Sept 1998
 */

#include <assert.h>
#include <stdio.h>
#include "glxf.h"

static int is_map_notify(Display *foo, XEvent *event, char *arg)
{
    return event->type==MapNotify && event->xmap.window==(Window)arg;
}

void create_gl_subwindow(Glxf_pane *pane, Window parent,
int x, int y, int width, int height, int *attrlist) {
    /* Create a sub-window of the parent window, for Opengl use */

    unsigned long winmask;
    XSetWindowAttributes winattr;
    XEvent event;
    Colormap colormap;
    Display *display;
    XVisualInfo *visinfo;

    display = XOpenDisplay(0);

    visinfo = glXChooseVisual(display, DefaultScreen(display), attrlist);
    if (!visinfo) {
	fprintf(stderr, "unable to open an X Window of the type requested -- asking for too many bits?\n");
	exit(1);
    }

    if (visinfo->class==TrueColor || visinfo->class==DirectColor) {
	printf("glxf: creating colormap\n");
	colormap = XCreateColormap(display,
	    RootWindow(display, visinfo->screen), visinfo->visual, AllocNone);

	/*
	 * note: if you try to create a window with a 24 bit visual when the
	 * default visual is 8 bits (or more precisely, when the parent window
	 * has a different visual or depth) and you don't explicitly set the
	 * colormap and border, you will die with a BadMatch error.
	 * You can thank the brain-damaged designers of X Windows for this.
	 */
	winattr.colormap = colormap;
	winattr.border_pixel = 0;
	winmask = CWBorderPixel | CWColormap | CWEventMask;
    }
    else {
	/* printf("glxf: not creating colormap\n"); */

	/* when using Mesa's implementation of OpenGL, and requesting a
	 * 24 bit visual but running on an 8 bit display, we don't want to
	 * create an X colormap, since Mesa is doing that for us.
	 */
	winmask = CWEventMask;
    }
    winattr.event_mask = StructureNotifyMask;

    /* create the subwindow */
    pane->display = display;
    pane->window = XCreateWindow(display, parent,
	/*origin*/ x, y, /*width,height*/ width, height,
	/*borderwidth*/ 0, /*depth*/ visinfo->depth, /*class*/ InputOutput,
	visinfo->visual,
	/*window attribute mask*/ winmask, &winattr);

    /* tell window manager to draw the window */
    XMapWindow(display, pane->window);

    /* Wait for MapNotify event when the window is first drawn */
    XIfEvent(display, &event, is_map_notify, (char *)pane->window);

    /* Create a graphics context if it hasn't been done before */
    /* Bind the X window to an OpenGL context */
    pane->context = glXCreateContext(display, visinfo,
	/*context share list*/ 0, /*direct rendering?*/ GL_TRUE);
    assert(pane->context);
    assert(glXMakeCurrent(display, pane->window, pane->context));

    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_DEPTH_TEST);	/* turn on z-buffering */

    pane->width = width;
    pane->height = height;
}

static int event_dispatch(XEvent *event, void *data) {
    /* call event handler for the pane in which the event occurred */
    ((Glxf_pane *)data)->handle_event(event);
    return 1;
}

void glxf_bind_pane(Glxf_pane *pane, FL_OBJECT *object,
    int *attrlist, void (*handle_event)(XEvent *event))
{
    const int inset = 4;

    pane->handle_event = handle_event;

    create_gl_subwindow(pane, FL_OBJECT_WID(object), object->x + inset,
	object->y + inset, object->w - 2 * inset, object->h - 2 * inset,
	attrlist);

    /* call pane->handle_event routine when window uncovered (Expose event)
     * mouse button pressed (ButtonPress), or key pressed (KeyPress)
     * or other things happen
     */
    fl_add_event_callback(pane->window, /*event type (0 means all)*/ 0,
	event_dispatch, pane);

    fl_activate_event_callbacks(pane->window);
}

