From 2d1312772711709fc44cb1a39283329864c25100 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 13 Dec 2007 15:07:01 +0000 Subject: [PATCH] Redesign and refactor Add class Display for access to the graphical environemnt before any windows are created Replace GLWindow with an independent GLContext class Put stuff into namespace Graphics Support for querying and changing video modes Handle Xlib errors --- Build | 5 + source/display.cpp | 149 +++++++++++++++++++++++++++++ source/display.h | 54 +++++++++++ source/glcontext.cpp | 92 ++++++++++++++++++ source/{glwindow.h => glcontext.h} | 34 +++---- source/glwindow.cpp | 124 ------------------------ source/keyboard.cpp | 3 +- source/keyboard.h | 6 +- source/mouse.cpp | 3 +- source/mouse.h | 8 +- source/types.h | 21 ++++ source/window.cpp | 133 +++++++++---------------- source/window.h | 40 ++++---- 13 files changed, 408 insertions(+), 264 deletions(-) create mode 100644 source/display.cpp create mode 100644 source/display.h create mode 100644 source/glcontext.cpp rename source/{glwindow.h => glcontext.h} (50%) delete mode 100644 source/glwindow.cpp create mode 100644 source/types.h diff --git a/Build b/Build index 2cf2f26..efb857b 100644 --- a/Build +++ b/Build @@ -9,6 +9,11 @@ package "mspgbase" require "sigc++-2.0"; require "xlib"; + build_info + { + library "Xxf86vm"; + }; + library "mspgbase" { source "source"; diff --git a/source/display.cpp b/source/display.cpp new file mode 100644 index 0000000..724318a --- /dev/null +++ b/source/display.cpp @@ -0,0 +1,149 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include +#include +#include +#include +#include +#include "display.h" +#include "window.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(static_cast(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: "<get_handle()]=wnd; +} + +void Display::remove_window(Window *wnd) +{ + windows.erase(wnd->get_handle()); +} + +void Display::set_mode(const VideoMode &mode) +{ + int screen=DefaultScreen(display); + + int nmodes; + XF86VidModeModeInfo **infos; + XF86VidModeGetAllModeLines(display, screen, &nmodes, &infos); + for(int i=0; i::iterator j=windows.find(event.xany.window); + if(j!=windows.end()) + j->second->event(event); + } + } +} + +void Display::check_error() +{ + if(error_flag) + { + error_flag=false; + throw Exception(error_msg); + } +} + +} // namespace Graphics +} // namespace Msp diff --git a/source/display.h b/source/display.h new file mode 100644 index 0000000..0433eab --- /dev/null +++ b/source/display.h @@ -0,0 +1,54 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_DISPLAY_H_ +#define MSP_GBASE_DISPLAY_H_ + +#include +#include +#include +#include "types.h" + +namespace Msp { +namespace Graphics { + +class Window; + +struct VideoMode +{ + unsigned width; + unsigned height; + unsigned rate; +}; + +class Display +{ +private: + ::Display *display; + std::list modes; + std::map windows; + +public: + Display(const std::string &disp_name=std::string()); + ~Display(); + + ::Display *get_display() const { return display; } + + void add_window(Window *); + void remove_window(Window *); + + const std::list &get_modes() const { return modes; } + void set_mode(const VideoMode &); + + void tick(); + void check_error(); +}; + +} // namespace Graphics +} // namespace Msp + +#endif diff --git a/source/glcontext.cpp b/source/glcontext.cpp new file mode 100644 index 0000000..5995384 --- /dev/null +++ b/source/glcontext.cpp @@ -0,0 +1,92 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include +#include "display.h" +#include "glcontext.h" +#include "window.h" + +namespace Msp { +namespace Graphics { + +GLOptions::GLOptions(): + alpha(false), + stencil(false), + doublebuffer(true), + multisample(0) +{ } + + +GLContext::GLContext(Display &d, const GLOptions &opts): + display(d) +{ + std::vector 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_display(); + XVisualInfo *vi=glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front()); + if(!vi) + throw Exception("Couldn't find a 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); + + glXMakeCurrent(dpy, window, context); +} + +void GLContext::attach(Window &wnd) +{ + XReparentWindow(display.get_display(), window, wnd.get_handle(), 0, 0); + XMapWindow(display.get_display(), window); + + wnd.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized)); + window_resized(wnd.get_width(), wnd.get_height()); +} + +void GLContext::swap_buffers() +{ + glXSwapBuffers(display.get_display(), window); +} + +void GLContext::window_resized(unsigned w, unsigned h) +{ + XMoveResizeWindow(display.get_display(), window, 0, 0, w, h); + glViewport(0, 0, w, h); +} + +} // namespace Graphics +} // namespace Msp diff --git a/source/glwindow.h b/source/glcontext.h similarity index 50% rename from source/glwindow.h rename to source/glcontext.h index dd6e59f..1156b53 100644 --- a/source/glwindow.h +++ b/source/glcontext.h @@ -5,44 +5,46 @@ Copyright © 2007 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ -#ifndef MSP_GBASE_GLWINDOW_H_ -#define MSP_GBASE_GLWINDOW_H_ +#ifndef MSP_GBASE_GLCONTEXT_H_ +#define MSP_GBASE_GLCONTEXT_H_ #include -#include "window.h" +#include "types.h" namespace Msp { +namespace Graphics { -struct GLDisplayOptions +class Display; + +struct GLOptions { bool alpha; bool stencil; bool doublebuffer; unsigned multisample; - GLDisplayOptions(); + GLOptions(); }; -class GLWindow: public Window +class GLContext { -protected: +private: typedef GLXContext Context; - GLDisplayOptions gl_options; - GLXWindow glx_wnd; + Display &display; Context context; + GLXWindow glx_wnd; + WindowHandle window; public: - GLWindow(unsigned, unsigned); - GLWindow(const DisplayOptions &, const GLDisplayOptions &); - ~GLWindow(); - + GLContext(Display &dpy, const GLOptions &opts); + void attach(Window &wnd); void swap_buffers(); -protected: - void init(); - virtual void on_event(const XEvent &event); +private: + void window_resized(unsigned, unsigned); }; +} // namespace Graphics } // namespace Msp #endif diff --git a/source/glwindow.cpp b/source/glwindow.cpp deleted file mode 100644 index fb585f0..0000000 --- a/source/glwindow.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include -#include -#include "glwindow.h" - -using namespace std; - -namespace Msp { - -GLDisplayOptions::GLDisplayOptions(): - alpha(false), - stencil(false), - doublebuffer(true), - multisample(0) -{ } - - -GLWindow::GLWindow(unsigned w, unsigned h) -{ - options.width=w; - options.height=h; - init(); -} - -GLWindow::GLWindow(const DisplayOptions &dopt, const GLDisplayOptions &gl_dopt) -{ - options=dopt; - gl_options=gl_dopt; - init(); -} - -GLWindow::~GLWindow() -{ - glXMakeContextCurrent(display, 0, 0, 0); - glXDestroyWindow(display, glx_wnd); - glXDestroyContext(display, context); -} - -void GLWindow::swap_buffers() -{ - glXSwapBuffers(display, glx_wnd); -} - -void GLWindow::init() -{ - prepare(); - - vector attribs; - - attribs.push_back(GLX_RENDER_TYPE); - attribs.push_back(GLX_RGBA_BIT); - - attribs.push_back(GLX_DRAWABLE_TYPE); - attribs.push_back(GLX_WINDOW_BIT); - - attribs.push_back(GLX_DEPTH_SIZE); - attribs.push_back(1); - - if(gl_options.alpha) - { - attribs.push_back(GLX_ALPHA_SIZE); - attribs.push_back(1); - } - - if(gl_options.stencil) - { - attribs.push_back(GLX_STENCIL_SIZE); - attribs.push_back(1); - } - - if(gl_options.doublebuffer) - { - attribs.push_back(GLX_DOUBLEBUFFER); - attribs.push_back(true); - } - - if(gl_options.multisample>0) - { - attribs.push_back(GLX_SAMPLE_BUFFERS_ARB); - attribs.push_back(gl_options.multisample); - } - - attribs.push_back(None); - - int count; - GLXFBConfig *config=glXChooseFBConfig(display, DefaultScreen(display), &attribs.front(), &count); - if(!config) - throw Exception("Couldn't get a GLX framebuffer configuration"); - - context=glXCreateNewContext(display, config[0], GLX_RGBA_TYPE, 0, true); - if(!context) - throw Exception("Couldn't create a GLX context"); - - XVisualInfo *vi=glXGetVisualFromFBConfig(display, config[0]); - Handle root=RootWindow(display, vi->screen); - - Colormap cmap=XCreateColormap(display, root, vi->visual, AllocNone); - XSetWindowAttributes attr; - attr.colormap=cmap; - attr.override_redirect=options.fullscreen; - - Handle wnd=XCreateWindow(display, root, 0, 0, options.width, options.height, 0, vi->depth, InputOutput, vi->visual, CWColormap|CWOverrideRedirect, &attr); - set_window(wnd); - - glx_wnd=glXCreateWindow(display, config[0], wnd, 0); - - glXMakeContextCurrent(display, glx_wnd, glx_wnd, context); - - XFree(config); -} - -void GLWindow::on_event(const XEvent &event) -{ - if(event.type==ConfigureNotify) - glViewport(0, 0, options.width, options.height); -} - -} // namespace Msp diff --git a/source/keyboard.cpp b/source/keyboard.cpp index 45ef092..ab01e62 100644 --- a/source/keyboard.cpp +++ b/source/keyboard.cpp @@ -6,12 +6,11 @@ Distributed under the LGPL */ #include "keyboard.h" -#include "window.h" namespace Msp { namespace Input { -Keyboard::Keyboard(Window &window) +Keyboard::Keyboard(Graphics::Window &window) { buttons.resize(256, false); diff --git a/source/keyboard.h b/source/keyboard.h index 65b3dba..e300603 100644 --- a/source/keyboard.h +++ b/source/keyboard.h @@ -9,17 +9,15 @@ Distributed under the LGPL #define MSP_GBASE_KEYBOARD_H_ #include "inputdevice.h" +#include "window.h" namespace Msp { - -class Window; - namespace Input { class Keyboard: public Device { public: - Keyboard(Window &); + Keyboard(Graphics::Window &); protected: void key_press(unsigned, unsigned, unsigned); void key_release(unsigned, unsigned); diff --git a/source/mouse.cpp b/source/mouse.cpp index b32b70f..dc36125 100644 --- a/source/mouse.cpp +++ b/source/mouse.cpp @@ -6,12 +6,11 @@ Distributed under the LGPL */ #include "mouse.h" -#include "window.h" namespace Msp { namespace Input { -Mouse::Mouse(Window &w): +Mouse::Mouse(Graphics::Window &w): window(w), axis_scale(0.01) { diff --git a/source/mouse.h b/source/mouse.h index 6260f3b..4199f84 100644 --- a/source/mouse.h +++ b/source/mouse.h @@ -9,21 +9,19 @@ Distributed under the LGPL #define MSP_GBASE_MOUSE_H_ #include "inputdevice.h" +#include "window.h" namespace Msp { - -class Window; - namespace Input { class Mouse: public Device { private: - Window &window; + Graphics::Window &window; float axis_scale; public: - Mouse(Window &); + Mouse(Graphics::Window &); private: void button_press(int, int, unsigned, unsigned); void button_release(int, int, unsigned, unsigned); diff --git a/source/types.h b/source/types.h new file mode 100644 index 0000000..1badc5d --- /dev/null +++ b/source/types.h @@ -0,0 +1,21 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_TYPES_H_ +#define MSP_GBASE_TYPES_H_ + +#include + +namespace Msp { +namespace Graphics { + +typedef ::Window WindowHandle; + +} // namespace Graphics +} // namespace Msp + +#endif diff --git a/source/window.cpp b/source/window.cpp index ee5bec9..f867faf 100644 --- a/source/window.cpp +++ b/source/window.cpp @@ -9,38 +9,35 @@ Distributed under the LGPL #include #include #include +#include "display.h" #include "window.h" using namespace std; namespace Msp { +namespace Graphics { -DisplayOptions::DisplayOptions(): +WindowOptions::WindowOptions(): width(640), height(480), - fullscreen(false) + fullscreen(false), + resizable(false) { } -/** -Initializes the class but does not open the window. Intended for use by -derived classes. -*/ -Window::Window(): - display(0), - window(0) -{ } - -Window::Window(unsigned w, unsigned h) +Window::Window(Display &dpy, unsigned w, unsigned h, bool fs): + display(dpy) { options.width=w; options.height=h; + options.fullscreen=fs; init(); } -Window::Window(const DisplayOptions &dopt): - options(dopt) +Window::Window(Display &dpy, const WindowOptions &opts): + display(dpy), + options(opts) { init(); } @@ -48,9 +45,9 @@ Window::Window(const DisplayOptions &dopt): Window::~Window() { if(window) - XDestroyWindow(display, window); - if(display) - XCloseDisplay(display); + XDestroyWindow(display.get_display(), window); + + display.remove_window(this); } void Window::set_title(const string &title) @@ -61,123 +58,79 @@ void Window::set_title(const string &title) prop.encoding=XA_STRING; prop.format=8; prop.nitems=title.size(); - XSetWMName(display, window, &prop); + XSetWMName(display.get_display(), window, &prop); + display.check_error(); } void Window::show() { - XMapRaised(display, window); + XMapRaised(display.get_display(), window); + display.check_error(); } void Window::hide() { - XUnmapWindow(display, window); -} - -void Window::tick() -{ - while(1) - { - int pending=XPending(display); - if(pending==0) - break; - - for(int i=0; i(&event.xkey), buf, sizeof(buf), 0, 0); + XLookupString(const_cast(&ev.xkey), buf, sizeof(buf), 0, 0); // XXX Handle the result according to locale - signal_key_press.emit(event.xkey.keycode, event.xkey.state, buf[0]); + signal_key_press.emit(ev.xkey.keycode, ev.xkey.state, buf[0]); } break; case KeyRelease: - signal_key_release.emit(event.xkey.keycode, event.xkey.state); + signal_key_release.emit(ev.xkey.keycode, ev.xkey.state); break; case ConfigureNotify: - options.width=event.xconfigure.width; - options.height=event.xconfigure.height; + options.width=ev.xconfigure.width; + options.height=ev.xconfigure.height; signal_resize.emit(options.width, options.height); break; case ClientMessage: - if(event.xclient.data.l[0]==static_cast(wm_delete_window)) + if(ev.xclient.data.l[0]==static_cast(wm_delete_window)) signal_close.emit(); break; case EnterNotify: - XSetInputFocus(display, window, RevertToParent, CurrentTime); + XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime); break; default:; } - - on_event(event); -} - -int Window::x_error_handler(Display *display, XErrorEvent *error) -{ - char buf[128]; - XGetErrorText(display, error->error_code, buf, sizeof(buf)); - /*string request_code=lexical_cast(error->request_code); - char buf2[1024]; - XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), buf, buf2, sizeof(buf2));*/ - throw Exception(buf); } +} // namespace Graphics } // namespace Msp diff --git a/source/window.h b/source/window.h index a8ad867..1047038 100644 --- a/source/window.h +++ b/source/window.h @@ -9,19 +9,22 @@ Distributed under the LGPL #define MSP_GBASE_WINDOW_H_ #include -#include #include +#include "types.h" namespace Msp { +namespace Graphics { -struct DisplayOptions +class Display; + +struct WindowOptions { - std::string display; unsigned width; unsigned height; bool fullscreen; + bool resizable; - DisplayOptions(); + WindowOptions(); }; class Window @@ -36,36 +39,31 @@ public: sigc::signal signal_close; protected: - typedef ::Window Handle; - - Display *display; - DisplayOptions options; - Handle window; - Atom wm_delete_window; + Display &display; + WindowOptions options; + WindowHandle window; + Atom wm_delete_window; - Window(); public: - Window(unsigned w, unsigned h); - Window(const DisplayOptions &dopt); - virtual ~Window(); + Window(Display &, unsigned w, unsigned h, bool fs=false); + Window(Display &, const WindowOptions &); + ~Window(); void set_title(const std::string &); unsigned get_width() const { return options.width; } unsigned get_height() const { return options.height; } + WindowHandle get_handle() const { return window; } + void show(); void hide(); - void tick(); + + void event(const XEvent &ev); protected: - void prepare(); - void set_window(Handle wnd); void init(); - void process_event(const XEvent &event); - virtual void on_event(const XEvent &event) { (void)event; } - - static int x_error_handler(Display *, XErrorEvent *); }; +} // namespace Graphics } // namespace Msp #endif -- 2.43.0