]> git.tdb.fi Git - libs/gui.git/commitdiff
Win32 compatibility (for most things)
authorMikko Rasa <tdb@tdb.fi>
Sun, 30 Dec 2007 16:18:40 +0000 (16:18 +0000)
committerMikko Rasa <tdb@tdb.fi>
Sun, 30 Dec 2007 16:18:40 +0000 (16:18 +0000)
Bind GLContext to a Window at creation time

Build
source/display.cpp
source/display.h
source/glcontext.cpp
source/glcontext.h
source/types.h
source/window.cpp
source/window.h

diff --git a/Build b/Build
index efb857bc0be93e8f5c4503bfdac0a416cac82774..19c48cb3844b50c40b81d249e670f04a04aa05a0 100644 (file)
--- a/Build
+++ b/Build
@@ -7,11 +7,23 @@ package "mspgbase"
 
        require "mspcore";
        require "sigc++-2.0";
-       require "xlib";
-
-       build_info
+       // The OpenGL stuff is hackish, but only way to do it right now
+       if "arch!=win32"
+       {
+               require "xlib";
+               require "opengl";
+               build_info
+               {
+                       library "Xxf86vm";
+               };
+       };
+       if "arch=win32"
        {
-               library "Xxf86vm";
+               build_info
+               {
+                       library "opengl32";
+                       library "gdi32";
+               };
        };
 
        library "mspgbase"
index ba5a6402c4196f937d5ddc689b577813325a8c2f..3baf7c11a72e92eb1a1827666f247198d85e21aa 100644 (file)
@@ -6,8 +6,10 @@ Distributed under the LGPL
 */
 
 #include <iostream>
+#ifndef WIN32
 #include <X11/Xlib.h>
 #include <X11/extensions/xf86vmode.h>
+#endif
 #include <msp/core/except.h>
 #include <msp/strings/formatter.h>
 #include <msp/strings/lexicalcast.h>
@@ -21,6 +23,7 @@ namespace {
 bool error_flag=false;
 std::string error_msg;
 
+#ifndef WIN32
 int x_error_handler(Display *display, XErrorEvent *event)
 {
        char err[128];
@@ -42,6 +45,7 @@ int x_error_handler(Display *display, XErrorEvent *event)
 
        return 0;
 }
+#endif
 
 }
 
@@ -50,6 +54,7 @@ namespace Graphics {
 
 Display::Display(const string &disp_name)
 {
+#ifndef WIN32
        if(disp_name.empty())
                display=XOpenDisplay(0);
        else
@@ -80,12 +85,17 @@ Display::Display(const string &disp_name)
        XF86VidModeGetModeLine(display, screen, &dotclock, &modeline);
        orig_mode=VideoMode(modeline.hdisplay, modeline.vdisplay);
        orig_mode.rate=dotclock/(modeline.htotal*modeline.vtotal);
+#else
+       (void)disp_name;
+#endif
 }
 
 Display::~Display()
 {
+#ifndef WIN32
        XCloseDisplay(display);
        display=0;
+#endif
 }
 
 void Display::add_window(Window *wnd)
@@ -100,6 +110,7 @@ void Display::remove_window(Window *wnd)
 
 void Display::set_mode(const VideoMode &mode)
 {
+#ifndef WIN32
        int screen=DefaultScreen(display);
 
        int nmodes;
@@ -119,6 +130,9 @@ void Display::set_mode(const VideoMode &mode)
        }
 
        throw InvalidParameterValue("Requested mode not supported");
+#else
+       (void)mode;
+#endif
 }
 
 void Display::tick()
@@ -127,6 +141,13 @@ void Display::tick()
 
        while(1)
        {
+#ifdef WIN32
+               MSG msg;
+               if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+                       DispatchMessage(&msg);
+               else
+                       break;
+#else
                int pending=XPending(display);
                if(pending==0)
                        break;
@@ -142,6 +163,7 @@ void Display::tick()
                        if(j!=windows.end())
                                j->second->event(event);
                }
+#endif
        }
 }
 
