]> git.tdb.fi Git - libs/gui.git/commitdiff
Split platform-specific parts into separate directories
authorMikko Rasa <tdb@tdb.fi>
Fri, 24 May 2013 18:08:06 +0000 (21:08 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 24 May 2013 18:08:06 +0000 (21:08 +0300)
35 files changed:
Build
source/graphics/display.cpp
source/graphics/display.h
source/graphics/display_priv.h [deleted file]
source/graphics/display_private.h [new file with mode: 0644]
source/graphics/drawcontext.cpp [deleted file]
source/graphics/glcontext.cpp
source/graphics/glcontext.h
source/graphics/glx/glcontext.cpp [new file with mode: 0644]
source/graphics/wgl/glcontext.cpp [new file with mode: 0644]
source/graphics/window.cpp
source/graphics/window.h
source/graphics/window_priv.h [deleted file]
source/graphics/window_private.h [new file with mode: 0644]
source/graphics/windows/display.cpp [new file with mode: 0644]
source/graphics/windows/display_platform.h [new file with mode: 0644]
source/graphics/windows/drawcontext.cpp [new file with mode: 0644]
source/graphics/windows/window.cpp [new file with mode: 0644]
source/graphics/windows/window_platform.h [new file with mode: 0644]
source/graphics/x11/display.cpp [new file with mode: 0644]
source/graphics/x11/display_platform.h [new file with mode: 0644]
source/graphics/x11/drawcontext.cpp [new file with mode: 0644]
source/graphics/x11/window.cpp [new file with mode: 0644]
source/graphics/x11/window_platform.h [new file with mode: 0644]
source/input/keyboard.cpp
source/input/keys.cpp
source/input/keys.h
source/input/keys_private.h [new file with mode: 0644]
source/input/mouse.cpp
source/input/windows/keyboard.cpp [new file with mode: 0644]
source/input/windows/keys.cpp [new file with mode: 0644]
source/input/windows/mouse.cpp [new file with mode: 0644]
source/input/x11/keyboard.cpp [new file with mode: 0644]
source/input/x11/keys.cpp [new file with mode: 0644]
source/input/x11/mouse.cpp [new file with mode: 0644]

diff --git a/Build b/Build
index f311834e48cf4ad3fde968825350396008fb06c2..a0f437caa8cd37f3e534672896902defdde577a2 100644 (file)
--- a/Build
+++ b/Build
@@ -57,6 +57,22 @@ package "mspgui"
        {
                source "source/graphics";
                source "source/input";
+               if_arch "windows"
+               {
+                       overlay "windows";
+                       if_feature "opengl"
+                       {
+                               overlay "wgl";
+                       };
+               };
+               if_arch "!windows"
+               {
+                       overlay "x11";
+                       if_feature "opengl"
+                       {
+                               overlay "glx";
+                       };
+               };
                install true;
                install_map
                {
index 588d492b9f64299f7e9aafb61b1f763fa4093777..42b0e8bb773404c892b01896d8ca13a589fa6f73 100644 (file)
@@ -1,49 +1,10 @@
-#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 "display_private.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<string, 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 {
 
@@ -52,75 +13,6 @@ unsupported_video_mode::unsupported_video_mode(const VideoMode &mode):
 { }
 
 
-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;
@@ -131,112 +23,11 @@ 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);
-       }
+       while(process_events()) ;
 }
 
 } // namespace Graphics
index 83b18532148c6cc01cafa9547539e9ec80091fa0..d311ba73c75f36ded3fe02e0401518638e88d2e2 100644 (file)
@@ -2,7 +2,6 @@
 #define MSP_GRAPHICS_DISPLAY_H_
 
 #include <list>
-#include <map>
 #include <stdexcept>
 #include <string>
 
@@ -55,6 +54,9 @@ public:
        void restore_mode() { set_mode(orig_mode); }
 
        void tick();
+private:
+       bool process_events();
+public:
        void check_error();
 };
 
diff --git a/source/graphics/display_priv.h b/source/graphics/display_priv.h
deleted file mode 100644 (file)
index 5e82f9d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#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/display_private.h b/source/graphics/display_private.h
new file mode 100644 (file)
index 0000000..ec772b0
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef MSP_GRAPHICS_DISPLAY_PRIVATE_H_
+#define MSP_GRAPHICS_DISPLAY_PRIVATE_H_
+
+#include <map>
+#include "display.h"
+#include "display_platform.h"
+#include "window_private.h"
+
+namespace Msp {
+namespace Graphics {
+
+struct Display::Private
+{
+       DisplayHandle display;
+       std::map<WindowHandle, Window *> windows;
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
diff --git a/source/graphics/drawcontext.cpp b/source/graphics/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
index b71383063c05d6edb036959e8034349897bff228..ab0ea7ad59267eb55625c42c2a26a72852450601 100644 (file)
@@ -1,19 +1,9 @@
-#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 <stdexcept>
 #include <msp/strings/format.h>
-#include "display.h"
 #include "glcontext.h"
 #include "window.h"
-#include "display_priv.h"
+
+using namespace std;
 
 namespace Msp {
 namespace Graphics {
@@ -32,156 +22,31 @@ unsupported_gl_mode::unsupported_gl_mode(const GLOptions &opts):
 { }
 
 
-#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
+       platform_init(opts);
 
        window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized));
 }
 
-GLContext::~GLContext()
+#ifndef WITH_OPENGL
+void GLContext::platform_init(const GLOptions &)
 {
-#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
+       throw runtime_error("no OpenGL support");
 }
 
+GLContext::~GLContext()
+{ }
+
 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;
+void GLContext::window_resized(unsigned, unsigned)
+{ }
 #endif
-}
 
 } // namespace Graphics
 } // namespace Msp
