]> git.tdb.fi Git - libs/gui.git/commitdiff
Consistently label the graphics part as graphics
authorMikko Rasa <tdb@tdb.fi>
Fri, 26 Aug 2011 10:41:12 +0000 (13:41 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 26 Aug 2011 10:41:12 +0000 (13:41 +0300)
Fix multiple inclusion guards in the input headers

41 files changed:
Build
source/gbase/display.cpp [deleted file]
source/gbase/display.h [deleted file]
source/gbase/display_priv.h [deleted file]
source/gbase/drawcontext.cpp [deleted file]
source/gbase/drawcontext.h [deleted file]
source/gbase/eventsource.h [deleted file]
source/gbase/glcontext.cpp [deleted file]
source/gbase/glcontext.h [deleted file]
source/gbase/image.cpp [deleted file]
source/gbase/image.h [deleted file]
source/gbase/pixelformat.h [deleted file]
source/gbase/simplewindow.cpp [deleted file]
source/gbase/simplewindow.h [deleted file]
source/gbase/window.cpp [deleted file]
source/gbase/window.h [deleted file]
source/gbase/window_priv.h [deleted file]
source/graphics/display.cpp [new file with mode: 0644]
source/graphics/display.h [new file with mode: 0644]
source/graphics/display_priv.h [new file with mode: 0644]
source/graphics/drawcontext.cpp [new file with mode: 0644]
source/graphics/drawcontext.h [new file with mode: 0644]
source/graphics/eventsource.h [new file with mode: 0644]
source/graphics/glcontext.cpp [new file with mode: 0644]
source/graphics/glcontext.h [new file with mode: 0644]
source/graphics/image.cpp [new file with mode: 0644]
source/graphics/image.h [new file with mode: 0644]
source/graphics/pixelformat.h [new file with mode: 0644]
source/graphics/simplewindow.cpp [new file with mode: 0644]
source/graphics/simplewindow.h [new file with mode: 0644]
source/graphics/window.cpp [new file with mode: 0644]
source/graphics/window.h [new file with mode: 0644]
source/graphics/window_priv.h [new file with mode: 0644]
source/input/binarycontrol.h
source/input/control.h
source/input/device.h
source/input/hub.h
source/input/keyboard.cpp
source/input/keyboard.h
source/input/mouse.h
source/input/smoothcontrol.h

diff --git a/Build b/Build
index 79b8cbca0287cf3e640d21a5646c77af84a95fde..6a78535f7154a0f8ae8bf7532f8d62f384a5ca6a 100644 (file)
--- a/Build
+++ b/Build
@@ -50,9 +50,9 @@ package "mspgbase"
                };
        };
 
-       headers "msp/gbase"
+       headers "msp/graphics"
        {
-               source "source/gbase";
+               source "source/graphics";
                install true;
        };
 
@@ -64,7 +64,7 @@ package "mspgbase"
 
        library "mspgbase"
        {
-               source "source/gbase";
+               source "source/graphics";
                source "source/input";
                install true;
        };
