+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <vector>
+#include <GL/glx.h>
+#include <msp/core/error.h>
+#include "window.h"
+
+using namespace std;
+
+#include <msp/strings/lexicalcast.h>
+
+namespace Msp {
+
+DisplayOptions::DisplayOptions():
+ width(640),
+ height(480),
+ fullscreen(false)
+{ }
+
+
+/**
+Initializes the class but does not open the window. Intended for use by
+derived classes.
+*/
+Window::Window():
+ display(0),
+ window(0)
+{ }
+
+Window::Window(unsigned w, unsigned h)
+{
+ options.width=w;
+ options.height=h;
+
+ init();
+}
+
+Window::Window(const DisplayOptions &dopt):
+ options(dopt)
+{
+ init();
+}
+
+Window::~Window()
+{
+ if(window)
+ XDestroyWindow(display, window);
+ if(display)
+ XCloseDisplay(display);
+}
+
+void Window::show()
+{
+ XMapRaised(display, window);
+}
+
+void Window::hide()
+{
+ XUnmapWindow(display, window);
+}
+
+void Window::tick()
+{
+ while(1)
+ {
+ int pending=XPending(display);
+ if(pending==0)
+ break;
+
+ for(int i=0; i<pending; ++i)
+ {
+ XEvent event;
+ XNextEvent(display, &event);
+ process_event(event);
+ }
+ }
+}
+
+void Window::prepare()
+{
+ if(options.display.empty())
+ display=XOpenDisplay(0);
+ else
+ display=XOpenDisplay(options.display.c_str());
+ if(!display)
+ throw Exception("Couldn't open X display");
+
+ //XSetErrorHandler(x_error_handler);
+}
+
+void Window::init()
+{
+ prepare();
+
+ window=XCreateWindow(display, DefaultRootWindow(display), 0, 0, options.width, options.height, 0, CopyFromParent, InputOutput, CopyFromParent, 0, 0);
+ if(!window)
+ throw Exception("Couldn't create a window");
+
+ XSelectInput(display, window, ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask);
+}
+
+void Window::process_event(const XEvent &event)
+{
+ switch(event.type)
+ {
+ case ButtonPress:
+ signal_button_press.emit(event.xbutton.x, event.xbutton.y, event.xbutton.button, event.xbutton.state);
+ break;
+ case ButtonRelease:
+ signal_button_release.emit(event.xbutton.x, event.xbutton.y, event.xbutton.button, event.xbutton.state);
+ break;
+ case MotionNotify:
+ signal_pointer_motion.emit(event.xmotion.x, event.xmotion.y);
+ break;
+ case KeyPress:
+ {
+ char buf[16];
+ XLookupString(const_cast<XKeyEvent *>(&event.xkey), buf, sizeof(buf), 0, 0);
+ // XXX Handle the result according to locale
+ signal_key_press.emit(event.xkey.keycode, event.xkey.state, buf[0]);
+ }
+ break;
+ case KeyRelease:
+ signal_key_release.emit(event.xkey.keycode, event.xkey.state);
+ break;
+ case ConfigureNotify:
+ options.width=event.xconfigure.width;
+ options.height=event.xconfigure.height;
+ break;
+ default:;
+ }
+}
+
+int Window::x_error_handler(Display *display, XErrorEvent *error)
+{
+ char buf[128];
+ XGetErrorText(display, error->error_code, buf, sizeof(buf));
+ /*string request_code=lexical_cast(error->request_code);
+ char buf2[1024];
+ XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), buf, buf2, sizeof(buf2));*/
+ throw Exception(buf);
+}
+
+} // namespace Msp