// Xlib OpenGL support functions.
// Written by Sjur Julin.
// License: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication license
// https://www.in-a-vision.com

#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/XKBlib.h>

#define GLX_GLXEXT_PROTOTYPES
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h>

//#include "resource.h"
#include "glstuff.h"

#include <stdint.h>
#include <stdbool.h>



// gcc -lX11 -lGL -lGLU

extern int quit;
static int keys[256];

Display                 *dpy;
Window                  root;
GLint                   att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
XVisualInfo             *vi;
Colormap                cmap;
XSetWindowAttributes    swa;
Window                  win;
GLXContext              glc;
XWindowAttributes       gwa;
XEvent                  xev;

#include <stdio.h>

void handleEvent(){

 	XNextEvent(dpy, &xev);
	switch(xev.type) {
    case VisibilityNotify:
        XRaiseWindow(dpy, win);
        XFlush(dpy);
		break;
	case Expose:
		XGetWindowAttributes(dpy, win, &gwa);
		glViewport(0, 0, gwa.width, gwa.height);
		break;
	case KeyPress: {
		int keycode = ((XKeyEvent*)&xev)->keycode;
		KeySym keysym = XkbKeycodeToKeysym( dpy, keycode, 0, 0 );
//		int keycode = ((XKeyEvent*)&xev)->keycode;
//		int keysym = XKeycodeToKeysym(dpy, keycode, 0);
		if(keysym==XK_Escape) quit=1; else printf("Keysym: %X (%X)\n", (int)keysym, keycode);
		char key = (char)keysym;
		keys[key=1];
	}	break;
	case ButtonPress:
		break;
	case MapNotify:
		break;
	default:
		break;
	}
}

#define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
#define _NET_WM_STATE_ADD           1    /* add/set property */
#define _NET_WM_STATE_TOGGLE        2    /* toggle property  */


Status x11_window_set_on_top (Display* display, Window xid) {
    XEvent event;
    event.xclient.type = ClientMessage;
    event.xclient.serial = 0;
    event.xclient.send_event = True;
    event.xclient.display = display;
    event.xclient.window  = xid;
    event.xclient.message_type = XInternAtom (display, "_NET_WM_STATE", False);
    event.xclient.format = 32;

    event.xclient.data.l[0] = _NET_WM_STATE_ADD;
    event.xclient.data.l[1] = XInternAtom (display, "_NET_WM_STATE_ABOVE", False);
    event.xclient.data.l[2] = 0; //unused.
    event.xclient.data.l[3] = 0;
    event.xclient.data.l[4] = 0;

	return XSendEvent (display, DefaultRootWindow(display), False,
				SubstructureRedirectMask|SubstructureNotifyMask, &event);
}

static int CreateWin(int w, int h) {
//	w = 640; h = 360;
	dpy = XOpenDisplay(NULL);
	if(!dpy) {
 		puts("No connect X server.");
		return 0;
 	}

	int scr = DefaultScreen(dpy);
	int x = DisplayWidth(dpy, scr)/2 - w/2;
	int y = DisplayHeight(dpy, scr)/2 - h/2;

	vi = glXChooseVisual(dpy, 0, att);
	if(!vi) { puts("No find glX visual."); return 0; }
       	else printf("visual %p selected.\n", (void *)vi->visualid);
	
	root = RootWindow(dpy, vi->screen);

	cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
	swa.colormap = cmap;
	swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask | SubstructureNotifyMask | SubstructureRedirectMask | VisibilityChangeMask | PropertyChangeMask;
	swa.override_redirect = True;
	swa.border_pixel = 0;

	win = XCreateWindow(dpy, root, x, y, w, h, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);

//	XMapRaised(dpy, win);
//	XMapWindow(dpy, win);
	XStoreName(dpy, win, "Xmasdemo");

	glc = glXCreateContext(dpy, vi, 0, GL_TRUE);
	glXMakeCurrent(dpy, win, glc);

	typedef struct Hints {
		unsigned long   flags;
		unsigned long   functions;
		unsigned long   decorations;
    	long            inputMode;
		unsigned long   status;
	} Hints;

	Hints hints;
	hints.flags = 2;
	hints.decorations = 0;
	Atom prop = XInternAtom(dpy, "_MOTIF_WM_HINTS", true);
	XChangeProperty(dpy,win,prop,prop,32,PropModeReplace,(unsigned char *)&hints,5);
	Atom atoms[2] = { XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False), None };
	XChangeProperty( dpy, win, XInternAtom(dpy, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char*)atoms, 1);
	XMapWindow(dpy, win);

	puts("SET_WINDOW_ON_TOP");
	//x11_window_set_on_top(dpy, win);

    XRaiseWindow(dpy, win);
    XFlush(dpy);

	XSizeHints* size_hints = XAllocSizeHints();

	if(!XGetWMSizeHints(dpy, win, size_hints, (long *)&hints, XInternAtom(dpy, "WM_SIZE_HINTS", False)) == 0) {
	    puts("Failed.");
	}

	puts("LOWER!"); 

	XLowerWindow(dpy, win);
	XUnmapWindow(dpy, win);
	XSync(dpy, False);

//	printf("HINTS: %ld\n", hints);

	XFree(size_hints);


	XRaiseWindow(dpy, win);

//	exit(0);



	return 0;
}

bool initOpenGL( bool display, int width, int height ) {

	(void)display;

	if(CreateWin(width, height)) {
		puts("Failed to create window");
		return false;
	}

	GLint res = glewInit();
	if(res != GLEW_OK) {
		printf("GLEW initialization failed: %s\n", glewGetErrorString(res));
		return false;
	}

	// Enable VSYNC in OpenGL https://stackoverflow.com/questions/589064/how-to-enable-vertical-sync-in-opengl#589232
	glXSwapIntervalEXT(dpy, win, -1);

	return true;
}

void postRender() {

	glXSwapBuffers(dpy, win);

	while(XPending(dpy))
		handleEvent();
}

void shutdownOpenGL(){
	glXMakeCurrent(dpy, None, 0);
	glXDestroyContext(dpy, glc);
	XDestroyWindow(dpy, win);
 	XCloseDisplay(dpy);
}