index 7397a785c309513e6459833cd4779162ea494a65..70efd20627426bed067dbd988b8cac1e1c811c4b 100644 (file)
@@ -31,7 +31,9 @@ struct VideoMode
 class Display
 {
 private:
+#ifndef WIN32
        ::Display *display;
+#endif
        std::list<VideoMode> modes;
        VideoMode orig_mode;
        std::map<WindowHandle, Window *> windows;
@@ -40,7 +42,9 @@ public:
        Display(const std::string &disp_name=std::string());
        ~Display();
 
+#ifndef WIN32
        ::Display *get_display() const { return display; }
+#endif
 
        void add_window(Window *);
        void remove_window(Window *);
index 9377e888a8b977133ce82f915afd5bcf4ec599e1..a749c6ce8f3966dbfc7514180a25a76603e29724 100644 (file)
@@ -6,11 +6,19 @@ Distributed under the LGPL
 */
 
 #include <vector>
+#ifdef WIN32
+#include <windows.h>
+#endif
+#include <GL/gl.h>
+#include <msp/core/application.h>
 #include <msp/core/except.h>
 #include "display.h"
 #include "glcontext.h"
 #include "window.h"
 
+#include <iostream>
+using namespace std;
+
 namespace Msp {
 namespace Graphics {
 
@@ -22,9 +30,38 @@ GLOptions::GLOptions():
 { }
 
 
-GLContext::GLContext(Display &d, const GLOptions &opts):
-       display(d)
+GLContext::GLContext(Window &wnd, const GLOptions &opts):
+       display(wnd.get_display()),
+       window(wnd)
 {
+#ifdef WIN32
+       HDC dc=GetDC(window.get_handle());
+
+       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 Exception("Couldn't find a suitable pixel format");
+       SetPixelFormat(dc, pf_index, &pfd);
+
+       context=wglCreateContext(dc);
+       wglMakeCurrent(dc, context);
+
+       ReleaseDC(window.get_handle(), dc);
+#else
        std::vector<int> attribs;
        
        attribs.push_back(GLX_RGBA);
@@ -55,44 +92,56 @@ GLContext::GLContext(Display &d, const GLOptions &opts):
        attribs.push_back(0);
 
        ::Display *dpy=display.get_display();
+
        XVisualInfo *vi=glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front());
        if(!vi)
-               throw Exception("Couldn't find a GLX visual");
+               throw Exception("Couldn't find a suitable GLX visual");
        context=glXCreateContext(dpy, vi, 0, true);
 
        XSetWindowAttributes attr;
        attr.colormap=XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
 
-       window=XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1024, 768, 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr);
+       subwnd=XCreateWindow(dpy, window.get_handle(), 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr);
+       XMapWindow(display.get_display(), subwnd);
 
        XFree(vi);
 
-       glXMakeCurrent(dpy, window, context);
-}
+       glXMakeCurrent(dpy, subwnd, context);
 
-GLContext::~GLContext()
-{
-       glXDestroyContext(display.get_display(), context);
-       XDestroyWindow(display.get_display(), window);
+       window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized));
+#endif
 }
 
-void GLContext::attach(Window &wnd)
+GLContext::~GLContext()
 {
-       XReparentWindow(display.get_display(), window, wnd.get_handle(), 0, 0);
-       XMapWindow(display.get_display(), window);
+#ifdef WIN32
+       wglMakeCurrent(0, 0);
+       wglDeleteContext(context);
+#else
+       ::Display *dpy=display.get_display();
 
-       wnd.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized));
-       window_resized(wnd.get_width(), wnd.get_height());
+       glXMakeCurrent(dpy, 0, 0);
+       glXDestroyContext(dpy, context);
+       XDestroyWindow(dpy, subwnd);
+#endif
 }
 
 void GLContext::swap_buffers()
 {
-       glXSwapBuffers(display.get_display(), window);
+#ifdef WIN32
+       HDC dc=GetDC(window.get_handle());
+       SwapBuffers(dc);
+       ReleaseDC(window.get_handle(), dc);
+#else
+       glXSwapBuffers(display.get_display(), subwnd);
+#endif
 }
 
 void GLContext::window_resized(unsigned w, unsigned h)
 {
-       XMoveResizeWindow(display.get_display(), window, 0, 0, w, h);
+#ifndef WIN32
+       XMoveResizeWindow(display.get_display(), subwnd, 0, 0, w, h);
+#endif
        glViewport(0, 0, w, h);
 }
 