diff --git a/source/gbase/display.cpp b/source/gbase/display.cpp
deleted file mode 100644 (file)
index da036a1..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-#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
diff --git a/source/gbase/display.h b/source/gbase/display.h
deleted file mode 100644 (file)
index 662e73f..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#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
diff --git a/source/gbase/display_priv.h b/source/gbase/display_priv.h
deleted file mode 100644 (file)
index f522812..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#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
diff --git a/source/gbase/drawcontext.cpp b/source/gbase/drawcontext.cpp
deleted file mode 100644 (file)
index 0396567..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-#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
diff --git a/source/gbase/drawcontext.h b/source/gbase/drawcontext.h
deleted file mode 100644 (file)
index 2717479..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#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
diff --git a/source/gbase/eventsource.h b/source/gbase/eventsource.h
deleted file mode 100644 (file)
index 5f09426..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#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
diff --git a/source/gbase/glcontext.cpp b/source/gbase/glcontext.cpp
deleted file mode 100644 (file)
index b713830..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-#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
diff --git a/source/gbase/glcontext.h b/source/gbase/glcontext.h
deleted file mode 100644 (file)
index dfac328..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#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
diff --git a/source/gbase/image.cpp b/source/gbase/image.cpp
deleted file mode 100644 (file)
index 3360b72..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-#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
diff --git a/source/gbase/image.h b/source/gbase/image.h
deleted file mode 100644 (file)
index aec1b0d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#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
diff --git a/source/gbase/pixelformat.h b/source/gbase/pixelformat.h
deleted file mode 100644 (file)
index 64b79ee..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#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
diff --git a/source/gbase/simplewindow.cpp b/source/gbase/simplewindow.cpp
deleted file mode 100644 (file)
index c782bab..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#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
diff --git a/source/gbase/simplewindow.h b/source/gbase/simplewindow.h
deleted file mode 100644 (file)
index 807e69f..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#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
diff --git a/source/gbase/window.cpp b/source/gbase/window.cpp
deleted file mode 100644 (file)
index 77959de..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-#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
diff --git a/source/gbase/window.h b/source/gbase/window.h
deleted file mode 100644 (file)
index a390b8c..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#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
diff --git a/source/gbase/window_priv.h b/source/gbase/window_priv.h
deleted file mode 100644 (file)
index 24d71a3..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#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
diff --git a/source/graphics/display.cpp b/source/graphics/display.cpp
new file mode 100644 (file)
index 0000000..da036a1
--- /dev/null
@@ -0,0 +1,243 @@
+#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
diff --git a/source/graphics/display.h b/source/graphics/display.h
new file mode 100644 (file)
index 0000000..b47a550
--- /dev/null
@@ -0,0 +1,63 @@
+#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
diff --git a/source/graphics/display_priv.h b/source/graphics/display_priv.h
new file mode 100644 (file)
index 0000000..5e82f9d
--- /dev/null
@@ -0,0 +1,20 @@
+#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
diff --git a/source/graphics/drawcontext.cpp b/source/graphics/drawcontext.cpp
new file mode 100644 (file)
index 0000000..0396567
--- /dev/null
@@ -0,0 +1,121 @@
+#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
diff --git a/source/graphics/drawcontext.h b/source/graphics/drawcontext.h
new file mode 100644 (file)
index 0000000..957e153
--- /dev/null
@@ -0,0 +1,32 @@
+#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
diff --git a/source/graphics/eventsource.h b/source/graphics/eventsource.h
new file mode 100644 (file)
index 0000000..3da2e94
--- /dev/null
@@ -0,0 +1,29 @@
+#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
diff --git a/source/graphics/glcontext.cpp b/source/graphics/glcontext.cpp
new file mode 100644 (file)
index 0000000..b713830
--- /dev/null
@@ -0,0 +1,187 @@
+#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
diff --git a/source/graphics/glcontext.h b/source/graphics/glcontext.h
new file mode 100644 (file)
index 0000000..db9df4e
--- /dev/null
@@ -0,0 +1,52 @@
+#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
diff --git a/source/graphics/image.cpp b/source/graphics/image.cpp
new file mode 100644 (file)
index 0000000..3360b72
--- /dev/null
@@ -0,0 +1,274 @@
+#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
diff --git a/source/graphics/image.h b/source/graphics/image.h
new file mode 100644 (file)
index 0000000..db65010
--- /dev/null
@@ -0,0 +1,48 @@
+#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
diff --git a/source/graphics/pixelformat.h b/source/graphics/pixelformat.h
new file mode 100644 (file)
index 0000000..891ba7c
--- /dev/null
@@ -0,0 +1,21 @@
+#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
diff --git a/source/graphics/simplewindow.cpp b/source/graphics/simplewindow.cpp
new file mode 100644 (file)
index 0000000..c782bab
--- /dev/null
@@ -0,0 +1,27 @@
+#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
diff --git a/source/graphics/simplewindow.h b/source/graphics/simplewindow.h
new file mode 100644 (file)
index 0000000..f7bb0ce
--- /dev/null
@@ -0,0 +1,52 @@
+#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
diff --git a/source/graphics/window.cpp b/source/graphics/window.cpp
new file mode 100644 (file)
index 0000000..77959de
--- /dev/null
@@ -0,0 +1,481 @@
+#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
diff --git a/source/graphics/window.h b/source/graphics/window.h
new file mode 100644 (file)
index 0000000..38b9217
--- /dev/null
@@ -0,0 +1,69 @@
+#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
diff --git a/source/graphics/window_priv.h b/source/graphics/window_priv.h
new file mode 100644 (file)
index 0000000..f5e9be8
--- /dev/null
@@ -0,0 +1,42 @@
+#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
index 851c6127f08006a11731e90ff037bd8b00c79344..8a156f78981fc5d2c60970305237f682af1e979c 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef MSP_GBASE_BINARYCONTROL_H_
-#define MSP_GBASE_BINARYCONTROL_H_
+#ifndef MSP_INPUT_BINARYCONTROL_H_
+#define MSP_INPUT_BINARYCONTROL_H_
 
 #include "control.h"
 
index a2f002c08557d57807bbaaaafb4171e9400c7923..924bbeca39024f3c0ed615c17d986cffa7ce7eb5 100644 (file)
@@ -1,5 +1,5 @@
-#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>
index 43d180d50b6595696f1767f490c48d3c0863a178..49d858ba2a3eed92dbfb1fb6f9c83dabe474e06a 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef MSP_GBASE_INPUTDEVICE_H_
-#define MSP_GBASE_INPUTDEVICE_H_
+#ifndef MSP_INPUT_INPUTDEVICE_H_
+#define MSP_INPUT_INPUTDEVICE_H_
 
 #include <string>
 #include <vector>
index 9fe57dd95a3bef2a501c23156b9812716fe0074d..8ec2fad7fcb3dd60af82a5f6dbab52c28a7571c3 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef MSP_GBASE_INPUTHUB_H_
-#define MSP_GBASE_INPUTHUB_H_
+#ifndef MSP_INPUT_INPUTHUB_H_
+#define MSP_INPUT_INPUTHUB_H_
 
 #include "device.h"
 
index 344048e802b43638df33ba97a4bd0f9059e7e869..02ff12eb2c0c2e7d02f739e776ddc6433bc9c815 100644 (file)
@@ -3,7 +3,7 @@
 #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"
index eaca0175c6284bba7584b992c5a2940558ec55b3..3e5b6b84131f8339364c69cd5199d3d5200cec01 100644 (file)
@@ -1,7 +1,7 @@
-#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 {
index eb5e9d61a4a1da49fda275a4b0b3e21bcdeb1ae7..5f7e71478913902c598bdeb551ea59d159c3a00a 100644 (file)
@@ -1,7 +1,7 @@
-#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 {
index fb6f84e41e2ff64ceee262656d6ac9cc96c27a60..78edbb3acd64a73b26a4ee9391c9b855b3ae5003 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef MSP_GBASE_SMOOTHCONTROL_H_
-#define MSP_GBASE_SMOOTHCONTROL_H_
+#ifndef MSP_INPUT_SMOOTHCONTROL_H_
+#define MSP_INPUT_SMOOTHCONTROL_H_
 
 #include "control.h"