+#include "glwindow.h"
+
+#include <assert.h>
+#include <X11/Xutil.h>
+#include <stdio.h>
+#include <string.h>
+
+GLWindow::~GLWindow()
+{
+ delete backend;
+ if (window)
+ XDestroyWindow(display, window);
+ XCloseDisplay(display);
+}
+
+void GLWindow::create(unsigned int width, unsigned int height)
+{
+ assert(!window);
+ // get visual from backend
+ XVisualInfo vinfo_template;
+ vinfo_template.visualid = backend->initialize(display);
+ int num_vinfo;
+ XVisualInfo *vi = XGetVisualInfo(display, VisualIDMask, &vinfo_template, &num_vinfo);
+ assert(num_vinfo == 1 && vi != NULL);
+ // set winattrs
+ XSetWindowAttributes winAttr;
+ winAttr.colormap = XCreateColormap(display, RootWindow(display, vi->screen), vi->visual, AllocNone);
+ winAttr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask;
+ winAttr.border_pixel = 0;
+ // create window
+ /*if (fullscreen) {
+ // get root window size
+ width = DisplayWidth(display, vi->screen);
+ height = DisplayHeight(display, vi->screen);
+ printf("Display size: %dx%d\n", width, height);
+ // set window attributes
+ winAttr.override_redirect = True;
+ window = XCreateWindow(display, RootWindow(display, vi->screen),
+ 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
+ CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &winAttr);
+ XWarpPointer(display, None, window, 0, 0, 0, 0, 0, 0);
+ XMapRaised(display, window);
+ XGrabKeyboard(display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
+ XGrabPointer(display, window, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
+ }
+ else {*/
+ printf("Initial window size: %dx%d\n", width, height);
+ // create a window in window mode
+ window = XCreateWindow(display, RootWindow(display, vi->screen),
+ 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
+ CWBorderPixel | CWColormap | CWEventMask, &winAttr);
+ /* handle wm_delete_events */
+ Atom wmDelete = XInternAtom(display, "WM_DELETE_WINDOW", True);
+ XMapRaised(display, window);
+ XSetWMProtocols(display, window, &wmDelete, 1);
+ // done
+ this->fullscreen = false;
+ this->width = width;
+ this->height = height;
+ backend->createContext(window);
+ initGL();
+ resizeGL(width, height);
+}
+
+void GLWindow::close()
+{
+ if (!window) return;
+ XEvent ev;
+ memset(&ev, 0, sizeof (ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = window;
+ ev.xclient.message_type = XInternAtom(display, "WM_PROTOCOLS", true);
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = XInternAtom(display, "WM_DELETE_WINDOW", false);
+ ev.xclient.data.l[1] = CurrentTime;
+ XSendEvent(display, window, False, NoEventMask, &ev);
+}
+
+void GLWindow::setFullscreen(bool fullscreen)
+{
+ assert(window);
+ // set fullscreen property
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.window = window;
+ e.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", true);
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = 2; // _NET_WM_STATE_TOGGLE
+ e.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", fullscreen);
+ e.xclient.data.l[2] = 0; // no second property to toggle
+ e.xclient.data.l[3] = 1;
+ e.xclient.data.l[4] = 0;
+ XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &e);
+}
+
+void GLWindow::exec()
+{
+ while (true)
+ {
+ /* handle the events in the queue */
+ while (XPending(display) > 0)
+ {
+ XEvent event;
+ XNextEvent(display, &event);
+ switch (event.type)
+ {
+ case Expose:
+ renderGL();
+ break;
+ case ConfigureNotify:
+ if (event.xconfigure.width != this->width || event.xconfigure.height != this->height) {
+ printf("Window resized to: %dx%d\n", event.xconfigure.width, event.xconfigure.height);
+ this->width = event.xconfigure.width;
+ this->height = event.xconfigure.height;
+ resizeGL(this->width, this->height);
+ }
+ break;
+ case KeyPress:
+ handleKeyPress(XLookupKeysym(&event.xkey, 0));
+ break;
+ case ClientMessage:
+ if (strcmp(XGetAtomName(display, event.xclient.message_type), "WM_PROTOCOLS") == 0 &&
+ strcmp(XGetAtomName(display, event.xclient.data.l[0]), "WM_DELETE_WINDOW") == 0)
+ {
+ XDestroyWindow(display, window);
+ window = 0;
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ renderGL();
+ }
+}