index f9e5f4696d9aab3cebeceed67be72049d0eeda5a..36130e1c55df8b8d048ea5a2000a12cc367724d0 100644 (file)
@@ -8,7 +8,9 @@ Distributed under the LGPL
 #ifndef MSP_GBASE_GLCONTEXT_H_
 #define MSP_GBASE_GLCONTEXT_H_
 
+#ifndef WIN32
 #include <GL/glx.h>
+#endif
 #include "types.h"
 
 namespace Msp {
@@ -29,18 +31,23 @@ struct GLOptions
 class GLContext
 {
 private:
+#ifdef WIN32
+       typedef HGLRC Context;
+#else
        typedef GLXContext Context;
+#endif
 
        Display &display;
+       Window &window;
        Context context;
-       GLXWindow glx_wnd;
-       WindowHandle window;
+#ifndef WIN32
+       WindowHandle subwnd;
+#endif
 
 public:
-       GLContext(Display &dpy, const GLOptions &opts);
+       GLContext(Window &wnd, const GLOptions &opts);
        ~GLContext();
 
-       void attach(Window &wnd);
        void swap_buffers();
 private:
        void window_resized(unsigned, unsigned);
index 1badc5dba48536b7556d2aab324d1bc38456d7c1..e3524f32e0962c6ee485c05eb4a26cc72f256a23 100644 (file)
@@ -8,12 +8,20 @@ Distributed under the LGPL
 #ifndef MSP_GBASE_TYPES_H_
 #define MSP_GBASE_TYPES_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
 
 } // namespace Graphics
 } // namespace Msp
index f916d1c9e5312e4290d40224e076b0e9e776b5e1..7f6f6d8fa0e6c77463df993397d01b9dc10ff777 100644 (file)
@@ -6,14 +6,21 @@ Distributed under the LGPL
 */
 
 #include <vector>
+#ifndef WIN32
 #include <X11/Xatom.h>
 #include <X11/Xutil.h>
+#else
+#include <windowsx.h>
+#endif
+#include <msp/core/application.h>
 #include <msp/core/except.h>
 #include "display.h"
 #include "window.h"
 
 using namespace std;
 
+#include <iostream>
+
 namespace Msp {
 namespace Graphics {
 
@@ -45,7 +52,11 @@ Window::Window(Display &dpy, const WindowOptions &opts):
 Window::~Window()
 {
        if(window)
+#ifdef WIN32
+               CloseWindow(window);
+#else
                XDestroyWindow(display.get_display(), window);
+#endif
 
        display.remove_window(this);
 
@@ -55,6 +66,9 @@ Window::~Window()
 
 void Window::set_title(const string &title)
 {
+#ifdef WIN32
+       SetWindowText(window, title.c_str());
+#else
        vector<unsigned char> buf(title.begin(), title.end());
        XTextProperty prop;
        prop.value=&buf[0];
@@ -63,6 +77,7 @@ void Window::set_title(const string &title)
        prop.nitems=title.size();
        XSetWMName(display.get_display(), window, &prop);
        display.check_error();
+#endif
 }
 
 void Window::reconfigure(const WindowOptions &opts)
@@ -71,6 +86,12 @@ void Window::reconfigure(const WindowOptions &opts)
 
        options=opts;
 
+#ifdef WIN32
+       // XXX Preserve position
+       MoveWindow(window, 0, 0, options.width, options.height, false);
+
+       (void)fullscreen_changed;
+#else
        ::Display *dpy=display.get_display();
 
        XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height);
@@ -88,22 +109,78 @@ void Window::reconfigure(const WindowOptions &opts)
                display.set_mode(VideoMode(options.width, options.height));
        else if(fullscreen_changed)
                display.restore_mode();
+#endif
 }
 
 void Window::show()
 {
+#ifdef WIN32
+       ShowWindow(window, SW_SHOWNORMAL);
+#else
        XMapRaised(display.get_display(), window);
        display.check_error();
+#endif
 }
 
 void Window::hide()
 {
+#ifdef WIN32
+       ShowWindow(window, SW_HIDE);
+#else
        XUnmapWindow(display.get_display(), window);
        display.check_error();
+#endif
 }
 
 void Window::init()
 {
+#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=0;
+               wndcl.hbrBackground=0;
+               wndcl.lpszMenuName=0;
+               wndcl.lpszClassName="mspgbase";
+               wndcl.hIconSm=0;
+
+               if(!RegisterClassEx(&wndcl))
+                       throw Exception("Couldn't register window class");
+
+               wndclass_created=true;
+       }
+
+       RECT rect;
+       rect.left=0;
+       rect.top=0;
+       rect.right=options.width;
+       rect.bottom=options.height;
+       AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW);
+
+       window=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
+               "mspgbase",
+               "Window",
+               WS_OVERLAPPEDWINDOW,
+               CW_USEDEFAULT, CW_USEDEFAULT,
+               rect.right-rect.left, rect.bottom-rect.top,
+               0,
+               0,
+               reinterpret_cast<HINSTANCE>(Application::get_data()),
+               this);
+       if(!window)
+               throw Exception("CreateWindowEx failed");
+
+#else
        ::Display *dpy=display.get_display();
 
        wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true);
