};
};
- headers "msp/gbase"
+ headers "msp/graphics"
{
- source "source/gbase";
+ source "source/graphics";
install true;
};
library "mspgbase"
{
- source "source/gbase";
+ source "source/graphics";
source "source/input";
install true;
};
+++ /dev/null
-#include <iostream>
-#ifndef WIN32
-#include <X11/Xlib.h>
-#ifdef WITH_XF86VIDMODE
-#include <X11/extensions/xf86vmode.h>
-#endif
-#endif
-#include <msp/strings/format.h>
-#include <msp/strings/lexicalcast.h>
-#include "display.h"
-#include "window.h"
-#include "display_priv.h"
-
-using namespace std;
-
-namespace {
-
-bool error_flag = false;
-std::string error_msg;
-
-#ifndef WIN32
-int x_error_handler(Display *display, XErrorEvent *event)
-{
- char err[128];
- XGetErrorText(display, event->error_code, err, sizeof(err));
-
- string request_code = Msp::lexical_cast(static_cast<int>(event->request_code));
- char req[128];
- XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req));
-
- string msg = Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid);
- if(error_flag)
- cerr<<"Discarding error: "<<msg<<'\n';
- else
- {
- cerr<<msg<<'\n';
- error_msg = msg;
- error_flag = true;
- }
-
- return 0;
-}
-#endif
-
-}
-
-namespace Msp {
-namespace Graphics {
-
-unsupported_video_mode::unsupported_video_mode(const VideoMode &mode):
- runtime_error(format("%dx%d", mode.width, mode.height))
-{ }
-
-
-Display::Display(const string &disp_name):
- priv(new Private)
-{
-#ifdef WIN32
- (void)disp_name;
-
- for(unsigned i=0;; ++i)
- {
- DEVMODE info;
- if(!EnumDisplaySettings(0, i, &info))
- break;
-
- VideoMode mode(info.dmPelsWidth, info.dmPelsHeight);
- mode.rate = info.dmDisplayFrequency;
- modes.push_back(mode);
- }
-
- DEVMODE info;
- if(EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &info))
- {
- orig_mode = VideoMode(info.dmPelsWidth, info.dmPelsHeight);
- orig_mode.rate = info.dmDisplayFrequency;
- }
-#else
- if(disp_name.empty())
- priv->display = XOpenDisplay(0);
- else
- priv->display = XOpenDisplay(disp_name.c_str());
- if(!priv->display)
- throw runtime_error("XOpenDisplay");
-
- XSetErrorHandler(x_error_handler);
-
-#ifdef WITH_XF86VIDMODE
- int screen = DefaultScreen(priv->display);
-
- int nmodes;
- XF86VidModeModeInfo **infos;
- XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos);
- for(int i=0; i<nmodes; ++i)
- {
- XF86VidModeModeInfo &info = *infos[i];
-
- VideoMode mode(info.hdisplay, info.vdisplay);
- if(info.htotal && info.vtotal)
- mode.rate = info.dotclock/(info.htotal*info.vtotal);
- modes.push_back(mode);
- }
-
- XFree(infos);
-
- XF86VidModeModeLine modeline;
- int dotclock;
- XF86VidModeGetModeLine(priv->display, screen, &dotclock, &modeline);
- orig_mode = VideoMode(modeline.hdisplay, modeline.vdisplay);
- if(modeline.htotal && modeline.vtotal)
- orig_mode.rate = dotclock/(modeline.htotal*modeline.vtotal);
-#endif
-#endif
-}
-
-Display::~Display()
-{
-#ifndef WIN32
- XCloseDisplay(priv->display);
- delete priv;
-#endif
-}
-
-void Display::add_window(Window &wnd)
-{
- priv->windows[wnd.get_private().window] = &wnd;
-}
-
-void Display::remove_window(Window &wnd)
-{
- priv->windows.erase(wnd.get_private().window);
-}
-
-void Display::set_mode(const VideoMode &mode)
-{
-#if defined(WIN32)
- DEVMODE info;
- info.dmSize = sizeof(DEVMODE);
- info.dmFields = DM_PELSWIDTH|DM_PELSHEIGHT;
- info.dmPelsWidth = mode.width;
- info.dmPelsHeight = mode.height;
- if(mode.rate)
- {
- info.dmFields |= DM_DISPLAYFREQUENCY;
- info.dmDisplayFrequency = mode.rate;
- }
-
- LONG ret = ChangeDisplaySettings(&info, CDS_FULLSCREEN);
- if(ret!=DISP_CHANGE_SUCCESSFUL)
- throw unsupported_video_mode(mode);
-#elif defined(WITH_XF86VIDMODE)
- int screen = DefaultScreen(priv->display);
-
- int nmodes;
- XF86VidModeModeInfo **infos;
- XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos);
- for(int i=0; i<nmodes; ++i)
- {
- XF86VidModeModeInfo &info = *infos[i];
-
- unsigned rate = 0;
- if(info.htotal && info.vtotal)
- rate = info.dotclock/(info.htotal*info.vtotal);
- if(info.hdisplay==mode.width && info.vdisplay==mode.height && (mode.rate==0 || rate==mode.rate))
- {
- XF86VidModeSwitchToMode(priv->display, screen, &info);
- XF86VidModeSetViewPort(priv->display, screen, 0, 0);
- return;
- }
- }
-
- throw unsupported_video_mode(mode);
-#else
- (void)mode;
- throw runtime_error("no xf86vidmode support");
-#endif
-}
-
-void Display::tick()
-{
- check_error();
-
- while(1)
- {
-#ifdef WIN32
- MSG msg;
- if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
- DispatchMessage(&msg);
- else
- break;
-#else
- int pending = XPending(priv->display);
- if(pending==0)
- break;
-
- for(; pending--;)
- {
- Window::Event event;
- XNextEvent(priv->display, &event.xevent);
-
- check_error();
-
- map<WindowHandle, Window *>::iterator j = priv->windows.find(event.xevent.xany.window);
- if(j!=priv->windows.end())
- {
- /* Filter keyboard autorepeat. If this packet is a KeyRelease and
- the next one is a KeyPress with the exact same parameters, they
- indicate autorepeat and must be dropped. */
- if(event.xevent.type==KeyRelease && !j->second->get_keyboard_autorepeat() && pending>0)
- {
- XKeyEvent &kev = event.xevent.xkey;
- XEvent ev2;
- XPeekEvent(priv->display, &ev2);
- if(ev2.type==KeyPress)
- {
- XKeyEvent &kev2 = ev2.xkey;
- if(kev2.window==kev.window && kev2.time==kev.time && kev2.keycode==kev.keycode)
- {
- XNextEvent(priv->display, &ev2);
- --pending;
- continue;
- }
- }
- }
-
- j->second->event(event);
- }
- }
-#endif
- }
-}
-
-void Display::check_error()
-{
- if(error_flag)
- {
- error_flag = false;
- throw runtime_error(error_msg);
- }
-}
-
-} // namespace Graphics
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GBASE_DISPLAY_H_
-#define MSP_GBASE_DISPLAY_H_
-
-#include <list>
-#include <map>
-#include <stdexcept>
-#include <string>
-
-namespace Msp {
-namespace Graphics {
-
-class Window;
-
-struct VideoMode
-{
- unsigned width;
- unsigned height;
- unsigned rate;
-
- VideoMode(): width(0), height(0), rate(0) { }
- VideoMode(unsigned w, unsigned h): width(w), height(h), rate(0) { }
-};
-
-
-class unsupported_video_mode: public std::runtime_error
-{
-public:
- unsupported_video_mode(const VideoMode &);
- virtual ~unsupported_video_mode() throw () { }
-};
-
-
-class Display
-{
-public:
- struct Private;
-
-private:
- std::list<VideoMode> modes;
- VideoMode orig_mode;
- Private *priv;
-
-public:
- Display(const std::string &disp_name = std::string());
- ~Display();
-
- const Private &get_private() const { return *priv; }
-
- void add_window(Window &);
- void remove_window(Window &);
-
- const std::list<VideoMode> &get_modes() const { return modes; }
- void set_mode(const VideoMode &);
- void restore_mode() { set_mode(orig_mode); }
-
- void tick();
- void check_error();
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifndef MSP_GBASE_DISPLAY_PRIV_H_
-#define MSP_GBASE_DISPLAY_PRIV_H_
-
-#include "window_priv.h"
-
-namespace Msp {
-namespace Graphics {
-
-struct Display::Private
-{
-#ifndef WIN32
- ::Display *display;
-#endif
- std::map<WindowHandle, Window *> windows;
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include <stdexcept>
-#ifndef WIN32
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <X11/Xlib.h>
-#include <X11/extensions/XShm.h>
-#include <X11/Xutil.h>
-#endif
-#include "display.h"
-#include "drawcontext.h"
-#include "window.h"
-#include "display_priv.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Graphics {
-
-struct DrawContext::Private
-{
-#ifndef WIN32
- XImage *image;
- bool use_shm;
- XShmSegmentInfo shminfo;
-#endif
-};
-
-DrawContext::DrawContext(Window &w):
- display(w.get_display()),
- window(w)
-{
-#ifdef WIN32
- throw runtime_error("no DrawContext support on windows");
-#else
- priv = new Private;
-
- ::Display *dpy = display.get_private().display;
-
- priv->use_shm = XShmQueryExtension(dpy);
-
- XWindowAttributes wa;
- XGetWindowAttributes(dpy, window.get_private().window, &wa);
-
- if(priv->use_shm)
- {
- priv->image = XShmCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, &priv->shminfo, wa.width, wa.height);
- if(!priv->image)
- throw runtime_error("XShmCreateImage");
-
- priv->shminfo.shmid = shmget(IPC_PRIVATE, priv->image->bytes_per_line*priv->image->height, IPC_CREAT|0666);
- priv->shminfo.shmaddr=priv->image->data = reinterpret_cast<char *>(shmat(priv->shminfo.shmid, 0, 0));
- priv->shminfo.readOnly = false;
-
- XShmAttach(dpy, &priv->shminfo);
-
- XSync(dpy, false);
- display.check_error();
- }
- else
- {
- priv->image = XCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, 0, wa.width, wa.height, 8, 0);
- if(!priv->image)
- throw runtime_error("XCreateImage");
- priv->image->data = new char[priv->image->bytes_per_line*priv->image->height];
- }
-#endif
-}
-
-DrawContext::~DrawContext()
-{
-#ifndef WIN32
- if(priv->use_shm)
- {
- XShmDetach(display.get_private().display, &priv->shminfo);
- shmdt(priv->shminfo.shmaddr);
- shmctl(priv->shminfo.shmid, IPC_RMID, 0);
- }
-
- XDestroyImage(priv->image);
-#endif
-
- delete priv;
-}
-
-unsigned DrawContext::get_depth() const
-{
-#ifdef WIN32
- return 0;
-#else
- return priv->image->bits_per_pixel;
-#endif
-}
-
-unsigned char *DrawContext::get_data()
-{
-#ifdef WIN32
- return 0;
-#else
- return reinterpret_cast<unsigned char *>(priv->image->data);
-#endif
-}
-
-void DrawContext::update()
-{
-#ifndef WIN32
- ::Display *dpy = display.get_private().display;
- WindowHandle wnd = window.get_private().window;
-
- GC gc = XCreateGC(dpy, wnd, 0, 0);
-
- if(priv->use_shm)
- XShmPutImage(dpy, wnd, gc, priv->image, 0, 0, 0, 0, priv->image->width, priv->image->height, false);
- else
- XPutImage(dpy, wnd, gc, priv->image, 0, 0, 0, 0, priv->image->width, priv->image->height);
-
- XFreeGC(dpy, gc);
-#endif
-}
-
-} // namespace Graphics
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GBASE_DRAWCONTEXT_H_
-#define MSP_GBASE_DRAWCONTEXT_H_
-
-namespace Msp {
-namespace Graphics {
-
-class Display;
-class Window;
-
-class DrawContext
-{
-private:
- struct Private;
-
- Display &display;
- Window &window;
- Private *priv;
-
-public:
- DrawContext(Window &);
- ~DrawContext();
-
- Window &get_window() const { return window; }
- unsigned get_depth() const;
- unsigned char *get_data();
- void update();
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifndef MSP_GBASE_EVENTSOURCE_H_
-#define MSP_GBASE_EVENTSOURCE_H_
-
-namespace Msp {
-namespace Graphics {
-
-class EventSource
-{
-public:
- sigc::signal<void, unsigned, unsigned, unsigned> signal_key_press;
- sigc::signal<void, unsigned, unsigned> signal_key_release;
- sigc::signal<void, int, int, unsigned, unsigned> signal_button_press;
- sigc::signal<void, int, int, unsigned, unsigned> signal_button_release;
- sigc::signal<void, int, int> signal_pointer_motion;
- sigc::signal<void, unsigned, unsigned> signal_resize;
-
-protected:
- EventSource() { }
-public:
- virtual ~EventSource() { }
-
- virtual unsigned get_width() const = 0;
- virtual unsigned get_height() const = 0;
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include <vector>
-#ifdef WIN32
-#include <windows.h>
-#endif
-#ifdef WITH_OPENGL
-#include <GL/gl.h>
-#ifndef WIN32
-#include <GL/glx.h>
-#endif
-#endif
-#include <msp/core/application.h>
-#include <msp/strings/format.h>
-#include "display.h"
-#include "glcontext.h"
-#include "window.h"
-#include "display_priv.h"
-
-namespace Msp {
-namespace Graphics {
-
-GLOptions::GLOptions():
- alpha(false),
- stencil(false),
- doublebuffer(true),
- multisample(0)
-{ }
-
-
-unsupported_gl_mode::unsupported_gl_mode(const GLOptions &opts):
- runtime_error(format("{ .alpha=%s, .stencil=%s, .doublebuffer=%s, .multisample=%d }",
- opts.alpha, opts.stencil, opts.doublebuffer, opts.multisample))
-{ }
-
-
-#ifdef WITH_OPENGL
-#ifdef WIN32
-typedef HGLRC Context;
-#else
-typedef GLXContext Context;
-#endif
-
-struct GLContext::Private
-{
- Context context;
-#ifndef WIN32
- // In X11, we need to create a window with the chosen visual
- WindowHandle subwnd;
-#endif
-};
-#endif
-
-
-GLContext::GLContext(Window &wnd, const GLOptions &opts):
- display(wnd.get_display()),
- window(wnd)
-{
-#ifdef WITH_OPENGL
- priv = new Private;
-
-#ifdef WIN32
- HDC dc = GetDC(window.get_private().window);
-
- PIXELFORMATDESCRIPTOR pfd;
- memset(&pfd, 0, sizeof(pfd));
-
- pfd.nSize = sizeof(pfd);
- pfd.nVersion = 1;
- pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
- if(opts.doublebuffer)
- pfd.dwFlags |= PFD_DOUBLEBUFFER;
- pfd.iPixelType = PFD_TYPE_RGBA;
- if(opts.alpha)
- pfd.cAlphaBits = 1;
- pfd.cDepthBits = 1;
- if(opts.stencil)
- pfd.cStencilBits = 1;
-
- int pf_index = ChoosePixelFormat(dc, &pfd);
- if(!pf_index)
- throw unsupported_gl_mode(opts);
- SetPixelFormat(dc, pf_index, &pfd);
-
- priv->context = wglCreateContext(dc);
- wglMakeCurrent(dc, priv->context);
-
- ReleaseDC(window.get_private().window, dc);
-#else
- std::vector<int> attribs;
-
- attribs.push_back(GLX_RGBA);
- attribs.push_back(GLX_DEPTH_SIZE);
- attribs.push_back(1);
-
- if(opts.alpha)
- {
- attribs.push_back(GLX_ALPHA_SIZE);
- attribs.push_back(1);
- }
-
- if(opts.stencil)
- {
- attribs.push_back(GLX_STENCIL_SIZE);
- attribs.push_back(1);
- }
-
- if(opts.doublebuffer)
- attribs.push_back(GLX_DOUBLEBUFFER);
-
- if(opts.multisample>0)
- {
- attribs.push_back(GLX_SAMPLE_BUFFERS_ARB);
- attribs.push_back(opts.multisample);
- }
-
- attribs.push_back(0);
-
- ::Display *dpy = display.get_private().display;
-
- XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front());
- if(!vi)
- throw unsupported_gl_mode(opts);
- priv->context = glXCreateContext(dpy, vi, 0, true);
-
- XSetWindowAttributes attr;
- attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
-
- priv->subwnd = XCreateWindow(dpy, window.get_private().window, 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr);
- XMapWindow(dpy, priv->subwnd);
-
- XFree(vi);
-
- glXMakeCurrent(dpy, priv->subwnd, priv->context);
-#endif
-#else
- (void)wnd;
- (void)opts;
- throw runtime_error("no OpenGL support");
-#endif
-
- window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized));
-}
-
-GLContext::~GLContext()
-{
-#ifdef WITH_OPENGL
-#ifdef WIN32
- wglMakeCurrent(0, 0);
- wglDeleteContext(priv->context);
-#else
- ::Display *dpy = display.get_private().display;
-
- glXMakeCurrent(dpy, 0, 0);
- glXDestroyContext(dpy, priv->context);
- XDestroyWindow(dpy, priv->subwnd);
-#endif
- delete priv;
-#endif
-}
-
-void GLContext::swap_buffers()
-{
-#ifdef WITH_OPENGL
-#ifdef WIN32
- HDC dc = GetDC(window.get_private().window);
- SwapBuffers(dc);
- ReleaseDC(window.get_private().window, dc);
-#else
- glXSwapBuffers(display.get_private().display, priv->subwnd);
-#endif
-#endif
-}
-
-void GLContext::window_resized(unsigned w, unsigned h)
-{
-#ifdef WITH_OPENGL
-#ifndef WIN32
- XMoveResizeWindow(display.get_private().display, priv->subwnd, 0, 0, w, h);
-#endif
- glViewport(0, 0, w, h);
-#else
- (void)w;
- (void)h;
-#endif
-}
-
-} // namespace Graphics
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GBASE_GLCONTEXT_H_
-#define MSP_GBASE_GLCONTEXT_H_
-
-#include <stdexcept>
-
-namespace Msp {
-namespace Graphics {
-
-class Display;
-class Window;
-
-struct GLOptions
-{
- bool alpha;
- bool stencil;
- bool doublebuffer;
- unsigned multisample;
-
- GLOptions();
-};
-
-
-class unsupported_gl_mode: public std::runtime_error
-{
-public:
- unsupported_gl_mode(const GLOptions &);
- virtual ~unsupported_gl_mode() throw () { }
-};
-
-
-class GLContext
-{
-private:
- struct Private;
-
- Display &display;
- Window &window;
- Private *priv;
-
-public:
- GLContext(Window &wnd, const GLOptions &opts = GLOptions());
- ~GLContext();
-
- void swap_buffers();
-private:
- void window_resized(unsigned, unsigned);
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifdef WITH_DEVIL
-#include <IL/il.h>
-#endif
-#ifdef WITH_LIBPNG
-#include <png.h>
-#include <msp/io/file.h>
-#include <msp/io/memory.h>
-#endif
-#include "image.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Graphics {
-
-struct Image::Private
-{
-#ifdef WITH_DEVIL
- unsigned id;
-#endif
-#ifdef WITH_LIBPNG
- PixelFormat fmt;
- unsigned width;
- unsigned height;
- char *data;
-#endif
-
- Private();
-};
-
-Image::Private::Private()
-{
-#ifdef WITH_DEVIL
- id = 0;
-#endif
-#ifdef WITH_LIBPNG
- fmt = RGB;
- width = 0;
- height = 0;
- data = 0;
-#endif
-}
-
-
-namespace {
-
-#ifdef WITH_LIBPNG
-void read(png_struct *png, png_byte *data, png_size_t size)
-{
- IO::Base *in = reinterpret_cast<IO::Base *>(png_get_io_ptr(png));
- in->read(reinterpret_cast<char *>(data), size);
-}
-
-void load_png(IO::Base &in, Image::Private &priv)
-{
- png_struct *png = 0;
- png_info *info = 0;
- priv.data = 0;
-
- try
- {
- png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
- info = png_create_info_struct(png);
-
- if(setjmp(png_jmpbuf(png)))
- throw bad_image_data("PNG error");
-
- png_set_read_fn(png, &in, read);
- png_read_info(png, info);
- png_uint_32 width;
- png_uint_32 height;
- int depth;
- int color;
- png_get_IHDR(png, info, &width, &height, &depth, &color, 0, 0, 0);
- priv.width = width;
- priv.height = height;
- if(depth!=8)
- throw unsupported_image_format("depth!=8");
- switch(color)
- {
- case PNG_COLOR_TYPE_PALETTE: priv.fmt = COLOR_INDEX; break;
- case PNG_COLOR_TYPE_GRAY: priv.fmt = LUMINANCE; break;
- case PNG_COLOR_TYPE_GRAY_ALPHA: priv.fmt = LUMINANCE_ALPHA; break;
- case PNG_COLOR_TYPE_RGB: priv.fmt = RGB; break;
- case PNG_COLOR_TYPE_RGB_ALPHA: priv.fmt = RGBA; break;
- default: throw unsupported_image_format("unknown color type");
- }
-
- unsigned nchans = png_get_channels(png, info);
- if(nchans==4 && priv.fmt==RGB)
- png_set_strip_alpha(png);
-
- unsigned rowstride = priv.width*nchans;
- priv.data = new char[rowstride*priv.height];
- for(unsigned y=0; y<priv.height; ++y)
- png_read_row(png, reinterpret_cast<png_byte *>(priv.data+rowstride*(priv.height-1-y)), 0);
-
- png_read_end(png, 0);
- png_destroy_read_struct(&png, &info, 0);
- }
- catch(...)
- {
- png_destroy_read_struct(&png, &info, 0);
- delete[] priv.data;
- throw;
- }
-}
-#endif
-
-#ifdef WITH_DEVIL
-void ensure_devil_image(unsigned &id)
-{
- static bool init_done = false;
-
- if(!init_done)
- {
- ilInit();
- ilEnable(IL_ORIGIN_SET);
- ilOriginFunc(IL_ORIGIN_LOWER_LEFT);
- init_done = true;
- }
-
- if(!id)
- ilGenImages(1, &id);
-}
-#endif
-
-}
-
-
-Image::Image():
- priv(new Private)
-{
-#if !defined(WITH_DEVIL) && !defined(WITH_LIBPNG)
- throw runtime_error("no image support");
-#endif
-}
-
-Image::~Image()
-{
-#ifdef WITH_DEVIL
- if(priv->id)
- ilDeleteImages(1, &priv->id);
-#endif
-#ifdef WITH_LIBPNG
- delete[] priv->data;
-#endif
- delete priv;
-}
-
-void Image::load_file(const string &fn)
-{
-#ifdef WITH_LIBPNG
- if(fn.size()>4 && !fn.compare(fn.size()-4, 4, ".png"))
- {
- IO::BufferedFile file(fn);
- load_png(file, *priv);
- }
- else
-#endif
- {
-#ifdef WITH_DEVIL
- ensure_devil_image(priv->id);
- ilBindImage(priv->id);
- if(!ilLoadImage(const_cast<char *>(fn.c_str())))
- throw bad_image_data("IL error");
-#else
- throw unsupported_image_format("DevIL needed for non-PNG images");
-#endif
- }
- (void)fn;
-}
-
-void Image::load_memory(const void *data, unsigned size)
-{
-#ifdef WITH_LIBPNG
- if(!png_sig_cmp(reinterpret_cast<png_byte *>(const_cast<void *>(data)), 0, 8))
- {
- IO::Memory mem(reinterpret_cast<const char *>(data), size);
- load_png(mem, *priv);
- }
- else
-#endif
- {
-#ifdef WITH_DEVIL
- ensure_devil_image(priv->id);
- ilBindImage(priv->id);
- if(!ilLoadL(IL_TYPE_UNKNOWN, const_cast<void *>(data), size))
- throw bad_image_data("IL error");
-#else
- throw unsupported_image_format("DevIL needed for non-PNG images");
-#endif
- }
- (void)data;
- (void)size;
-}
-
-PixelFormat Image::get_format() const
-{
-#ifdef WITH_LIBPNG
- if(priv->data)
- return priv->fmt;
-#endif
-#ifdef WITH_DEVIL
- if(priv->id)
- {
- ilBindImage(priv->id);
- switch(ilGetInteger(IL_IMAGE_FORMAT))
- {
- case IL_COLOR_INDEX: return COLOR_INDEX;
- case IL_LUMINANCE: return LUMINANCE;
- case IL_LUMINANCE_ALPHA: return LUMINANCE_ALPHA;
- case IL_RGB: return RGB;
- case IL_RGBA: return RGBA;
- case IL_BGR: return BGR;
- case IL_BGRA: return BGRA;
- // XXX bad, should throw when loading
- default: throw invalid_argument("unknown pixel format in image");
- }
- }
-#endif
- return RGB;
-}
-
-unsigned Image::get_width() const
-{
-#ifdef WITH_LIBPNG
- if(priv->data)
- return priv->width;
-#endif
-#ifdef WITH_DEVIL
- if(priv->id)
- {
- ilBindImage(priv->id);
- return ilGetInteger(IL_IMAGE_WIDTH);
- }
-#endif
- return 0;
-}
-
-unsigned Image::get_height() const
-{
-#ifdef WITH_LIBPNG
- if(priv->data)
- return priv->height;
-#endif
-#ifdef WITH_DEVIL
- if(priv->id)
- {
- ilBindImage(priv->id);
- return ilGetInteger(IL_IMAGE_HEIGHT);
- }
-#endif
- return 0;
-}
-
-const void *Image::get_data() const
-{
-#ifdef WITH_LIBPNG
- if(priv->data)
- return priv->data;
-#endif
-#ifdef WITH_DEVIL
- if(priv->id)
- {
- ilBindImage(priv->id);
- return ilGetData();
- }
-#endif
- return 0;
-}
-
-} // namespace Graphics
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GBASE_IMAGE_H_
-#define MSP_GBASE_IMAGE_H_
-
-#include <string>
-#include "pixelformat.h"
-
-namespace Msp {
-namespace Graphics {
-
-class unsupported_image_format: public std::runtime_error
-{
-public:
- unsupported_image_format(const std::string &w): std::runtime_error(w) { }
- virtual ~unsupported_image_format() throw() { }
-};
-
-class bad_image_data: public std::runtime_error
-{
-public:
- bad_image_data(const std::string &w): std::runtime_error(w) { }
- virtual ~bad_image_data() throw() { }
-};
-
-
-class Image
-{
-public:
- struct Private;
-
-private:
- Private *priv;
-
-public:
- Image();
- ~Image();
-
- void load_file(const std::string &);
- void load_memory(const void *, unsigned);
- PixelFormat get_format() const;
- unsigned get_width() const;
- unsigned get_height() const;
- const void *get_data() const;
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifndef MSP_GBASE_PIXELFORMAT_H_
-#define MSP_GBASE_PIXELFORMAT_H_
-
-namespace Msp {
-namespace Graphics {
-
-enum PixelFormat
-{
- COLOR_INDEX,
- LUMINANCE,
- LUMINANCE_ALPHA,
- RGB,
- RGBA,
- BGR,
- BGRA
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include "simplewindow.h"
-
-namespace Msp {
-namespace Graphics {
-
-SimpleWindow::SimpleWindow(unsigned w, unsigned h, bool fs):
- Window(dpy, w, h, fs)
-{ }
-
-void SimpleWindow::tick()
-{
- dpy.tick();
-}
-
-
-SimpleGLWindow::SimpleGLWindow(unsigned w, unsigned h, bool fs):
- SimpleWindow(w, h, fs),
- gl_ctx(*this)
-{ }
-
-void SimpleGLWindow::swap_buffers()
-{
- gl_ctx.swap_buffers();
-}
-
-} // namespace Graphics
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GBASE_SIMPLEWINDOW_H_
-#define MSP_GBASE_SIMPLEWINDOW_H_
-
-#include "display.h"
-#include "glcontext.h"
-#include "window.h"
-
-namespace Msp {
-namespace Graphics {
-
-/**
-Helper class for SimpleWindow.
-*/
-class SimpleWindowBase
-{
-protected:
- Display dpy;
-
- SimpleWindowBase() { }
-};
-
-
-/**
-A simplified Window that encapsulates a Display.
-*/
-class SimpleWindow: public SimpleWindowBase, public Window
-{
-public:
- SimpleWindow(unsigned, unsigned, bool =false);
-
- void tick();
-};
-
-
-/**
-A SimpleWindow bundled with a GLContext.
-*/
-class SimpleGLWindow: public SimpleWindow
-{
-private:
- GLContext gl_ctx;
-
-public:
- SimpleGLWindow(unsigned, unsigned, bool =false);
- GLContext &get_gl_context() { return gl_ctx; }
- void swap_buffers();
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include <vector>
-#ifndef WIN32
-#include <X11/Xatom.h>
-#include <X11/Xutil.h>
-#ifdef WITH_XF86VIDMODE
-#include <X11/extensions/xf86vmode.h>
-#endif
-#else
-#include <windowsx.h>
-#endif
-#include <msp/core/application.h>
-#include "display.h"
-#include "window.h"
-#include "display_priv.h"
-
-using namespace std;
-
-namespace {
-
-#ifdef WIN32
-LRESULT CALLBACK wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
-{
- if(msg==WM_CREATE)
- {
- CREATESTRUCT *cs = reinterpret_cast<CREATESTRUCT *>(lparam);
- SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(cs->lpCreateParams));
- }
- else
- {
- Msp::Graphics::Window *wnd = reinterpret_cast<Msp::Graphics::Window *>(GetWindowLong(hwnd, 0));
- Msp::Graphics::Window::Event ev;
- ev.msg = msg;
- ev.wparam = wparam;
- ev.lparam = lparam;
- if(wnd && wnd->event(ev))
- return 0;
- }
-
- return DefWindowProc(hwnd, msg, wparam, lparam);
-}
-#else
-Bool match_event_type(Display *, XEvent *event, XPointer arg)
-{
- return event->type==*reinterpret_cast<int *>(arg);
-}
-#endif
-
-}
-
-namespace Msp {
-namespace Graphics {
-
-WindowOptions::WindowOptions():
- width(640),
- height(480),
- fullscreen(false),
- resizable(false)
-{ }
-
-
-Window::Window(Display &dpy, unsigned w, unsigned h, bool fs):
- display(dpy)
-{
- options.width = w;
- options.height = h;
- options.fullscreen = fs;
-
- init();
-}
-
-Window::Window(Display &dpy, const WindowOptions &opts):
- display(dpy),
- options(opts)
-{
- init();
-}
-
-void Window::init()
-{
- visible = false;
- kbd_autorepeat = true;
- resizing = false;
- priv = new Private;
-
-#ifdef WIN32
- static bool wndclass_created = false;
-
- if(!wndclass_created)
- {
- WNDCLASSEX wndcl;
-
- wndcl.cbSize = sizeof(WNDCLASSEX);
- wndcl.style = 0;
- wndcl.lpfnWndProc = &wndproc_;
- wndcl.cbClsExtra = 0;
- wndcl.cbWndExtra = sizeof(Window *);
- wndcl.hInstance = reinterpret_cast<HINSTANCE>(Application::get_data());
- wndcl.hIcon = 0;
- wndcl.hCursor = LoadCursor(0, IDC_ARROW);
- wndcl.hbrBackground = 0;
- wndcl.lpszMenuName = 0;
- wndcl.lpszClassName = "mspgbase";
- wndcl.hIconSm = 0;
-
- if(!RegisterClassEx(&wndcl))
- throw system_error("RegisterClassEx");
-
- wndclass_created = true;
- }
-
- RECT rect;
- SetRect(&rect, 0, 0, options.width, options.height);
-
- int style = (options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW);
- if(!options.resizable)
- style &= ~WS_THICKFRAME;
- int exstyle = (options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW);
- AdjustWindowRectEx(&rect, style, false, exstyle);
-
- priv->window = CreateWindowEx(exstyle,
- "mspgbase",
- "Window",
- style,
- CW_USEDEFAULT, CW_USEDEFAULT,
- rect.right-rect.left, rect.bottom-rect.top,
- 0,
- 0,
- reinterpret_cast<HINSTANCE>(Application::get_data()),
- this);
- if(!priv->window)
- throw system_error("CreateWindowEx");
-
-#else
- ::Display *dpy = display.get_private().display;
-
- priv->wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", true);
- priv->invisible_cursor = 0;
-
- XSetWindowAttributes attr;
- attr.override_redirect = options.fullscreen;
- attr.event_mask = ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask;
-
- priv->window = XCreateWindow(dpy,
- DefaultRootWindow(dpy),
- 0, 0,
- options.width, options.height,
- 0,
- CopyFromParent,
- InputOutput,
- CopyFromParent,
- CWOverrideRedirect|CWEventMask, &attr);
-
- XSetWMProtocols(dpy, priv->window, &priv->wm_delete_window, 1);
-
- if(!options.resizable)
- {
- XSizeHints hints;
- hints.flags = PMinSize|PMaxSize;
- hints.min_width=hints.max_width = options.width;
- hints.min_height=hints.max_height = options.height;
- XSetWMNormalHints(dpy, priv->window, &hints);
- }
-
-#endif
-
- display.add_window(*this);
- display.check_error();
-}
-
-Window::~Window()
-{
- if(priv->window)
-#ifdef WIN32
- CloseWindow(priv->window);
-#else
- XDestroyWindow(display.get_private().display, priv->window);
-
- if(priv->invisible_cursor)
- XFreeCursor(display.get_private().display, priv->invisible_cursor);
-#endif
-
- display.remove_window(*this);
-
- if(options.fullscreen)
- display.restore_mode();
-
- delete priv;
-}
-
-void Window::set_title(const string &title)
-{
-#ifdef WIN32
- SetWindowText(priv->window, title.c_str());
-#else
- vector<unsigned char> buf(title.begin(), title.end());
- XTextProperty prop;
- prop.value = &buf[0];
- prop.encoding = XA_STRING;
- prop.format = 8;
- prop.nitems = title.size();
- XSetWMName(display.get_private().display, priv->window, &prop);
- display.check_error();
-#endif
-}
-
-void Window::reconfigure(const WindowOptions &opts)
-{
- bool fullscreen_changed = (opts.fullscreen!=options.fullscreen);
- resizing = (opts.width!=options.width || opts.height!=options.height);
-
- options = opts;
-
-#ifdef WIN32
- RECT rect;
- SetRect(&rect, 0, 0, options.width, options.height);
-
- int style = (options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW);
- if(!options.resizable)
- style &= ~WS_THICKFRAME;
- int exstyle = (options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW);
- AdjustWindowRectEx(&rect, style, false, exstyle);
-
- if(fullscreen_changed)
- {
- hide();
- SetWindowLong(priv->window, GWL_EXSTYLE, exstyle);
- SetWindowLong(priv->window, GWL_STYLE, style);
- show();
- }
-
- if(options.fullscreen)
- SetWindowPos(priv->window, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOZORDER);
- else
- SetWindowPos(priv->window, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE|SWP_NOZORDER);
-#else
- ::Display *dpy = display.get_private().display;
-
- bool was_visible = visible;
- if(fullscreen_changed)
- {
- if(was_visible)
- {
- hide();
-
- // Wait for the window to be unmapped. This makes window managers happy.
- XEvent ev;
- int ev_type = UnmapNotify;
- XPeekIfEvent(dpy, &ev, match_event_type, reinterpret_cast<char *>(&ev_type));
- }
-
- XSetWindowAttributes attr;
- attr.override_redirect = options.fullscreen;
- XChangeWindowAttributes(dpy, priv->window, CWOverrideRedirect, &attr);
- }
-
- XSizeHints hints;
- if(options.resizable)
- hints.flags = 0;
- else
- {
- hints.flags = PMinSize|PMaxSize;
- hints.min_width=hints.max_width = options.width;
- hints.min_height=hints.max_height = options.height;
- }
- XSetWMNormalHints(dpy, priv->window, &hints);
-
- if(options.fullscreen)
- XMoveResizeWindow(dpy, priv->window, 0, 0, options.width, options.height);
- else
- XResizeWindow(dpy, priv->window, options.width, options.height);
-
- if(fullscreen_changed)
- {
- if(was_visible)
- show();
- }
-#endif
-
- if(visible)
- {
- if(options.fullscreen)
- display.set_mode(VideoMode(options.width, options.height));
- else if(fullscreen_changed)
- display.restore_mode();
- }
-}
-
-void Window::set_keyboard_autorepeat(bool r)
-{
- kbd_autorepeat = r;
-}
-
-void Window::show_cursor(bool s)
-{
-#ifdef WIN32
- ShowCursor(s);
-#else
- ::Display *dpy = display.get_private().display;
-
- if(s)
- XUndefineCursor(dpy, priv->window);
- else
- {
- if(!priv->invisible_cursor)
- {
- int screen = DefaultScreen(dpy);
-
- Pixmap pm = XCreatePixmap(dpy, priv->window, 1, 1, 1);
- GC gc = XCreateGC(dpy, pm, 0, 0);
- XSetFunction(dpy, gc, GXclear);
- XDrawPoint(dpy, pm, gc, 0, 0);
- XFreeGC(dpy, gc);
-
- XColor black;
- black.pixel = BlackPixel(dpy, screen);
- XQueryColor(dpy, DefaultColormap(dpy, screen), &black);
-
- priv->invisible_cursor = XCreatePixmapCursor(dpy, pm, pm, &black, &black, 0, 0);
-
- XFreePixmap(dpy, pm);
- }
- XDefineCursor(dpy, priv->window, priv->invisible_cursor);
- }
-#endif
-}
-
-void Window::warp_pointer(int x, int y)
-{
-#ifndef WIN32
- XWarpPointer(display.get_private().display, None, priv->window, 0, 0, 0, 0, x, y);
-#else
- (void)x;
- (void)y;
-#endif
-}
-
-void Window::show()
-{
-#ifdef WIN32
- ShowWindow(priv->window, SW_SHOWNORMAL);
-#else
- XMapRaised(display.get_private().display, priv->window);
-#endif
- visible = true;
-
- if(options.fullscreen)
- {
- display.set_mode(VideoMode(options.width, options.height));
-#ifndef WIN32
- XWarpPointer(display.get_private().display, None, priv->window, 0, 0, 0, 0, options.width/2, options.height/2);
-#endif
- }
-}
-
-void Window::hide()
-{
-#ifdef WIN32
- ShowWindow(priv->window, SW_HIDE);
-#else
- XUnmapWindow(display.get_private().display, priv->window);
-#endif
- visible = false;
-
- if(options.fullscreen)
- display.restore_mode();
-}
-
-bool Window::event(const Event &evnt)
-{
-#ifdef WIN32
- WPARAM wp = evnt.wparam;
- LPARAM lp = evnt.lparam;
- switch(evnt.msg)
- {
- case WM_KEYDOWN:
- signal_key_press.emit(wp, 0, wp);
- break;
- case WM_KEYUP:
- signal_key_release.emit(wp, 0);
- break;
- case WM_LBUTTONDOWN:
- signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
- break;
- case WM_LBUTTONUP:
- signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
- break;
- case WM_MBUTTONDOWN:
- signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
- break;
- case WM_MBUTTONUP:
- signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
- break;
- case WM_RBUTTONDOWN:
- signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
- break;
- case WM_RBUTTONUP:
- signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
- break;
- case WM_MOUSEWHEEL:
- {
- unsigned btn = (HIWORD(wp)&0x8000) ? 5 : 4;
- signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), btn, 0);
- signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), btn, 0);
- }
- break;
- case WM_MOUSEMOVE:
- signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
- break;
- case WM_SIZE:
- options.width = LOWORD(lp);
- options.height = HIWORD(lp);
- signal_resize.emit(options.width, options.height);
- break;
- case WM_CLOSE:
- signal_close.emit();
- break;
- default:
- return false;
- }
-#else
- const XEvent &ev = evnt.xevent;
- switch(ev.type)
- {
- case ButtonPress:
- signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
- break;
- case ButtonRelease:
- signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
- break;
- case MotionNotify:
- signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y);
- break;
- case KeyPress:
- {
- char buf[16];
- XLookupString(const_cast<XKeyEvent *>(&ev.xkey), buf, sizeof(buf), 0, 0);
- // XXX Handle the result according to locale
- signal_key_press.emit(XKeycodeToKeysym(display.get_private().display, ev.xkey.keycode, 0), ev.xkey.state, buf[0]);
- }
- break;
- case KeyRelease:
- signal_key_release.emit(XKeycodeToKeysym(display.get_private().display, ev.xkey.keycode, 0), ev.xkey.state);
- break;
- case ConfigureNotify:
- if((ev.xconfigure.width==static_cast<int>(options.width) && ev.xconfigure.height==static_cast<int>(options.height)) == resizing)
- {
- options.width = ev.xconfigure.width;
- options.height = ev.xconfigure.height;
- resizing = false;
- signal_resize.emit(options.width, options.height);
- }
-#ifdef WITH_XF86VIDMODE
- if(options.fullscreen)
- {
- ::Display *dpy = display.get_private().display;
- int screen = DefaultScreen(dpy);
- XF86VidModeSetViewPort(dpy, screen, ev.xconfigure.x, ev.xconfigure.y);
- }
-#endif
- break;
- case ClientMessage:
- if(ev.xclient.data.l[0]==static_cast<long>(priv->wm_delete_window))
- signal_close.emit();
- break;
- case EnterNotify:
- if(options.fullscreen)
- XSetInputFocus(display.get_private().display, priv->window, RevertToParent, CurrentTime);
- break;
- case MapNotify:
- if(options.fullscreen)
- XGrabPointer(display.get_private().display, priv->window, true, None, GrabModeAsync, GrabModeAsync, priv->window, None, CurrentTime);
- break;
- default:
- return false;
- }
-#endif
- return true;
-}
-
-} // namespace Graphics
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GBASE_WINDOW_H_
-#define MSP_GBASE_WINDOW_H_
-
-#include <string>
-#include <sigc++/signal.h>
-#include "eventsource.h"
-
-namespace Msp {
-namespace Graphics {
-
-class Display;
-
-struct WindowOptions
-{
- unsigned width;
- unsigned height;
- bool fullscreen;
- bool resizable;
-
- WindowOptions();
-};
-
-class Window: public EventSource
-{
-public:
- struct Private;
- struct Event;
-
- sigc::signal<void> signal_close;
-
-protected:
- Display &display;
- WindowOptions options;
- bool visible;
- bool kbd_autorepeat;
- bool resizing;
- Private *priv;
-
-public:
- Window(Display &, unsigned w, unsigned h, bool fs = false);
- Window(Display &, const WindowOptions &);
-private:
- void init();
-public:
- virtual ~Window();
-
- void set_title(const std::string &);
- void reconfigure(const WindowOptions &);
- void set_keyboard_autorepeat(bool);
- bool get_keyboard_autorepeat() const { return kbd_autorepeat; }
- void show_cursor(bool);
- void warp_pointer(int, int);
-
- Display &get_display() const { return display; }
- const WindowOptions &get_options() const { return options; }
- virtual unsigned get_width() const { return options.width; }
- virtual unsigned get_height() const { return options.height; }
- const Private &get_private() const { return *priv; }
-
- void show();
- void hide();
-
- bool event(const Event &evnt);
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-#ifndef MSP_GBASE_WINDOW_PRIV_H_
-#define MSP_GBASE_WINDOW_PRIV_H_
-
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <X11/Xlib.h>
-#endif
-
-namespace Msp {
-namespace Graphics {
-
-#ifdef WIN32
-typedef HWND WindowHandle;
-#else
-typedef ::Window WindowHandle;
-#endif
-
-struct Window::Private
-{
- WindowHandle window;
-#ifndef WIN32
- Atom wm_delete_window;
- Cursor invisible_cursor;
-#endif
-};
-
-struct Window::Event
-{
-#ifdef WIN32
- UINT msg;
- WPARAM wparam;
- LPARAM lparam;
-#else
- XEvent xevent;
-#endif
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
--- /dev/null
+#include <iostream>
+#ifndef WIN32
+#include <X11/Xlib.h>
+#ifdef WITH_XF86VIDMODE
+#include <X11/extensions/xf86vmode.h>
+#endif
+#endif
+#include <msp/strings/format.h>
+#include <msp/strings/lexicalcast.h>
+#include "display.h"
+#include "window.h"
+#include "display_priv.h"
+
+using namespace std;
+
+namespace {
+
+bool error_flag = false;
+std::string error_msg;
+
+#ifndef WIN32
+int x_error_handler(Display *display, XErrorEvent *event)
+{
+ char err[128];
+ XGetErrorText(display, event->error_code, err, sizeof(err));
+
+ string request_code = Msp::lexical_cast(static_cast<int>(event->request_code));
+ char req[128];
+ XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req));
+
+ string msg = Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid);
+ if(error_flag)
+ cerr<<"Discarding error: "<<msg<<'\n';
+ else
+ {
+ cerr<<msg<<'\n';
+ error_msg = msg;
+ error_flag = true;
+ }
+
+ return 0;
+}
+#endif
+
+}
+
+namespace Msp {
+namespace Graphics {
+
+unsupported_video_mode::unsupported_video_mode(const VideoMode &mode):
+ runtime_error(format("%dx%d", mode.width, mode.height))
+{ }
+
+
+Display::Display(const string &disp_name):
+ priv(new Private)
+{
+#ifdef WIN32
+ (void)disp_name;
+
+ for(unsigned i=0;; ++i)
+ {
+ DEVMODE info;
+ if(!EnumDisplaySettings(0, i, &info))
+ break;
+
+ VideoMode mode(info.dmPelsWidth, info.dmPelsHeight);
+ mode.rate = info.dmDisplayFrequency;
+ modes.push_back(mode);
+ }
+
+ DEVMODE info;
+ if(EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &info))
+ {
+ orig_mode = VideoMode(info.dmPelsWidth, info.dmPelsHeight);
+ orig_mode.rate = info.dmDisplayFrequency;
+ }
+#else
+ if(disp_name.empty())
+ priv->display = XOpenDisplay(0);
+ else
+ priv->display = XOpenDisplay(disp_name.c_str());
+ if(!priv->display)
+ throw runtime_error("XOpenDisplay");
+
+ XSetErrorHandler(x_error_handler);
+
+#ifdef WITH_XF86VIDMODE
+ int screen = DefaultScreen(priv->display);
+
+ int nmodes;
+ XF86VidModeModeInfo **infos;
+ XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos);
+ for(int i=0; i<nmodes; ++i)
+ {
+ XF86VidModeModeInfo &info = *infos[i];
+
+ VideoMode mode(info.hdisplay, info.vdisplay);
+ if(info.htotal && info.vtotal)
+ mode.rate = info.dotclock/(info.htotal*info.vtotal);
+ modes.push_back(mode);
+ }
+
+ XFree(infos);
+
+ XF86VidModeModeLine modeline;
+ int dotclock;
+ XF86VidModeGetModeLine(priv->display, screen, &dotclock, &modeline);
+ orig_mode = VideoMode(modeline.hdisplay, modeline.vdisplay);
+ if(modeline.htotal && modeline.vtotal)
+ orig_mode.rate = dotclock/(modeline.htotal*modeline.vtotal);
+#endif
+#endif
+}
+
+Display::~Display()
+{
+#ifndef WIN32
+ XCloseDisplay(priv->display);
+ delete priv;
+#endif
+}
+
+void Display::add_window(Window &wnd)
+{
+ priv->windows[wnd.get_private().window] = &wnd;
+}
+
+void Display::remove_window(Window &wnd)
+{
+ priv->windows.erase(wnd.get_private().window);
+}
+
+void Display::set_mode(const VideoMode &mode)
+{
+#if defined(WIN32)
+ DEVMODE info;
+ info.dmSize = sizeof(DEVMODE);
+ info.dmFields = DM_PELSWIDTH|DM_PELSHEIGHT;
+ info.dmPelsWidth = mode.width;
+ info.dmPelsHeight = mode.height;
+ if(mode.rate)
+ {
+ info.dmFields |= DM_DISPLAYFREQUENCY;
+ info.dmDisplayFrequency = mode.rate;
+ }
+
+ LONG ret = ChangeDisplaySettings(&info, CDS_FULLSCREEN);
+ if(ret!=DISP_CHANGE_SUCCESSFUL)
+ throw unsupported_video_mode(mode);
+#elif defined(WITH_XF86VIDMODE)
+ int screen = DefaultScreen(priv->display);
+
+ int nmodes;
+ XF86VidModeModeInfo **infos;
+ XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos);
+ for(int i=0; i<nmodes; ++i)
+ {
+ XF86VidModeModeInfo &info = *infos[i];
+
+ unsigned rate = 0;
+ if(info.htotal && info.vtotal)
+ rate = info.dotclock/(info.htotal*info.vtotal);
+ if(info.hdisplay==mode.width && info.vdisplay==mode.height && (mode.rate==0 || rate==mode.rate))
+ {
+ XF86VidModeSwitchToMode(priv->display, screen, &info);
+ XF86VidModeSetViewPort(priv->display, screen, 0, 0);
+ return;
+ }
+ }
+
+ throw unsupported_video_mode(mode);
+#else
+ (void)mode;
+ throw runtime_error("no xf86vidmode support");
+#endif
+}
+
+void Display::tick()
+{
+ check_error();
+
+ while(1)
+ {
+#ifdef WIN32
+ MSG msg;
+ if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ DispatchMessage(&msg);
+ else
+ break;
+#else
+ int pending = XPending(priv->display);
+ if(pending==0)
+ break;
+
+ for(; pending--;)
+ {
+ Window::Event event;
+ XNextEvent(priv->display, &event.xevent);
+
+ check_error();
+
+ map<WindowHandle, Window *>::iterator j = priv->windows.find(event.xevent.xany.window);
+ if(j!=priv->windows.end())
+ {
+ /* Filter keyboard autorepeat. If this packet is a KeyRelease and
+ the next one is a KeyPress with the exact same parameters, they
+ indicate autorepeat and must be dropped. */
+ if(event.xevent.type==KeyRelease && !j->second->get_keyboard_autorepeat() && pending>0)
+ {
+ XKeyEvent &kev = event.xevent.xkey;
+ XEvent ev2;
+ XPeekEvent(priv->display, &ev2);
+ if(ev2.type==KeyPress)
+ {
+ XKeyEvent &kev2 = ev2.xkey;
+ if(kev2.window==kev.window && kev2.time==kev.time && kev2.keycode==kev.keycode)
+ {
+ XNextEvent(priv->display, &ev2);
+ --pending;
+ continue;
+ }
+ }
+ }
+
+ j->second->event(event);
+ }
+ }
+#endif
+ }
+}
+
+void Display::check_error()
+{
+ if(error_flag)
+ {
+ error_flag = false;
+ throw runtime_error(error_msg);
+ }
+}
+
+} // namespace Graphics
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GRAPHICS_DISPLAY_H_
+#define MSP_GRAPHICS_DISPLAY_H_
+
+#include <list>
+#include <map>
+#include <stdexcept>
+#include <string>
+
+namespace Msp {
+namespace Graphics {
+
+class Window;
+
+struct VideoMode
+{
+ unsigned width;
+ unsigned height;
+ unsigned rate;
+
+ VideoMode(): width(0), height(0), rate(0) { }
+ VideoMode(unsigned w, unsigned h): width(w), height(h), rate(0) { }
+};
+
+
+class unsupported_video_mode: public std::runtime_error
+{
+public:
+ unsupported_video_mode(const VideoMode &);
+ virtual ~unsupported_video_mode() throw () { }
+};
+
+
+class Display
+{
+public:
+ struct Private;
+
+private:
+ std::list<VideoMode> modes;
+ VideoMode orig_mode;
+ Private *priv;
+
+public:
+ Display(const std::string &disp_name = std::string());
+ ~Display();
+
+ const Private &get_private() const { return *priv; }
+
+ void add_window(Window &);
+ void remove_window(Window &);
+
+ const std::list<VideoMode> &get_modes() const { return modes; }
+ void set_mode(const VideoMode &);
+ void restore_mode() { set_mode(orig_mode); }
+
+ void tick();
+ void check_error();
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_GRAPHICS_DISPLAY_PRIV_H_
+#define MSP_GRAPHICS_DISPLAY_PRIV_H_
+
+#include "window_priv.h"
+
+namespace Msp {
+namespace Graphics {
+
+struct Display::Private
+{
+#ifndef WIN32
+ ::Display *display;
+#endif
+ std::map<WindowHandle, Window *> windows;
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <stdexcept>
+#ifndef WIN32
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+#include <X11/Xutil.h>
+#endif
+#include "display.h"
+#include "drawcontext.h"
+#include "window.h"
+#include "display_priv.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Graphics {
+
+struct DrawContext::Private
+{
+#ifndef WIN32
+ XImage *image;
+ bool use_shm;
+ XShmSegmentInfo shminfo;
+#endif
+};
+
+DrawContext::DrawContext(Window &w):
+ display(w.get_display()),
+ window(w)
+{
+#ifdef WIN32
+ throw runtime_error("no DrawContext support on windows");
+#else
+ priv = new Private;
+
+ ::Display *dpy = display.get_private().display;
+
+ priv->use_shm = XShmQueryExtension(dpy);
+
+ XWindowAttributes wa;
+ XGetWindowAttributes(dpy, window.get_private().window, &wa);
+
+ if(priv->use_shm)
+ {
+ priv->image = XShmCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, &priv->shminfo, wa.width, wa.height);
+ if(!priv->image)
+ throw runtime_error("XShmCreateImage");
+
+ priv->shminfo.shmid = shmget(IPC_PRIVATE, priv->image->bytes_per_line*priv->image->height, IPC_CREAT|0666);
+ priv->shminfo.shmaddr=priv->image->data = reinterpret_cast<char *>(shmat(priv->shminfo.shmid, 0, 0));
+ priv->shminfo.readOnly = false;
+
+ XShmAttach(dpy, &priv->shminfo);
+
+ XSync(dpy, false);
+ display.check_error();
+ }
+ else
+ {
+ priv->image = XCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, 0, wa.width, wa.height, 8, 0);
+ if(!priv->image)
+ throw runtime_error("XCreateImage");
+ priv->image->data = new char[priv->image->bytes_per_line*priv->image->height];
+ }
+#endif
+}
+
+DrawContext::~DrawContext()
+{
+#ifndef WIN32
+ if(priv->use_shm)
+ {
+ XShmDetach(display.get_private().display, &priv->shminfo);
+ shmdt(priv->shminfo.shmaddr);
+ shmctl(priv->shminfo.shmid, IPC_RMID, 0);
+ }
+
+ XDestroyImage(priv->image);
+#endif
+
+ delete priv;
+}
+
+unsigned DrawContext::get_depth() const
+{
+#ifdef WIN32
+ return 0;
+#else
+ return priv->image->bits_per_pixel;
+#endif
+}
+
+unsigned char *DrawContext::get_data()
+{
+#ifdef WIN32
+ return 0;
+#else
+ return reinterpret_cast<unsigned char *>(priv->image->data);
+#endif
+}
+
+void DrawContext::update()
+{
+#ifndef WIN32
+ ::Display *dpy = display.get_private().display;
+ WindowHandle wnd = window.get_private().window;
+
+ GC gc = XCreateGC(dpy, wnd, 0, 0);
+
+ if(priv->use_shm)
+ XShmPutImage(dpy, wnd, gc, priv->image, 0, 0, 0, 0, priv->image->width, priv->image->height, false);
+ else
+ XPutImage(dpy, wnd, gc, priv->image, 0, 0, 0, 0, priv->image->width, priv->image->height);
+
+ XFreeGC(dpy, gc);
+#endif
+}
+
+} // namespace Graphics
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GRAPHICS_DRAWCONTEXT_H_
+#define MSP_GRAPHICS_DRAWCONTEXT_H_
+
+namespace Msp {
+namespace Graphics {
+
+class Display;
+class Window;
+
+class DrawContext
+{
+private:
+ struct Private;
+
+ Display &display;
+ Window &window;
+ Private *priv;
+
+public:
+ DrawContext(Window &);
+ ~DrawContext();
+
+ Window &get_window() const { return window; }
+ unsigned get_depth() const;
+ unsigned char *get_data();
+ void update();
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_GRAPHICS_EVENTSOURCE_H_
+#define MSP_GRAPHICS_EVENTSOURCE_H_
+
+namespace Msp {
+namespace Graphics {
+
+class EventSource
+{
+public:
+ sigc::signal<void, unsigned, unsigned, unsigned> signal_key_press;
+ sigc::signal<void, unsigned, unsigned> signal_key_release;
+ sigc::signal<void, int, int, unsigned, unsigned> signal_button_press;
+ sigc::signal<void, int, int, unsigned, unsigned> signal_button_release;
+ sigc::signal<void, int, int> signal_pointer_motion;
+ sigc::signal<void, unsigned, unsigned> signal_resize;
+
+protected:
+ EventSource() { }
+public:
+ virtual ~EventSource() { }
+
+ virtual unsigned get_width() const = 0;
+ virtual unsigned get_height() const = 0;
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <vector>
+#ifdef WIN32
+#include <windows.h>
+#endif
+#ifdef WITH_OPENGL
+#include <GL/gl.h>
+#ifndef WIN32
+#include <GL/glx.h>
+#endif
+#endif
+#include <msp/core/application.h>
+#include <msp/strings/format.h>
+#include "display.h"
+#include "glcontext.h"
+#include "window.h"
+#include "display_priv.h"
+
+namespace Msp {
+namespace Graphics {
+
+GLOptions::GLOptions():
+ alpha(false),
+ stencil(false),
+ doublebuffer(true),
+ multisample(0)
+{ }
+
+
+unsupported_gl_mode::unsupported_gl_mode(const GLOptions &opts):
+ runtime_error(format("{ .alpha=%s, .stencil=%s, .doublebuffer=%s, .multisample=%d }",
+ opts.alpha, opts.stencil, opts.doublebuffer, opts.multisample))
+{ }
+
+
+#ifdef WITH_OPENGL
+#ifdef WIN32
+typedef HGLRC Context;
+#else
+typedef GLXContext Context;
+#endif
+
+struct GLContext::Private
+{
+ Context context;
+#ifndef WIN32
+ // In X11, we need to create a window with the chosen visual
+ WindowHandle subwnd;
+#endif
+};
+#endif
+
+
+GLContext::GLContext(Window &wnd, const GLOptions &opts):
+ display(wnd.get_display()),
+ window(wnd)
+{
+#ifdef WITH_OPENGL
+ priv = new Private;
+
+#ifdef WIN32
+ HDC dc = GetDC(window.get_private().window);
+
+ PIXELFORMATDESCRIPTOR pfd;
+ memset(&pfd, 0, sizeof(pfd));
+
+ pfd.nSize = sizeof(pfd);
+ pfd.nVersion = 1;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+ if(opts.doublebuffer)
+ pfd.dwFlags |= PFD_DOUBLEBUFFER;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ if(opts.alpha)
+ pfd.cAlphaBits = 1;
+ pfd.cDepthBits = 1;
+ if(opts.stencil)
+ pfd.cStencilBits = 1;
+
+ int pf_index = ChoosePixelFormat(dc, &pfd);
+ if(!pf_index)
+ throw unsupported_gl_mode(opts);
+ SetPixelFormat(dc, pf_index, &pfd);
+
+ priv->context = wglCreateContext(dc);
+ wglMakeCurrent(dc, priv->context);
+
+ ReleaseDC(window.get_private().window, dc);
+#else
+ std::vector<int> attribs;
+
+ attribs.push_back(GLX_RGBA);
+ attribs.push_back(GLX_DEPTH_SIZE);
+ attribs.push_back(1);
+
+ if(opts.alpha)
+ {
+ attribs.push_back(GLX_ALPHA_SIZE);
+ attribs.push_back(1);
+ }
+
+ if(opts.stencil)
+ {
+ attribs.push_back(GLX_STENCIL_SIZE);
+ attribs.push_back(1);
+ }
+
+ if(opts.doublebuffer)
+ attribs.push_back(GLX_DOUBLEBUFFER);
+
+ if(opts.multisample>0)
+ {
+ attribs.push_back(GLX_SAMPLE_BUFFERS_ARB);
+ attribs.push_back(opts.multisample);
+ }
+
+ attribs.push_back(0);
+
+ ::Display *dpy = display.get_private().display;
+
+ XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front());
+ if(!vi)
+ throw unsupported_gl_mode(opts);
+ priv->context = glXCreateContext(dpy, vi, 0, true);
+
+ XSetWindowAttributes attr;
+ attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
+
+ priv->subwnd = XCreateWindow(dpy, window.get_private().window, 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr);
+ XMapWindow(dpy, priv->subwnd);
+
+ XFree(vi);
+
+ glXMakeCurrent(dpy, priv->subwnd, priv->context);
+#endif
+#else
+ (void)wnd;
+ (void)opts;
+ throw runtime_error("no OpenGL support");
+#endif
+
+ window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized));
+}
+
+GLContext::~GLContext()
+{
+#ifdef WITH_OPENGL
+#ifdef WIN32
+ wglMakeCurrent(0, 0);
+ wglDeleteContext(priv->context);
+#else
+ ::Display *dpy = display.get_private().display;
+
+ glXMakeCurrent(dpy, 0, 0);
+ glXDestroyContext(dpy, priv->context);
+ XDestroyWindow(dpy, priv->subwnd);
+#endif
+ delete priv;
+#endif
+}
+
+void GLContext::swap_buffers()
+{
+#ifdef WITH_OPENGL
+#ifdef WIN32
+ HDC dc = GetDC(window.get_private().window);
+ SwapBuffers(dc);
+ ReleaseDC(window.get_private().window, dc);
+#else
+ glXSwapBuffers(display.get_private().display, priv->subwnd);
+#endif
+#endif
+}
+
+void GLContext::window_resized(unsigned w, unsigned h)
+{
+#ifdef WITH_OPENGL
+#ifndef WIN32
+ XMoveResizeWindow(display.get_private().display, priv->subwnd, 0, 0, w, h);
+#endif
+ glViewport(0, 0, w, h);
+#else
+ (void)w;
+ (void)h;
+#endif
+}
+
+} // namespace Graphics
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GRAPHICS_GLCONTEXT_H_
+#define MSP_GRAPHICS_GLCONTEXT_H_
+
+#include <stdexcept>
+
+namespace Msp {
+namespace Graphics {
+
+class Display;
+class Window;
+
+struct GLOptions
+{
+ bool alpha;
+ bool stencil;
+ bool doublebuffer;
+ unsigned multisample;
+
+ GLOptions();
+};
+
+
+class unsupported_gl_mode: public std::runtime_error
+{
+public:
+ unsupported_gl_mode(const GLOptions &);
+ virtual ~unsupported_gl_mode() throw () { }
+};
+
+
+class GLContext
+{
+private:
+ struct Private;
+
+ Display &display;
+ Window &window;
+ Private *priv;
+
+public:
+ GLContext(Window &wnd, const GLOptions &opts = GLOptions());
+ ~GLContext();
+
+ void swap_buffers();
+private:
+ void window_resized(unsigned, unsigned);
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifdef WITH_DEVIL
+#include <IL/il.h>
+#endif
+#ifdef WITH_LIBPNG
+#include <png.h>
+#include <msp/io/file.h>
+#include <msp/io/memory.h>
+#endif
+#include "image.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Graphics {
+
+struct Image::Private
+{
+#ifdef WITH_DEVIL
+ unsigned id;
+#endif
+#ifdef WITH_LIBPNG
+ PixelFormat fmt;
+ unsigned width;
+ unsigned height;
+ char *data;
+#endif
+
+ Private();
+};
+
+Image::Private::Private()
+{
+#ifdef WITH_DEVIL
+ id = 0;
+#endif
+#ifdef WITH_LIBPNG
+ fmt = RGB;
+ width = 0;
+ height = 0;
+ data = 0;
+#endif
+}
+
+
+namespace {
+
+#ifdef WITH_LIBPNG
+void read(png_struct *png, png_byte *data, png_size_t size)
+{
+ IO::Base *in = reinterpret_cast<IO::Base *>(png_get_io_ptr(png));
+ in->read(reinterpret_cast<char *>(data), size);
+}
+
+void load_png(IO::Base &in, Image::Private &priv)
+{
+ png_struct *png = 0;
+ png_info *info = 0;
+ priv.data = 0;
+
+ try
+ {
+ png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ info = png_create_info_struct(png);
+
+ if(setjmp(png_jmpbuf(png)))
+ throw bad_image_data("PNG error");
+
+ png_set_read_fn(png, &in, read);
+ png_read_info(png, info);
+ png_uint_32 width;
+ png_uint_32 height;
+ int depth;
+ int color;
+ png_get_IHDR(png, info, &width, &height, &depth, &color, 0, 0, 0);
+ priv.width = width;
+ priv.height = height;
+ if(depth!=8)
+ throw unsupported_image_format("depth!=8");
+ switch(color)
+ {
+ case PNG_COLOR_TYPE_PALETTE: priv.fmt = COLOR_INDEX; break;
+ case PNG_COLOR_TYPE_GRAY: priv.fmt = LUMINANCE; break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA: priv.fmt = LUMINANCE_ALPHA; break;
+ case PNG_COLOR_TYPE_RGB: priv.fmt = RGB; break;
+ case PNG_COLOR_TYPE_RGB_ALPHA: priv.fmt = RGBA; break;
+ default: throw unsupported_image_format("unknown color type");
+ }
+
+ unsigned nchans = png_get_channels(png, info);
+ if(nchans==4 && priv.fmt==RGB)
+ png_set_strip_alpha(png);
+
+ unsigned rowstride = priv.width*nchans;
+ priv.data = new char[rowstride*priv.height];
+ for(unsigned y=0; y<priv.height; ++y)
+ png_read_row(png, reinterpret_cast<png_byte *>(priv.data+rowstride*(priv.height-1-y)), 0);
+
+ png_read_end(png, 0);
+ png_destroy_read_struct(&png, &info, 0);
+ }
+ catch(...)
+ {
+ png_destroy_read_struct(&png, &info, 0);
+ delete[] priv.data;
+ throw;
+ }
+}
+#endif
+
+#ifdef WITH_DEVIL
+void ensure_devil_image(unsigned &id)
+{
+ static bool init_done = false;
+
+ if(!init_done)
+ {
+ ilInit();
+ ilEnable(IL_ORIGIN_SET);
+ ilOriginFunc(IL_ORIGIN_LOWER_LEFT);
+ init_done = true;
+ }
+
+ if(!id)
+ ilGenImages(1, &id);
+}
+#endif
+
+}
+
+
+Image::Image():
+ priv(new Private)
+{
+#if !defined(WITH_DEVIL) && !defined(WITH_LIBPNG)
+ throw runtime_error("no image support");
+#endif
+}
+
+Image::~Image()
+{
+#ifdef WITH_DEVIL
+ if(priv->id)
+ ilDeleteImages(1, &priv->id);
+#endif
+#ifdef WITH_LIBPNG
+ delete[] priv->data;
+#endif
+ delete priv;
+}
+
+void Image::load_file(const string &fn)
+{
+#ifdef WITH_LIBPNG
+ if(fn.size()>4 && !fn.compare(fn.size()-4, 4, ".png"))
+ {
+ IO::BufferedFile file(fn);
+ load_png(file, *priv);
+ }
+ else
+#endif
+ {
+#ifdef WITH_DEVIL
+ ensure_devil_image(priv->id);
+ ilBindImage(priv->id);
+ if(!ilLoadImage(const_cast<char *>(fn.c_str())))
+ throw bad_image_data("IL error");
+#else
+ throw unsupported_image_format("DevIL needed for non-PNG images");
+#endif
+ }
+ (void)fn;
+}
+
+void Image::load_memory(const void *data, unsigned size)
+{
+#ifdef WITH_LIBPNG
+ if(!png_sig_cmp(reinterpret_cast<png_byte *>(const_cast<void *>(data)), 0, 8))
+ {
+ IO::Memory mem(reinterpret_cast<const char *>(data), size);
+ load_png(mem, *priv);
+ }
+ else
+#endif
+ {
+#ifdef WITH_DEVIL
+ ensure_devil_image(priv->id);
+ ilBindImage(priv->id);
+ if(!ilLoadL(IL_TYPE_UNKNOWN, const_cast<void *>(data), size))
+ throw bad_image_data("IL error");
+#else
+ throw unsupported_image_format("DevIL needed for non-PNG images");
+#endif
+ }
+ (void)data;
+ (void)size;
+}
+
+PixelFormat Image::get_format() const
+{
+#ifdef WITH_LIBPNG
+ if(priv->data)
+ return priv->fmt;
+#endif
+#ifdef WITH_DEVIL
+ if(priv->id)
+ {
+ ilBindImage(priv->id);
+ switch(ilGetInteger(IL_IMAGE_FORMAT))
+ {
+ case IL_COLOR_INDEX: return COLOR_INDEX;
+ case IL_LUMINANCE: return LUMINANCE;
+ case IL_LUMINANCE_ALPHA: return LUMINANCE_ALPHA;
+ case IL_RGB: return RGB;
+ case IL_RGBA: return RGBA;
+ case IL_BGR: return BGR;
+ case IL_BGRA: return BGRA;
+ // XXX bad, should throw when loading
+ default: throw invalid_argument("unknown pixel format in image");
+ }
+ }
+#endif
+ return RGB;
+}
+
+unsigned Image::get_width() const
+{
+#ifdef WITH_LIBPNG
+ if(priv->data)
+ return priv->width;
+#endif
+#ifdef WITH_DEVIL
+ if(priv->id)
+ {
+ ilBindImage(priv->id);
+ return ilGetInteger(IL_IMAGE_WIDTH);
+ }
+#endif
+ return 0;
+}
+
+unsigned Image::get_height() const
+{
+#ifdef WITH_LIBPNG
+ if(priv->data)
+ return priv->height;
+#endif
+#ifdef WITH_DEVIL
+ if(priv->id)
+ {
+ ilBindImage(priv->id);
+ return ilGetInteger(IL_IMAGE_HEIGHT);
+ }
+#endif
+ return 0;
+}
+
+const void *Image::get_data() const
+{
+#ifdef WITH_LIBPNG
+ if(priv->data)
+ return priv->data;
+#endif
+#ifdef WITH_DEVIL
+ if(priv->id)
+ {
+ ilBindImage(priv->id);
+ return ilGetData();
+ }
+#endif
+ return 0;
+}
+
+} // namespace Graphics
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GRAPHICS_IMAGE_H_
+#define MSP_GRAPHICS_IMAGE_H_
+
+#include <string>
+#include "pixelformat.h"
+
+namespace Msp {
+namespace Graphics {
+
+class unsupported_image_format: public std::runtime_error
+{
+public:
+ unsupported_image_format(const std::string &w): std::runtime_error(w) { }
+ virtual ~unsupported_image_format() throw() { }
+};
+
+class bad_image_data: public std::runtime_error
+{
+public:
+ bad_image_data(const std::string &w): std::runtime_error(w) { }
+ virtual ~bad_image_data() throw() { }
+};
+
+
+class Image
+{
+public:
+ struct Private;
+
+private:
+ Private *priv;
+
+public:
+ Image();
+ ~Image();
+
+ void load_file(const std::string &);
+ void load_memory(const void *, unsigned);
+ PixelFormat get_format() const;
+ unsigned get_width() const;
+ unsigned get_height() const;
+ const void *get_data() const;
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_GRAPHICS_PIXELFORMAT_H_
+#define MSP_GRAPHICS_PIXELFORMAT_H_
+
+namespace Msp {
+namespace Graphics {
+
+enum PixelFormat
+{
+ COLOR_INDEX,
+ LUMINANCE,
+ LUMINANCE_ALPHA,
+ RGB,
+ RGBA,
+ BGR,
+ BGRA
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+#include "simplewindow.h"
+
+namespace Msp {
+namespace Graphics {
+
+SimpleWindow::SimpleWindow(unsigned w, unsigned h, bool fs):
+ Window(dpy, w, h, fs)
+{ }
+
+void SimpleWindow::tick()
+{
+ dpy.tick();
+}
+
+
+SimpleGLWindow::SimpleGLWindow(unsigned w, unsigned h, bool fs):
+ SimpleWindow(w, h, fs),
+ gl_ctx(*this)
+{ }
+
+void SimpleGLWindow::swap_buffers()
+{
+ gl_ctx.swap_buffers();
+}
+
+} // namespace Graphics
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GRAPHICS_SIMPLEWINDOW_H_
+#define MSP_GRAPHICS_SIMPLEWINDOW_H_
+
+#include "display.h"
+#include "glcontext.h"
+#include "window.h"
+
+namespace Msp {
+namespace Graphics {
+
+/**
+Helper class for SimpleWindow.
+*/
+class SimpleWindowBase
+{
+protected:
+ Display dpy;
+
+ SimpleWindowBase() { }
+};
+
+
+/**
+A simplified Window that encapsulates a Display.
+*/
+class SimpleWindow: public SimpleWindowBase, public Window
+{
+public:
+ SimpleWindow(unsigned, unsigned, bool =false);
+
+ void tick();
+};
+
+
+/**
+A SimpleWindow bundled with a GLContext.
+*/
+class SimpleGLWindow: public SimpleWindow
+{
+private:
+ GLContext gl_ctx;
+
+public:
+ SimpleGLWindow(unsigned, unsigned, bool =false);
+ GLContext &get_gl_context() { return gl_ctx; }
+ void swap_buffers();
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <vector>
+#ifndef WIN32
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#ifdef WITH_XF86VIDMODE
+#include <X11/extensions/xf86vmode.h>
+#endif
+#else
+#include <windowsx.h>
+#endif
+#include <msp/core/application.h>
+#include "display.h"
+#include "window.h"
+#include "display_priv.h"
+
+using namespace std;
+
+namespace {
+
+#ifdef WIN32
+LRESULT CALLBACK wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ if(msg==WM_CREATE)
+ {
+ CREATESTRUCT *cs = reinterpret_cast<CREATESTRUCT *>(lparam);
+ SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(cs->lpCreateParams));
+ }
+ else
+ {
+ Msp::Graphics::Window *wnd = reinterpret_cast<Msp::Graphics::Window *>(GetWindowLong(hwnd, 0));
+ Msp::Graphics::Window::Event ev;
+ ev.msg = msg;
+ ev.wparam = wparam;
+ ev.lparam = lparam;
+ if(wnd && wnd->event(ev))
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+#else
+Bool match_event_type(Display *, XEvent *event, XPointer arg)
+{
+ return event->type==*reinterpret_cast<int *>(arg);
+}
+#endif
+
+}
+
+namespace Msp {
+namespace Graphics {
+
+WindowOptions::WindowOptions():
+ width(640),
+ height(480),
+ fullscreen(false),
+ resizable(false)
+{ }
+
+
+Window::Window(Display &dpy, unsigned w, unsigned h, bool fs):
+ display(dpy)
+{
+ options.width = w;
+ options.height = h;
+ options.fullscreen = fs;
+
+ init();
+}
+
+Window::Window(Display &dpy, const WindowOptions &opts):
+ display(dpy),
+ options(opts)
+{
+ init();
+}
+
+void Window::init()
+{
+ visible = false;
+ kbd_autorepeat = true;
+ resizing = false;
+ priv = new Private;
+
+#ifdef WIN32
+ static bool wndclass_created = false;
+
+ if(!wndclass_created)
+ {
+ WNDCLASSEX wndcl;
+
+ wndcl.cbSize = sizeof(WNDCLASSEX);
+ wndcl.style = 0;
+ wndcl.lpfnWndProc = &wndproc_;
+ wndcl.cbClsExtra = 0;
+ wndcl.cbWndExtra = sizeof(Window *);
+ wndcl.hInstance = reinterpret_cast<HINSTANCE>(Application::get_data());
+ wndcl.hIcon = 0;
+ wndcl.hCursor = LoadCursor(0, IDC_ARROW);
+ wndcl.hbrBackground = 0;
+ wndcl.lpszMenuName = 0;
+ wndcl.lpszClassName = "mspgbase";
+ wndcl.hIconSm = 0;
+
+ if(!RegisterClassEx(&wndcl))
+ throw system_error("RegisterClassEx");
+
+ wndclass_created = true;
+ }
+
+ RECT rect;
+ SetRect(&rect, 0, 0, options.width, options.height);
+
+ int style = (options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW);
+ if(!options.resizable)
+ style &= ~WS_THICKFRAME;
+ int exstyle = (options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW);
+ AdjustWindowRectEx(&rect, style, false, exstyle);
+
+ priv->window = CreateWindowEx(exstyle,
+ "mspgbase",
+ "Window",
+ style,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ rect.right-rect.left, rect.bottom-rect.top,
+ 0,
+ 0,
+ reinterpret_cast<HINSTANCE>(Application::get_data()),
+ this);
+ if(!priv->window)
+ throw system_error("CreateWindowEx");
+
+#else
+ ::Display *dpy = display.get_private().display;
+
+ priv->wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", true);
+ priv->invisible_cursor = 0;
+
+ XSetWindowAttributes attr;
+ attr.override_redirect = options.fullscreen;
+ attr.event_mask = ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask;
+
+ priv->window = XCreateWindow(dpy,
+ DefaultRootWindow(dpy),
+ 0, 0,
+ options.width, options.height,
+ 0,
+ CopyFromParent,
+ InputOutput,
+ CopyFromParent,
+ CWOverrideRedirect|CWEventMask, &attr);
+
+ XSetWMProtocols(dpy, priv->window, &priv->wm_delete_window, 1);
+
+ if(!options.resizable)
+ {
+ XSizeHints hints;
+ hints.flags = PMinSize|PMaxSize;
+ hints.min_width=hints.max_width = options.width;
+ hints.min_height=hints.max_height = options.height;
+ XSetWMNormalHints(dpy, priv->window, &hints);
+ }
+
+#endif
+
+ display.add_window(*this);
+ display.check_error();
+}
+
+Window::~Window()
+{
+ if(priv->window)
+#ifdef WIN32
+ CloseWindow(priv->window);
+#else
+ XDestroyWindow(display.get_private().display, priv->window);
+
+ if(priv->invisible_cursor)
+ XFreeCursor(display.get_private().display, priv->invisible_cursor);
+#endif
+
+ display.remove_window(*this);
+
+ if(options.fullscreen)
+ display.restore_mode();
+
+ delete priv;
+}
+
+void Window::set_title(const string &title)
+{
+#ifdef WIN32
+ SetWindowText(priv->window, title.c_str());
+#else
+ vector<unsigned char> buf(title.begin(), title.end());
+ XTextProperty prop;
+ prop.value = &buf[0];
+ prop.encoding = XA_STRING;
+ prop.format = 8;
+ prop.nitems = title.size();
+ XSetWMName(display.get_private().display, priv->window, &prop);
+ display.check_error();
+#endif
+}
+
+void Window::reconfigure(const WindowOptions &opts)
+{
+ bool fullscreen_changed = (opts.fullscreen!=options.fullscreen);
+ resizing = (opts.width!=options.width || opts.height!=options.height);
+
+ options = opts;
+
+#ifdef WIN32
+ RECT rect;
+ SetRect(&rect, 0, 0, options.width, options.height);
+
+ int style = (options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW);
+ if(!options.resizable)
+ style &= ~WS_THICKFRAME;
+ int exstyle = (options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW);
+ AdjustWindowRectEx(&rect, style, false, exstyle);
+
+ if(fullscreen_changed)
+ {
+ hide();
+ SetWindowLong(priv->window, GWL_EXSTYLE, exstyle);
+ SetWindowLong(priv->window, GWL_STYLE, style);
+ show();
+ }
+
+ if(options.fullscreen)
+ SetWindowPos(priv->window, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOZORDER);
+ else
+ SetWindowPos(priv->window, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE|SWP_NOZORDER);
+#else
+ ::Display *dpy = display.get_private().display;
+
+ bool was_visible = visible;
+ if(fullscreen_changed)
+ {
+ if(was_visible)
+ {
+ hide();
+
+ // Wait for the window to be unmapped. This makes window managers happy.
+ XEvent ev;
+ int ev_type = UnmapNotify;
+ XPeekIfEvent(dpy, &ev, match_event_type, reinterpret_cast<char *>(&ev_type));
+ }
+
+ XSetWindowAttributes attr;
+ attr.override_redirect = options.fullscreen;
+ XChangeWindowAttributes(dpy, priv->window, CWOverrideRedirect, &attr);
+ }
+
+ XSizeHints hints;
+ if(options.resizable)
+ hints.flags = 0;
+ else
+ {
+ hints.flags = PMinSize|PMaxSize;
+ hints.min_width=hints.max_width = options.width;
+ hints.min_height=hints.max_height = options.height;
+ }
+ XSetWMNormalHints(dpy, priv->window, &hints);
+
+ if(options.fullscreen)
+ XMoveResizeWindow(dpy, priv->window, 0, 0, options.width, options.height);
+ else
+ XResizeWindow(dpy, priv->window, options.width, options.height);
+
+ if(fullscreen_changed)
+ {
+ if(was_visible)
+ show();
+ }
+#endif
+
+ if(visible)
+ {
+ if(options.fullscreen)
+ display.set_mode(VideoMode(options.width, options.height));
+ else if(fullscreen_changed)
+ display.restore_mode();
+ }
+}
+
+void Window::set_keyboard_autorepeat(bool r)
+{
+ kbd_autorepeat = r;
+}
+
+void Window::show_cursor(bool s)
+{
+#ifdef WIN32
+ ShowCursor(s);
+#else
+ ::Display *dpy = display.get_private().display;
+
+ if(s)
+ XUndefineCursor(dpy, priv->window);
+ else
+ {
+ if(!priv->invisible_cursor)
+ {
+ int screen = DefaultScreen(dpy);
+
+ Pixmap pm = XCreatePixmap(dpy, priv->window, 1, 1, 1);
+ GC gc = XCreateGC(dpy, pm, 0, 0);
+ XSetFunction(dpy, gc, GXclear);
+ XDrawPoint(dpy, pm, gc, 0, 0);
+ XFreeGC(dpy, gc);
+
+ XColor black;
+ black.pixel = BlackPixel(dpy, screen);
+ XQueryColor(dpy, DefaultColormap(dpy, screen), &black);
+
+ priv->invisible_cursor = XCreatePixmapCursor(dpy, pm, pm, &black, &black, 0, 0);
+
+ XFreePixmap(dpy, pm);
+ }
+ XDefineCursor(dpy, priv->window, priv->invisible_cursor);
+ }
+#endif
+}
+
+void Window::warp_pointer(int x, int y)
+{
+#ifndef WIN32
+ XWarpPointer(display.get_private().display, None, priv->window, 0, 0, 0, 0, x, y);
+#else
+ (void)x;
+ (void)y;
+#endif
+}
+
+void Window::show()
+{
+#ifdef WIN32
+ ShowWindow(priv->window, SW_SHOWNORMAL);
+#else
+ XMapRaised(display.get_private().display, priv->window);
+#endif
+ visible = true;
+
+ if(options.fullscreen)
+ {
+ display.set_mode(VideoMode(options.width, options.height));
+#ifndef WIN32
+ XWarpPointer(display.get_private().display, None, priv->window, 0, 0, 0, 0, options.width/2, options.height/2);
+#endif
+ }
+}
+
+void Window::hide()
+{
+#ifdef WIN32
+ ShowWindow(priv->window, SW_HIDE);
+#else
+ XUnmapWindow(display.get_private().display, priv->window);
+#endif
+ visible = false;
+
+ if(options.fullscreen)
+ display.restore_mode();
+}
+
+bool Window::event(const Event &evnt)
+{
+#ifdef WIN32
+ WPARAM wp = evnt.wparam;
+ LPARAM lp = evnt.lparam;
+ switch(evnt.msg)
+ {
+ case WM_KEYDOWN:
+ signal_key_press.emit(wp, 0, wp);
+ break;
+ case WM_KEYUP:
+ signal_key_release.emit(wp, 0);
+ break;
+ case WM_LBUTTONDOWN:
+ signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
+ break;
+ case WM_LBUTTONUP:
+ signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
+ break;
+ case WM_MBUTTONDOWN:
+ signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
+ break;
+ case WM_MBUTTONUP:
+ signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
+ break;
+ case WM_RBUTTONDOWN:
+ signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
+ break;
+ case WM_RBUTTONUP:
+ signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
+ break;
+ case WM_MOUSEWHEEL:
+ {
+ unsigned btn = (HIWORD(wp)&0x8000) ? 5 : 4;
+ signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), btn, 0);
+ signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), btn, 0);
+ }
+ break;
+ case WM_MOUSEMOVE:
+ signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
+ break;
+ case WM_SIZE:
+ options.width = LOWORD(lp);
+ options.height = HIWORD(lp);
+ signal_resize.emit(options.width, options.height);
+ break;
+ case WM_CLOSE:
+ signal_close.emit();
+ break;
+ default:
+ return false;
+ }
+#else
+ const XEvent &ev = evnt.xevent;
+ switch(ev.type)
+ {
+ case ButtonPress:
+ signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
+ break;
+ case ButtonRelease:
+ signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
+ break;
+ case MotionNotify:
+ signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y);
+ break;
+ case KeyPress:
+ {
+ char buf[16];
+ XLookupString(const_cast<XKeyEvent *>(&ev.xkey), buf, sizeof(buf), 0, 0);
+ // XXX Handle the result according to locale
+ signal_key_press.emit(XKeycodeToKeysym(display.get_private().display, ev.xkey.keycode, 0), ev.xkey.state, buf[0]);
+ }
+ break;
+ case KeyRelease:
+ signal_key_release.emit(XKeycodeToKeysym(display.get_private().display, ev.xkey.keycode, 0), ev.xkey.state);
+ break;
+ case ConfigureNotify:
+ if((ev.xconfigure.width==static_cast<int>(options.width) && ev.xconfigure.height==static_cast<int>(options.height)) == resizing)
+ {
+ options.width = ev.xconfigure.width;
+ options.height = ev.xconfigure.height;
+ resizing = false;
+ signal_resize.emit(options.width, options.height);
+ }
+#ifdef WITH_XF86VIDMODE
+ if(options.fullscreen)
+ {
+ ::Display *dpy = display.get_private().display;
+ int screen = DefaultScreen(dpy);
+ XF86VidModeSetViewPort(dpy, screen, ev.xconfigure.x, ev.xconfigure.y);
+ }
+#endif
+ break;
+ case ClientMessage:
+ if(ev.xclient.data.l[0]==static_cast<long>(priv->wm_delete_window))
+ signal_close.emit();
+ break;
+ case EnterNotify:
+ if(options.fullscreen)
+ XSetInputFocus(display.get_private().display, priv->window, RevertToParent, CurrentTime);
+ break;
+ case MapNotify:
+ if(options.fullscreen)
+ XGrabPointer(display.get_private().display, priv->window, true, None, GrabModeAsync, GrabModeAsync, priv->window, None, CurrentTime);
+ break;
+ default:
+ return false;
+ }
+#endif
+ return true;
+}
+
+} // namespace Graphics
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GRAPHICS_WINDOW_H_
+#define MSP_GRAPHICS_WINDOW_H_
+
+#include <string>
+#include <sigc++/signal.h>
+#include "eventsource.h"
+
+namespace Msp {
+namespace Graphics {
+
+class Display;
+
+struct WindowOptions
+{
+ unsigned width;
+ unsigned height;
+ bool fullscreen;
+ bool resizable;
+
+ WindowOptions();
+};
+
+class Window: public EventSource
+{
+public:
+ struct Private;
+ struct Event;
+
+ sigc::signal<void> signal_close;
+
+protected:
+ Display &display;
+ WindowOptions options;
+ bool visible;
+ bool kbd_autorepeat;
+ bool resizing;
+ Private *priv;
+
+public:
+ Window(Display &, unsigned w, unsigned h, bool fs = false);
+ Window(Display &, const WindowOptions &);
+private:
+ void init();
+public:
+ virtual ~Window();
+
+ void set_title(const std::string &);
+ void reconfigure(const WindowOptions &);
+ void set_keyboard_autorepeat(bool);
+ bool get_keyboard_autorepeat() const { return kbd_autorepeat; }
+ void show_cursor(bool);
+ void warp_pointer(int, int);
+
+ Display &get_display() const { return display; }
+ const WindowOptions &get_options() const { return options; }
+ virtual unsigned get_width() const { return options.width; }
+ virtual unsigned get_height() const { return options.height; }
+ const Private &get_private() const { return *priv; }
+
+ void show();
+ void hide();
+
+ bool event(const Event &evnt);
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_GRAPHICS_WINDOW_PRIV_H_
+#define MSP_GRAPHICS_WINDOW_PRIV_H_
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <X11/Xlib.h>
+#endif
+
+namespace Msp {
+namespace Graphics {
+
+#ifdef WIN32
+typedef HWND WindowHandle;
+#else
+typedef ::Window WindowHandle;
+#endif
+
+struct Window::Private
+{
+ WindowHandle window;
+#ifndef WIN32
+ Atom wm_delete_window;
+ Cursor invisible_cursor;
+#endif
+};
+
+struct Window::Event
+{
+#ifdef WIN32
+ UINT msg;
+ WPARAM wparam;
+ LPARAM lparam;
+#else
+ XEvent xevent;
+#endif
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
-#ifndef MSP_GBASE_BINARYCONTROL_H_
-#define MSP_GBASE_BINARYCONTROL_H_
+#ifndef MSP_INPUT_BINARYCONTROL_H_
+#define MSP_INPUT_BINARYCONTROL_H_
#include "control.h"
-#ifndef MSP_GBASE_CONTROL_H_
-#define MSP_GBASE_CONTROL_H_
+#ifndef MSP_INPUT_CONTROL_H_
+#define MSP_INPUT_CONTROL_H_
#include <string>
#include <sigc++/signal.h>
-#ifndef MSP_GBASE_INPUTDEVICE_H_
-#define MSP_GBASE_INPUTDEVICE_H_
+#ifndef MSP_INPUT_INPUTDEVICE_H_
+#define MSP_INPUT_INPUTDEVICE_H_
#include <string>
#include <vector>
-#ifndef MSP_GBASE_INPUTHUB_H_
-#define MSP_GBASE_INPUTHUB_H_
+#ifndef MSP_INPUT_INPUTHUB_H_
+#define MSP_INPUT_INPUTHUB_H_
#include "device.h"
#else
#include <X11/Xlib.h>
#endif
-#include <msp/gbase/display.h>
+#include <msp/graphics/display.h>
#include <msp/strings/format.h>
#include "keyboard.h"
#include "keys.h"
-#ifndef MSP_GBASE_KEYBOARD_H_
-#define MSP_GBASE_KEYBOARD_H_
+#ifndef MSP_INPUT_KEYBOARD_H_
+#define MSP_INPUT_KEYBOARD_H_
-#include <msp/gbase/window.h>
+#include <msp/graphics/window.h>
#include "device.h"
namespace Msp {
-#ifndef MSP_GBASE_MOUSE_H_
-#define MSP_GBASE_MOUSE_H_
+#ifndef MSP_INPUT_MOUSE_H_
+#define MSP_INPUT_MOUSE_H_
-#include <msp/gbase/window.h>
+#include <msp/graphics/window.h>
#include "device.h"
namespace Msp {
-#ifndef MSP_GBASE_SMOOTHCONTROL_H_
-#define MSP_GBASE_SMOOTHCONTROL_H_
+#ifndef MSP_INPUT_SMOOTHCONTROL_H_
+#define MSP_INPUT_SMOOTHCONTROL_H_
#include "control.h"