index db9df4e0aee08e3f150c17c826f2a578e1a142d7..a2480909416e29d9e1aa96c49ae410ad66d8382b 100644 (file)
@@ -39,6 +39,9 @@ private:
 
 public:
        GLContext(Window &wnd, const GLOptions &opts = GLOptions());
+private:
+       void platform_init(const GLOptions &);
+public:
        ~GLContext();
 
        void swap_buffers();
diff --git a/source/graphics/glx/glcontext.cpp b/source/graphics/glx/glcontext.cpp
new file mode 100644 (file)
index 0000000..09a4ef8
--- /dev/null
@@ -0,0 +1,97 @@
+#include <vector>
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include "glcontext.h"
+#include "display_private.h"
+#include "window_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Graphics {
+
+typedef GLXContext ContextHandle;
+
+struct GLContext::Private
+{
+       ContextHandle context;
+       // We need to create a window with the chosen visual
+       WindowHandle subwnd;
+};
+
+
+void GLContext::platform_init(const GLOptions &opts)
+{
+       priv = new Private;
+
+       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);
+
+       DisplayHandle 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);
+}
+
+GLContext::~GLContext()
+{
+       DisplayHandle dpy = display.get_private().display;
+
+       glXMakeCurrent(dpy, 0, 0);
+       glXDestroyContext(dpy, priv->context);
+       XDestroyWindow(dpy, priv->subwnd);
+
+       delete priv;
+}
+
+void GLContext::swap_buffers()
+{
+       glXSwapBuffers(display.get_private().display, priv->subwnd);
+}
+
+void GLContext::window_resized(unsigned w, unsigned h)
+{
+       XMoveResizeWindow(display.get_private().display, priv->subwnd, 0, 0, w, h);
+       glViewport(0, 0, w, h);
+}
+
+} // namespace Graphics
+} // namespace Msp
diff --git a/source/graphics/wgl/glcontext.cpp b/source/graphics/wgl/glcontext.cpp
new file mode 100644 (file)
index 0000000..1a0ad7a
--- /dev/null
@@ -0,0 +1,70 @@
+#include <windows.h>
+#include <GL/gl.h>
+#include "glcontext.h"
+#include "window_private.h"
+
+namespace Msp {
+namespace Graphics {
+
+typedef HGLRC ContextHandle;
+
+struct GLContext::Private
+{
+       ContextHandle context;
+};
+
+
+void GLContext::platform_init()
+{
+       priv = new Private;
+
+       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);
+}
+
+GLContext::~GLContext()
+{
+       wglMakeCurrent(0, 0);
+       wglDeleteContext(priv->context);
+
+       delete priv;
+}
+
+void GLContext::swap_buffers()
+{
+       HDC dc = GetDC(window.get_private().window);
+       SwapBuffers(dc);
+       ReleaseDC(window.get_private().window, dc);
+}
+
+void GLContext::window_resized(unsigned w, unsigned h)
+{
+       glViewport(0, 0, w, h);
+}
+
+} // namespace Graphics
+} // namespace Msp
index a1353acf8fe4000f6b5a35cce9624cd6b2d43399..166e49f716fc8f63944015360b8806068ff325b6 100644 (file)
@@ -1,53 +1,9 @@
-#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 <msp/core/systemerror.h>
 #include "display.h"
 #include "window.h"
-#include "display_priv.h"
+#include "window_private.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 {
 
@@ -83,86 +39,7 @@ void Window::init()
        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 = "mspgui";
-               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,
-               "mspgui",
-               "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
+       platform_init();
 
        display.add_window(*this);
        display.check_error();
@@ -170,15 +47,7 @@ void Window::init()
 
 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
+       platform_cleanup();
 
        display.remove_window(*this);
 
@@ -188,94 +57,13 @@ Window::~Window()
        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
+       platform_reconfigure(fullscreen_changed);
 
        if(visible)
        {
@@ -291,155 +79,26 @@ 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
+       platform_show();
        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
+               warp_pointer(options.width/2, options.height/2);
        }
 }
 
 void Window::hide()
 {
-#ifdef WIN32
-       ShowWindow(priv->window, SW_HIDE);
-#else
-       XUnmapWindow(display.get_private().display, priv->window);
-#endif
+       platform_hide();
        visible = false;
 
        if(options.fullscreen)
                display.restore_mode();
 }
 