@@ -112,7 +189,15 @@ void Window::init()
        attr.override_redirect=options.fullscreen;
        attr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask;
 
-       window=XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, options.width, options.height, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect|CWEventMask, &attr);
+       window=XCreateWindow(dpy,
+               DefaultRootWindow(dpy),
+               0, 0,
+               options.width, options.height,
+               0,
+               CopyFromParent,
+               InputOutput,
+               CopyFromParent,
+               CWOverrideRedirect|CWEventMask, &attr);
 
        XSetWMProtocols(dpy, window, &wm_delete_window, 1);
 
@@ -121,11 +206,13 @@ void Window::init()
                display.set_mode(VideoMode(options.width, options.height));
                XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2);
        }
+#endif
 
        display.add_window(this);
        display.check_error();
 }
 
+#ifndef WIN32
 void Window::event(const XEvent &ev)
 {
        switch(ev.type)
@@ -169,6 +256,67 @@ void Window::event(const XEvent &ev)
        default:;
        }
 }
+#endif
+
+#ifdef WIN32
+int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp)
+{
+       switch(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_MOUSEMOVE:
+               signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
+               break;
+       case WM_CLOSE:
+               signal_close.emit();
+               break;
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
+LRESULT CALLBACK Window::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
+       {
+               Window *wnd=reinterpret_cast<Window *>(GetWindowLong(hwnd, 0));
+               if(wnd && wnd->wndproc(msg, wparam, lparam))
+                       return 0;
+       }
+
+       return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+#endif
 
 } // namespace Graphics
 } // namespace Msp
index 2999a783fc137a1c3e1e67e6d01464c19286d530..e85f86ac7128e522e7869d9a9faec8f5e811b7f7 100644 (file)
@@ -42,7 +42,9 @@ protected:
        Display &display;
        WindowOptions options;
        WindowHandle window;
+#ifndef WIN32
        Atom wm_delete_window;
+#endif
 
 public:
        Window(Display &, unsigned w, unsigned h, bool fs=false);
@@ -52,6 +54,7 @@ public:
        void set_title(const std::string &);
        void reconfigure(const WindowOptions &);
 
+       Display &get_display() const { return display; }
        const WindowOptions &get_options() const { return options; }
        unsigned get_width() const  { return options.width; }
        unsigned get_height() const { return options.height; }
@@ -60,9 +63,15 @@ public:
        void show();
        void hide();
 
+#ifndef WIN32
        void event(const XEvent &ev);
+#endif
 protected:
        void init();
+#ifdef WIN32
+       int wndproc(UINT, WPARAM, LPARAM);
+       static LRESULT CALLBACK wndproc_(HWND, UINT, WPARAM, LPARAM);
+#endif
 };
 
 } // namespace Graphics