-bool Window::event(const Event &evnt)
-{
-#ifdef WIN32
-       switch(evnt.msg)
-       {
-       case WM_KEYDOWN:
-       case WM_KEYUP:
-       case WM_LBUTTONDOWN:
-       case WM_LBUTTONUP:
-       case WM_MBUTTONDOWN:
-       case WM_MBUTTONUP:
-       case WM_RBUTTONDOWN:
-       case WM_RBUTTONUP:
-       case WM_MOUSEWHEEL:
-       case WM_MOUSEMOVE:
-               signal_input_event.emit(evnt);
-               break;
-       case WM_SIZE:
-               options.width = LOWORD(evnt.lparam);
-               options.height = HIWORD(evnt.lparam);
-               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:
-       case ButtonRelease:
-       case MotionNotify:
-       case KeyPress:
-       case KeyRelease:
-               signal_input_event.emit(evnt);
-               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
index 942fc8c984074f72572828e5ed5efee6f43675ab..55751b3d5a15cf689972ac38e3dc0f890f2d4a64 100644 (file)
@@ -46,11 +46,16 @@ public:
        Window(Display &, const WindowOptions &);
 private:
        void init();
+       void platform_init();
+       void platform_cleanup();
 public:
        virtual ~Window();
 
        void set_title(const std::string &);
        void reconfigure(const WindowOptions &);
+private:
+       void platform_reconfigure(bool);
+public:
        void set_keyboard_autorepeat(bool);
        bool get_keyboard_autorepeat() const { return kbd_autorepeat; }
        void show_cursor(bool);
@@ -64,7 +69,11 @@ public:
 
        void show();
        void hide();
+private:
+       void platform_show();
+       void platform_hide();
 
+public:
        bool event(const Event &evnt);
 };
 
diff --git a/source/graphics/window_priv.h b/source/graphics/window_priv.h
deleted file mode 100644 (file)
index f5e9be8..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#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
diff --git a/source/graphics/window_private.h b/source/graphics/window_private.h
new file mode 100644 (file)
index 0000000..2257b1c
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef MSP_GRAPHICS_WINDOW_PRIVATE_H_
+#define MSP_GRAPHICS_WINDOW_PRIVATE_H_
+
+#include "window.h"
+#include "window_platform.h"
+
+namespace Msp {
+namespace Graphics {
+
+struct Window::Private: PlatformWindowPrivate
+{
+       WindowHandle window;
+};
+
+struct Window::Event: PlatformEvent
+{
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
diff --git a/source/graphics/windows/display.cpp b/source/graphics/windows/display.cpp
new file mode 100644 (file)
index 0000000..5cc04c1
--- /dev/null
@@ -0,0 +1,69 @@
+#include <windows.h>
+#include "display.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Graphics {
+
+Display::Display(const string &)
+{
+       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;
+       }
+}
+
+Display::~Display()
+{
+}
+
+void Display::set_mode(const VideoMode &mode)
+{
+       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);
+}
+
+bool Display::process_events()
+{
+       MSG msg;
+       if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+       {
+               DispatchMessage(&msg);
+               return true;
+       }
+       else
+               return false;
+}
+
+void Display::check_error()
+{
+}
+
+} // namespace Msp
+} // namespace Graphics
diff --git a/source/graphics/windows/display_platform.h b/source/graphics/windows/display_platform.h
new file mode 100644 (file)
index 0000000..dac4dd7
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef MSP_GRAPHICS_DISPLAY_PLATFORM_H_
+#define MSP_GRAPHICS_DISPLAY_PLATFORM_H_
+
+namespace Msp {
+namespace Graphics {
+
+typedef void *DisplayHandle;
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
diff --git a/source/graphics/windows/drawcontext.cpp b/source/graphics/windows/drawcontext.cpp
new file mode 100644 (file)
index 0000000..b887615
--- /dev/null
@@ -0,0 +1,34 @@
+#include <stdexcept>
+#include "drawcontext.h"
+#include "window.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Graphics {
+
+DrawContext::DrawContext(Window &w):
+       display(w.get_display()),
+       window(w)
+{
+       throw runtime_error("no DrawContext support on windows");
+}
+
+DrawContext::~DrawContext()
+{ }
+
+unsigned DrawContext::get_depth() const
+{
+       return 0;
+}
+
+unsigned char *DrawContext::get_data()
+{
+       return 0;
+}
+
+void DrawContext::update()
+{ }
+
+} // namespace Graphics
+} // namespace Msp
diff --git a/source/graphics/windows/window.cpp b/source/graphics/windows/window.cpp
new file mode 100644 (file)
index 0000000..c5cdc62
--- /dev/null
@@ -0,0 +1,174 @@
+#include <windowsx.h>
+#include <msp/core/application.h>
+#include <msp/core/systemerror.h>
+#include "window.h"
+#include "window_private.h"
+
+using namespace std;
+
+namespace {
+
+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);
+}
+
+}
+
+namespace Msp {
+namespace Graphics {
+
+void Window::platform_init()
+{
+       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 = "mspgui";
+               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,
+               "mspgui",
+               "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");
+}
+
+void Window::platform_cleanup()
+{
+       if(priv->window)
+               CloseWindow(priv->window);
+}
+
+void Window::set_title(const string &title)
+{
+       SetWindowText(priv->window, title.c_str());
+}
+
+void Window::platform_reconfigure(bool fullscreen_changed)
+{
+       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);
+}
+
+void Window::show_cursor(bool s)
+{
+       ShowCursor(s);
+}
+
+void Window::warp_pointer(int, int)
+{
+}
+
+void Window::platform_show()
+{
+       ShowWindow(priv->window, SW_SHOWNORMAL);
+}
+
+void Window::platform_hide()
+{
+       ShowWindow(priv->window, SW_HIDE);
+}
+
+bool Window::event(const Event &evnt)
+{
+       switch(evnt.msg)
+       {
+       case WM_KEYDOWN:
+       case WM_KEYUP:
+       case WM_LBUTTONDOWN:
+       case WM_LBUTTONUP:
+       case WM_MBUTTONDOWN:
+       case WM_MBUTTONUP:
+       case WM_RBUTTONDOWN:
+       case WM_RBUTTONUP:
+       case WM_MOUSEWHEEL:
+       case WM_MOUSEMOVE:
+               signal_input_event.emit(evnt);
+               break;
+       case WM_SIZE:
+               options.width = LOWORD(evnt.lparam);
+               options.height = HIWORD(evnt.lparam);
+               signal_resize.emit(options.width, options.height);
+               break;
+       case WM_CLOSE:
+               signal_close.emit();
+               break;
+       default:
+               return false;
+       }
+
+       return true;
+}
+
+} // namespace Graphics
+} // namespace Msp
diff --git a/source/graphics/windows/window_platform.h b/source/graphics/windows/window_platform.h
new file mode 100644 (file)
index 0000000..1ff5cf3
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef MSP_GRAPHICS_WINDOW_PLATFORM_H_
+#define MSP_GRAPHICS_WINDOW_PLATFORM_H_
+
+#include <windows.h>
+
+namespace Msp {
+namespace Graphics {
+
+typedef HWND WindowHandle;
+
+struct PlatformWindowPrivate
+{
+};
+
+struct PlatformEvent
+{
+       UINT msg;
+       WPARAM wparam;
+       LPARAM lparam;
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
diff --git a/source/graphics/x11/display.cpp b/source/graphics/x11/display.cpp
new file mode 100644 (file)
index 0000000..0e89794
--- /dev/null
@@ -0,0 +1,174 @@
+#include <iostream>
+#include <X11/Xlib.h>
+#ifdef WITH_XF86VIDMODE
+#include <X11/extensions/xf86vmode.h>
+#endif
+#include <msp/strings/format.h>
+#include <msp/strings/lexicalcast.h>
+#include "display.h"
+#include "display_private.h"
+
+using namespace std;
+
+namespace {
+
+bool error_flag = false;
+std::string error_msg;
+
+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<string, 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;
+}
+
+}
+
+
+namespace Msp {
+namespace Graphics {
+
+Display::Display(const string &disp_name):
+       priv(new Private)
+{
+       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
+}
+
+Display::~Display()
+{
+       XCloseDisplay(priv->display);
+       delete priv;
+}
+
+void Display::set_mode(const VideoMode &mode)
+{
+#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];
+
+               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
+}
+
+bool Display::process_events()
+{
+       int pending = XPending(priv->display);
+       if(pending==0)
+               return false;
+
+       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);
+               }
+       }
+
+       return true;
+}
+
+void Display::check_error()
+{
+       if(error_flag)
+       {
+               error_flag = false;
+               throw runtime_error(error_msg);
+       }
+}
+
+} // namespace Msp
+} // namespace Graphics
diff --git a/source/graphics/x11/display_platform.h b/source/graphics/x11/display_platform.h
new file mode 100644 (file)
index 0000000..1ebe616
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef MSP_GRAPHICS_DISPLAY_PLATFORM_H_
+#define MSP_GRAPHICS_DISPLAY_PLATFORM_H_
+
+#include <X11/Xlib.h>
+
+namespace Msp {
+namespace Graphics {
+
+typedef ::Display *DisplayHandle;
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
diff --git a/source/graphics/x11/drawcontext.cpp b/source/graphics/x11/drawcontext.cpp
new file mode 100644 (file)
index 0000000..e40390f
--- /dev/null
@@ -0,0 +1,99 @@
+#include <stdexcept>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+#include <X11/Xutil.h>
+#include "display_private.h"
+#include "drawcontext.h"
+#include "window_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Graphics {
+
+struct DrawContext::Private
+{
+       XImage *image;
+       bool use_shm;
+       XShmSegmentInfo shminfo;
+};
+
+DrawContext::DrawContext(Window &w):
+       display(w.get_display()),
+       window(w),
+       priv(new Private)
+{
+       DisplayHandle 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];
+       }
+}
+
+DrawContext::~DrawContext()
+{
+       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);
+
+       delete priv;
+}
+
+unsigned DrawContext::get_depth() const
+{
+       return priv->image->bits_per_pixel;
+}
+
+unsigned char *DrawContext::get_data()
+{
+       return reinterpret_cast<unsigned char *>(priv->image->data);
+}
+
+void DrawContext::update()
+{
+       DisplayHandle 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);
+}
+
+} // namespace Graphics
+} // namespace Msp
diff --git a/source/graphics/x11/window.cpp b/source/graphics/x11/window.cpp
new file mode 100644 (file)
index 0000000..577f1d4
--- /dev/null
@@ -0,0 +1,216 @@
+#include <vector>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#ifdef WITH_XF86VIDMODE
+#include <X11/extensions/xf86vmode.h>
+#endif
+#include <msp/core/systemerror.h>
+#include "display_private.h"
+#include "window.h"
+#include "window_private.h"
+
+using namespace std;
+
+namespace {
+
+Bool match_event_type(Display *, XEvent *event, XPointer arg)
+{
+       return event->type==*reinterpret_cast<int *>(arg);
+}
+
+}
+
+namespace Msp {
+namespace Graphics {
+
+void Window::platform_init()
+{
+       DisplayHandle 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);
+       }
+}
+
+void Window::platform_cleanup()
+{
+       if(priv->window)
+               XDestroyWindow(display.get_private().display, priv->window);
+
+       if(priv->invisible_cursor)
+               XFreeCursor(display.get_private().display, priv->invisible_cursor);
+}
+
+void Window::set_title(const string &title)
+{
+       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();
+}
+
+void Window::platform_reconfigure(bool fullscreen_changed)
+{
+       DisplayHandle 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 && was_visible)
+               show();
+}
+
+void Window::show_cursor(bool s)
+{
+       DisplayHandle 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);
+       }
+}
+
+void Window::warp_pointer(int x, int y)
+{
+       XWarpPointer(display.get_private().display, None, priv->window, 0, 0, 0, 0, x, y);
+}
+
+void Window::platform_show()
+{
+       XMapRaised(display.get_private().display, priv->window);
+}
+
+void Window::platform_hide()
+{
+       XUnmapWindow(display.get_private().display, priv->window);
+}
+
+bool Window::event(const Event &evnt)
+{
+       const XEvent &ev = evnt.xevent;
+       switch(ev.type)
+       {
+       case ButtonPress:
+       case ButtonRelease:
+       case MotionNotify:
+       case KeyPress:
+       case KeyRelease:
+               signal_input_event.emit(evnt);
+               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)
+               {
+                       DisplayHandle 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;
+       }
+
+       return true;
+}
+
+} // namespace Graphics
+} // namespace Msp
diff --git a/source/graphics/x11/window_platform.h b/source/graphics/x11/window_platform.h
new file mode 100644 (file)
index 0000000..3c81a6e
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef MSP_GRAPHICS_WINDOW_PLATFORM_H_
+#define MSP_GRAPHICS_WINDOW_PLATFORM_H_
+
+#include <X11/Xlib.h>
+
+namespace Msp {
+namespace Graphics {
+
+typedef ::Window WindowHandle;
+
+struct PlatformWindowPrivate
+{
+       Atom wm_delete_window;
+       Cursor invisible_cursor;
+};
+
+struct PlatformEvent
+{
+       XEvent xevent;
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
index ab2f9eae3b1e18a13edfb110251cbfa1155866ca..159e5ee41b9e304adfb777e649251aa2c274887c 100644 (file)
@@ -1,18 +1,7 @@
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#endif
-#include <msp/graphics/display.h>
 #include <msp/graphics/window.h>
-#include <msp/graphics/display_priv.h>
-#include <msp/graphics/window_priv.h>
 #include "keyboard.h"
 #include "keys.h"
 
-#define MAPVK_VK_TO_VSC 0
-
 namespace Msp {
 namespace Input {
 
@@ -26,59 +15,5 @@ Keyboard::Keyboard(Graphics::Window &w):
        window.signal_input_event.connect(sigc::mem_fun(this, &Keyboard::input_event));
 }
 
-std::string Keyboard::get_button_name(unsigned btn) const
-{
-       if(btn==0)
-               return "None";
-#ifndef WIN32
-       const char *str = XKeysymToString(key_to_sys(btn));
-       if(!str)
-               return Device::get_button_name(btn);
-       return str;
-#else
-       char buf[128];
-       unsigned scan = MapVirtualKey(key_to_sys(btn), MAPVK_VK_TO_VSC);
-       if(!GetKeyNameText(scan<<16, buf, sizeof(buf)))
-               return Device::get_button_name(btn);
-       return buf;
-#endif
-}
-
-void Keyboard::input_event(const Graphics::Window::Event &event)
-{
-#ifdef WIN32
-       switch(event.msg)
-       {
-       case WM_KEYDOWN:
-       case WM_KEYUP:
-               set_button_state(key_from_sys(event.wparam), event.msg==WM_KEYDOWN, true);
-               break;
-       case WM_CHAR:
-               signal_character.emit(event.wparam);
-               break;
-       }
-#else
-       switch(event.xevent.type)
-       {
-       case KeyPress:
-       case KeyRelease:
-               {
-                       KeySym keysym = XLookupKeysym(const_cast<XKeyEvent *>(&event.xevent.xkey), 0);
-                       if(keysym!=NoSymbol)
-                               if(unsigned key = key_from_sys(keysym))
-                                       set_button_state(key, event.xevent.type==KeyPress, true);
-                       if(event.xevent.type==KeyPress)
-                       {
-                               char ch;
-                               if(XLookupString(const_cast<XKeyEvent *>(&event.xevent.xkey), &ch, 1, 0, 0))
-                                       // XLookupString always returns Latin-1
-                                       signal_character.emit(static_cast<unsigned char>(ch));
-                       }
-               }
-               break;
-       }
-#endif
-}
-
 } // namespace Input
 } // namespace Msp
index 38d94807b03fcc0d982f641a433f8aa98e4ae513..abefeaa7a3e15decb4bce239ef3f3abbed3e6880 100644 (file)
 #include <map>
 #include <stdexcept>
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <X11/X.h>
-#include <X11/keysym.h>
-#endif
 #include "keys.h"
 
 using namespace std;
 
-namespace {
-
-unsigned keymap[Msp::Input::N_KEYS_]=
-{
-#ifndef WIN32
-       0, 0, 0, 0, 0, 0, 0, 0,
-       XK_BackSpace, XK_Tab, XK_Return, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, XK_Escape, 0, 0, 0, 0,
-
-       XK_space, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, XK_plus, XK_comma, XK_minus, XK_period, XK_slash,
-       XK_0, XK_1, XK_2, XK_3, XK_4, XK_5, XK_6, XK_7,
-       XK_8, XK_9, 0, XK_semicolon, XK_less, XK_equal, 0, 0,
-
-       0, XK_a, XK_b, XK_c, XK_d, XK_e, XK_f, XK_g,
-       XK_h, XK_i, XK_j, XK_k, XK_l, XK_m, XK_n, XK_o,
-       XK_p, XK_q, XK_r, XK_s, XK_t, XK_u, XK_v, XK_w,
-       XK_x, XK_y, XK_z, XK_bracketleft, XK_backslash, XK_bracketright, 0, 0,
-
-       XK_grave, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-
-       XK_adiaeresis, XK_odiaeresis, XK_udiaeresis, XK_aring, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-
-       XK_Left, XK_Right, XK_Up, XK_Down, 0, 0, 0, 0,
-       XK_Home, XK_End, XK_Page_Up, XK_Page_Down, XK_Insert, XK_Delete, 0, 0,
-       XK_F1, XK_F2, XK_F3, XK_F4, XK_F5, XK_F6, XK_F7, XK_F8,
-       XK_F9, XK_F10, XK_F11, XK_F12, 0, 0, 0, 0,
-
-       XK_Shift_L, XK_Shift_R, XK_Control_L, XK_Control_R, XK_Alt_L, XK_Alt_R, XK_Super_L, XK_Super_R,
-       XK_Caps_Lock, XK_Scroll_Lock, XK_Num_Lock, 0, 0, 0, 0, 0,
-       XK_KP_0, XK_KP_1, XK_KP_2, XK_KP_3, XK_KP_4, XK_KP_5, XK_KP_6, XK_KP_7,
-       XK_KP_8, XK_KP_9, XK_KP_Add, XK_KP_Subtract, XK_KP_Multiply, XK_KP_Divide, XK_KP_Separator, 0,
-
-       XK_Pause, XK_Print, XK_Menu, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-#else
-       0, 0, 0, 0, 0, 0, 0, 0,
-       VK_BACK, VK_TAB, VK_RETURN, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, VK_ESCAPE, 0, 0, 0, 0,
-
-       VK_SPACE, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       '0', '1', '2', '3', '4', '5', '6', '7',
-       '8', '9', 0, 0, 0, 0, 0, 0,
-
-       0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
-       'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
-       'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
-       'X', 'Y', 'Z', 0, 0, 0, 0, 0,
-
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-
-       VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, 0, 0, 0, 0,
-       VK_HOME, VK_END, VK_PRIOR, VK_NEXT, VK_INSERT, VK_DELETE, 0, 0,
-       0, VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7,
-       VK_F8, VK_F9, VK_F10, VK_F11, VK_F12, 0, 0, 0,
-
-       VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, 0, 0, VK_LWIN, VK_RWIN,
-       VK_CAPITAL, VK_SCROLL, VK_NUMLOCK, 0, 0, 0, 0, 0,
-       VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
-       VK_NUMPAD8, VK_NUMPAD9, VK_ADD, VK_SUBTRACT, VK_MULTIPLY, VK_DIVIDE, VK_SEPARATOR, 0,
-
-       VK_PAUSE, VK_SNAPSHOT, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-#endif
-};
-
-}
-
 namespace Msp {
 namespace Input {
 
+extern unsigned sys_keymap[];
+
 unsigned key_from_sys(unsigned code)
 {
        static bool init_done = false;
@@ -110,8 +17,8 @@ unsigned key_from_sys(unsigned code)
        if(!init_done)
        {
                for(unsigned i=0; i<N_KEYS_; ++i)
-                       if(keymap[i])
-                               reverse_map[keymap[i]] = i;
+                       if(sys_keymap[i])
+                               reverse_map[sys_keymap[i]] = i;
 
                init_done = true;
        }
@@ -127,7 +34,7 @@ unsigned key_to_sys(unsigned key)
 {
        if(key>=N_KEYS_)
                throw invalid_argument("key_to_sys");
-       return keymap[key];
+       return sys_keymap[key];
 }
 
 } // namespace Input
index 3915aa2fce8dd1ec4706ff78ae3c5554de4c9045..c5822f89e14870170d09c3520be2e3720457e41e 100644 (file)
@@ -139,9 +139,6 @@ enum
        N_KEYS_ = 0x100
 };
 
-extern unsigned key_from_sys(unsigned);
-extern unsigned key_to_sys(unsigned);
-
 } // namespace Input
 } // namespace Msp
 
diff --git a/source/input/keys_private.h b/source/input/keys_private.h
new file mode 100644 (file)
index 0000000..715b970
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef MSP_INPUT_KEYS_PRIVATE_H_
+#define MSP_INPUT_KEYS_PRIVATE_H_
+
+namespace Msp {
+namespace Input {
+
+unsigned key_from_sys(unsigned);
+unsigned key_to_sys(unsigned);
+
+} // namespace Input
+} // namespace Msp
+
+#endif
index 2337f70f5aa86139be1b803c3bc6e9385d581adc..1b41e3654517c2adb12d02e5cb10821df70a5764 100644 (file)
@@ -1,8 +1,4 @@
-#ifdef WIN32
-#include <windowsx.h>
-#endif
 #include <msp/graphics/window.h>
-#include <msp/graphics/window_priv.h>
 #include "mouse.h"
 
 namespace Msp {
@@ -51,49 +47,5 @@ std::string Mouse::get_axis_name(unsigned axis) const
        };
 }
 
-void Mouse::input_event(const Graphics::Window::Event &event)
-{
-#ifdef WIN32
-       switch(event.msg)
-       {
-       case WM_LBUTTONDOWN:
-       case WM_LBUTTONUP:
-               set_button_state(1, event.msg==WM_LBUTTONDOWN, true);
-               break;
-       case WM_MBUTTONDOWN:
-       case WM_MBUTTONUP:
-               set_button_state(2, event.msg==WM_MBUTTONDOWN, true);
-               break;
-       case WM_RBUTTONDOWN:
-       case WM_RBUTTONUP:
-               set_button_state(3, event.msg==WM_RBUTTONDOWN, true);
-               break;
-       case WM_MOUSEWHEEL:
-               {
-                       unsigned btn = (HIWORD(event.wparam)&0x8000) ? 5 : 4;
-                       set_button_state(btn, true, true);
-                       set_button_state(btn, false, true);
-               }
-               break;
-       case WM_MOUSEMOVE:
-               set_axis_value(0, GET_X_LPARAM(event.lparam)*2.0/window.get_width()-1.0, true);
-               set_axis_value(1, 1.0-GET_Y_LPARAM(event.lparam)*2.0/window.get_height(), true);
-               break;
-       }
-#else
-       switch(event.xevent.type)
-       {
-       case ButtonPress:
-       case ButtonRelease:
-               set_button_state(event.xevent.xbutton.button, event.xevent.type==ButtonPress, true);
-               break;
-       case MotionNotify:
-               set_axis_value(0, event.xevent.xmotion.x*2.0/window.get_width()-1.0, true);
-               set_axis_value(1, 1.0-event.xevent.xmotion.y*2.0/window.get_height(), true);
-               break;
-       }
-#endif
-}
-
 } // namespace Input
 } // namespace Msp
diff --git a/source/input/windows/keyboard.cpp b/source/input/windows/keyboard.cpp
new file mode 100644 (file)
index 0000000..24b019e
--- /dev/null
@@ -0,0 +1,38 @@
+#include <windows.h>
+#include <msp/graphics/window_private.h>
+#include "keyboard.h"
+#include "keys_private.h"
+
+#define MAPVK_VK_TO_VSC 0
+
+namespace Msp {
+namespace Input {
+
+std::string Keyboard::get_button_name(unsigned btn) const
+{
+       if(btn==0)
+               return "None";
+
+       char buf[128];
+       unsigned scan = MapVirtualKey(key_to_sys(btn), MAPVK_VK_TO_VSC);
+       if(!GetKeyNameText(scan<<16, buf, sizeof(buf)))
+               return Device::get_button_name(btn);
+       return buf;
+}
+
+void Keyboard::input_event(const Graphics::Window::Event &event)
+{
+       switch(event.msg)
+       {
+       case WM_KEYDOWN:
+       case WM_KEYUP:
+               set_button_state(key_from_sys(event.wparam), event.msg==WM_KEYDOWN, true);
+               break;
+       case WM_CHAR:
+               signal_character.emit(event.wparam);
+               break;
+       }
+}
+
+} // namespace Input
+} // namespace Msp
diff --git a/source/input/windows/keys.cpp b/source/input/windows/keys.cpp
new file mode 100644 (file)
index 0000000..6501196
--- /dev/null
@@ -0,0 +1,51 @@
+#include <windows.h>
+#include "keys.h"
+
+namespace Msp {
+namespace Input {
+
+unsigned sys_keymap[N_KEYS_]=
+{
+       0, 0, 0, 0, 0, 0, 0, 0,
+       VK_BACK, VK_TAB, VK_RETURN, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, VK_ESCAPE, 0, 0, 0, 0,
+
+       VK_SPACE, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       '0', '1', '2', '3', '4', '5', '6', '7',
+       '8', '9', 0, 0, 0, 0, 0, 0,
+
+       0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+       'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+       'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+       'X', 'Y', 'Z', 0, 0, 0, 0, 0,
+
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+
+       VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, 0, 0, 0, 0,
+       VK_HOME, VK_END, VK_PRIOR, VK_NEXT, VK_INSERT, VK_DELETE, 0, 0,
+       0, VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7,
+       VK_F8, VK_F9, VK_F10, VK_F11, VK_F12, 0, 0, 0,
+
+       VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, 0, 0, VK_LWIN, VK_RWIN,
+       VK_CAPITAL, VK_SCROLL, VK_NUMLOCK, 0, 0, 0, 0, 0,
+       VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
+       VK_NUMPAD8, VK_NUMPAD9, VK_ADD, VK_SUBTRACT, VK_MULTIPLY, VK_DIVIDE, VK_SEPARATOR, 0,
+
+       VK_PAUSE, VK_SNAPSHOT, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+} // namespace Input
+} // namespace Msp
diff --git a/source/input/windows/mouse.cpp b/source/input/windows/mouse.cpp
new file mode 100644 (file)
index 0000000..77f8488
--- /dev/null
@@ -0,0 +1,39 @@
+#include <windowsx.h>
+#include <msp/graphics/window_private.h>
+#include "mouse.h"
+
+namespace Msp {
+namespace Input {
+
+void Mouse::input_event(const Graphics::Window::Event &event)
+{
+       switch(event.msg)
+       {
+       case WM_LBUTTONDOWN:
+       case WM_LBUTTONUP:
+               set_button_state(1, event.msg==WM_LBUTTONDOWN, true);
+               break;
+       case WM_MBUTTONDOWN:
+       case WM_MBUTTONUP:
+               set_button_state(2, event.msg==WM_MBUTTONDOWN, true);
+               break;
+       case WM_RBUTTONDOWN:
+       case WM_RBUTTONUP:
+               set_button_state(3, event.msg==WM_RBUTTONDOWN, true);
+               break;
+       case WM_MOUSEWHEEL:
+               {
+                       unsigned btn = (HIWORD(event.wparam)&0x8000) ? 5 : 4;
+                       set_button_state(btn, true, true);
+                       set_button_state(btn, false, true);
+               }
+               break;
+       case WM_MOUSEMOVE:
+               set_axis_value(0, GET_X_LPARAM(event.lparam)*2.0/window.get_width()-1.0, true);
+               set_axis_value(1, 1.0-GET_Y_LPARAM(event.lparam)*2.0/window.get_height(), true);
+               break;
+       }
+}
+
+} // namespace Input
+} // namepsace Msp
diff --git a/source/input/x11/keyboard.cpp b/source/input/x11/keyboard.cpp
new file mode 100644 (file)
index 0000000..50142c9
--- /dev/null
@@ -0,0 +1,45 @@
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <msp/graphics/window_private.h>
+#include "keyboard.h"
+#include "keys_private.h"
+
+namespace Msp {
+namespace Input {
+
+std::string Keyboard::get_button_name(unsigned btn) const
+{
+       if(btn==0)
+               return "None";
+
+       const char *str = XKeysymToString(key_to_sys(btn));
+       if(!str)
+               return Device::get_button_name(btn);
+       return str;
+}
+
+void Keyboard::input_event(const Graphics::Window::Event &event)
+{
+       switch(event.xevent.type)
+       {
+       case KeyPress:
+       case KeyRelease:
+               {
+                       KeySym keysym = XLookupKeysym(const_cast<XKeyEvent *>(&event.xevent.xkey), 0);
+                       if(keysym!=NoSymbol)
+                               if(unsigned key = key_from_sys(keysym))
+                                       set_button_state(key, event.xevent.type==KeyPress, true);
+                       if(event.xevent.type==KeyPress)
+                       {
+                               char ch;
+                               if(XLookupString(const_cast<XKeyEvent *>(&event.xevent.xkey), &ch, 1, 0, 0))
+                                       // XLookupString always returns Latin-1
+                                       signal_character.emit(static_cast<unsigned char>(ch));
+                       }
+               }
+               break;
+       }
+}
+
+} // namespace Input
+} // namespace Msp
diff --git a/source/input/x11/keys.cpp b/source/input/x11/keys.cpp
new file mode 100644 (file)
index 0000000..a1bb874
--- /dev/null
@@ -0,0 +1,51 @@
+#include <X11/keysym.h>
+#include "keys.h"
+
+namespace Msp {
+namespace Input {
+
+unsigned sys_keymap[N_KEYS_]=
+{
+       0, 0, 0, 0, 0, 0, 0, 0,
+       XK_BackSpace, XK_Tab, XK_Return, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, XK_Escape, 0, 0, 0, 0,
+
+       XK_space, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, XK_plus, XK_comma, XK_minus, XK_period, XK_slash,
+       XK_0, XK_1, XK_2, XK_3, XK_4, XK_5, XK_6, XK_7,
+       XK_8, XK_9, 0, XK_semicolon, XK_less, XK_equal, 0, 0,
+
+       0, XK_a, XK_b, XK_c, XK_d, XK_e, XK_f, XK_g,
+       XK_h, XK_i, XK_j, XK_k, XK_l, XK_m, XK_n, XK_o,
+       XK_p, XK_q, XK_r, XK_s, XK_t, XK_u, XK_v, XK_w,
+       XK_x, XK_y, XK_z, XK_bracketleft, XK_backslash, XK_bracketright, 0, 0,
+
+       XK_grave, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+
+       XK_adiaeresis, XK_odiaeresis, XK_udiaeresis, XK_aring, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+
+       XK_Left, XK_Right, XK_Up, XK_Down, 0, 0, 0, 0,
+       XK_Home, XK_End, XK_Page_Up, XK_Page_Down, XK_Insert, XK_Delete, 0, 0,
+       XK_F1, XK_F2, XK_F3, XK_F4, XK_F5, XK_F6, XK_F7, XK_F8,
+       XK_F9, XK_F10, XK_F11, XK_F12, 0, 0, 0, 0,
+
+       XK_Shift_L, XK_Shift_R, XK_Control_L, XK_Control_R, XK_Alt_L, XK_Alt_R, XK_Super_L, XK_Super_R,
+       XK_Caps_Lock, XK_Scroll_Lock, XK_Num_Lock, 0, 0, 0, 0, 0,
+       XK_KP_0, XK_KP_1, XK_KP_2, XK_KP_3, XK_KP_4, XK_KP_5, XK_KP_6, XK_KP_7,
+       XK_KP_8, XK_KP_9, XK_KP_Add, XK_KP_Subtract, XK_KP_Multiply, XK_KP_Divide, XK_KP_Separator, 0,
+
+       XK_Pause, XK_Print, XK_Menu, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+} // namespace Input
+} // namespace Msp
diff --git a/source/input/x11/mouse.cpp b/source/input/x11/mouse.cpp
new file mode 100644 (file)
index 0000000..3533d56
--- /dev/null
@@ -0,0 +1,23 @@
+#include <msp/graphics/window_private.h>
+#include "mouse.h"
+
+namespace Msp {
+namespace Input {
+
+void Mouse::input_event(const Graphics::Window::Event &event)
+{
+       switch(event.xevent.type)
+       {
+       case ButtonPress:
+       case ButtonRelease:
+               set_button_state(event.xevent.xbutton.button, event.xevent.type==ButtonPress, true);
+               break;
+       case MotionNotify:
+               set_axis_value(0, event.xevent.xmotion.x*2.0/window.get_width()-1.0, true);
+               set_axis_value(1, 1.0-event.xevent.xmotion.y*2.0/window.get_height(), true);
+               break;
+       }
+}
+
+} // namespace Input
+} // namepsace Msp