};
};
+ headers "gbase"
+ {
+ source "source/gbase";
+ install_headers "msp/gbase";
+ };
+
+ headers "input"
+ {
+ source "source/input";
+ install_headers "msp/input";
+ };
+
library "mspgbase"
{
- source "source";
+ source "source/gbase";
+ source "source/input";
install true;
- install_headers "msp/gbase";
};
};
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include "binarycontrol.h"
-#include "inputdevice.h"
-
-namespace Msp {
-namespace Input {
-
-BinaryControl::BinaryControl():
- state(false)
-{ }
-
-BinaryControl::BinaryControl(const ControlSource &s):
- Control(s),
- state(false)
-{ }
-
-BinaryControl::BinaryControl(Device &d, ControlSrcType t, unsigned i):
- Control(d, t, i),
- state(false)
-{ }
-
-void BinaryControl::on_press()
-{
- if(!state)
- {
- state=true;
- signal_press.emit();
- }
-}
-
-void BinaryControl::on_release()
-{
- if(state)
- {
- state=false;
- signal_release.emit();
- }
-}
-
-void BinaryControl::on_motion(float value, float)
-{
- if(value>src.dev->get_axis_threshold())
- on_press();
- else
- on_release();
-}
-
-} // namespace Input
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_GBASE_BINARYCONTROL_H_
-#define MSP_GBASE_BINARYCONTROL_H_
-
-#include "control.h"
-
-namespace Msp {
-namespace Input {
-
-/**
-A control with two possible states. Button state is mapped directly. An axis
-is considered to be active when its value is above a threshold (defined by the
-input device).
-*/
-class BinaryControl: public Control
-{
-public:
- sigc::signal<void> signal_press;
- sigc::signal<void> signal_release;
-
-private:
- bool state;
-
-public:
- BinaryControl();
- BinaryControl(const ControlSource &);
- BinaryControl(Device &, ControlSrcType, unsigned);
- bool get_state() const { return state; }
-
-private:
- virtual void on_press();
- virtual void on_release();
- virtual void on_motion(float, float);
-};
-
-} // namespace Input
-} // namespace Msp
-
-#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <msp/core/except.h>
-#include <msp/strings/lexicalcast.h>
-#include "control.h"
-#include "inputdevice.h"
-
-namespace Msp {
-namespace Input {
-
-ControlSource::ControlSource():
- dev(0),
- type(NONE),
- index(0)
-{ }
-
-ControlSource::ControlSource(Device &d, ControlSrcType t, unsigned i):
- dev(&d),
- type(t),
- index(i)
-{ }
-
-std::string ControlSource::str() const
-{
- if(type==BUTTON)
- return dev->get_button_name(index);
- else if(type==AXIS_POS || type==AXIS_NEG)
- return dev->get_axis_name(index);
- else if(type==NONE)
- return "None";
-
- return lexical_cast(index);
-}
-
-
-Control::Control():
- capture_dev(0)
-{ }
-
-Control::Control(const ControlSource &s):
- src(s),
- capture_dev(0)
-{ }
-
-Control::Control(Device &d, ControlSrcType t, unsigned i):
- src(d, t, i),
- capture_dev(0)
-{
- connect_signals();
-}
-
-Control::Control(const Control &c):
- trackable(c),
- src(c.src),
- capture_dev(0)
-{
- connect_signals();
-}
-
-Control &Control::operator=(const Control &c)
-{
- notify_callbacks();
- src=c.src;
- capture_dev=0;
- connect_signals();
-
- return *this;
-}
-
-void Control::capture(Device &d)
-{
- notify_callbacks();
- capture_dev=&d;
- capture_dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press));
- capture_dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion));
-}
-
-void Control::cancel_capture()
-{
- notify_callbacks();
- capture_dev=0;
- connect_signals();
-}
-
-void Control::connect_signals()
-{
- switch(src.type)
- {
- case NONE:
- break;
- case BUTTON:
- src.dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press));
- src.dev->signal_button_release.connect(sigc::mem_fun(this, &Control::button_release));
- break;
- case AXIS_POS:
- case AXIS_NEG:
- src.dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion));
- break;
- default:
- throw Exception("Invalid source in Control");
- }
-}
-
-void Control::button_press(unsigned i)
-{
- if(capture_dev)
- {
- src.dev=capture_dev;
- src.type=BUTTON;
- src.index=i;
-
- notify_callbacks();
- capture_dev=0;
- connect_signals();
- signal_capture_complete.emit();
- }
- else if(src.type==BUTTON && i==src.index)
- on_press();
-}
-
-void Control::button_release(unsigned i)
-{
- if(src.type==BUTTON && i==src.index)
- on_release();
-}
-
-void Control::axis_motion(unsigned i, float v, float r)
-{
- if(capture_dev)
- {
- ControlSrcType type=NONE;
- if(v<-src.dev->get_axis_threshold())
- type=AXIS_NEG;
- else if(v>src.dev->get_axis_threshold())
- type=AXIS_POS;
-
- if(type!=NONE)
- {
- src.dev=capture_dev;
- src.type=type;
- src.index=i;
-
- notify_callbacks();
- capture_dev=0;
- connect_signals();
- signal_capture_complete.emit();
- }
- }
- else if(src.type==AXIS_POS && i==src.index && v>=0)
- on_motion(v, r);
- else if(src.type==AXIS_NEG && i==src.index && v<=0)
- on_motion(-v, -r);
-}
-
-} // namespace Input
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_GBASE_CONTROL_H_
-#define MSP_GBASE_CONTROL_H_
-
-#include <sigc++/signal.h>
-#include <sigc++/trackable.h>
-
-namespace Msp {
-namespace Input {
-
-class Device;
-
-enum ControlSrcType
-{
- NONE,
- BUTTON,
- AXIS_POS,
- AXIS_NEG
-};
-
-/**
-Specifies the source of a control. This provides a way for setting sources for
-different types of controls in a uniform way.
-*/
-struct ControlSource
-{
- Device *dev;
- ControlSrcType type;
- unsigned index;
-
- ControlSource();
- ControlSource(Device &, ControlSrcType, unsigned);
- std::string str() const;
-};
-
-/**
-Provides further abstraction on top of input devices. There are two types of
-controls currently defined: BinaryControl and SmoothControl.
-
-A control uses either a button or half of an axis (positive or negative) as its
-source. How the source values are interpreted depends on the exact type of the
-control. Controls also support interactive binding by capturing a button press
-or axis motion.
-*/
-class Control: public sigc::trackable
-{
-public:
- sigc::signal<void> signal_capture_complete;
-
-protected:
- ControlSource src;
- Device *capture_dev;
-
- Control();
- Control(const ControlSource &);
- Control(Device &, ControlSrcType, unsigned);
- Control(const Control &);
-public:
- Control &operator=(const Control &);
- virtual ~Control() { }
-
- void capture(Device &);
- void cancel_capture();
- const ControlSource &get_source() const { return src; }
-protected:
- virtual void on_press() =0;
- virtual void on_release() =0;
- virtual void on_motion(float, float) =0;
-
-private:
- void connect_signals();
- void button_press(unsigned);
- void button_release(unsigned);
- void axis_motion(unsigned, float, float);
-};
-
-} // namespace Input
-} // namespace Msp
-
-#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-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>
-#include "display.h"
-#include "window.h"
-
-using namespace std;
-
-namespace {
-
-bool error_flag=false;
-std::string error_msg;
-
-#ifndef WIN32
-int x_error_handler(Display *display, XErrorEvent *event)
-{
- char err[128];
- XGetErrorText(display, event->error_code, err, sizeof(err));
-
- string request_code=Msp::lexical_cast(static_cast<int>(event->request_code));
- char req[128];
- XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req));
-
- string msg=Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid);
- if(error_flag)
- cerr<<"Discarding error: "<<msg<<'\n';
- else
- {
- cerr<<msg<<'\n';
- error_msg=msg;
- error_flag=true;
- }
-
- return 0;
-}
-#endif
-
-}
-
-namespace Msp {
-namespace Graphics {
-
-Display::Display(const string &disp_name)
-{
-#ifndef WIN32
- if(disp_name.empty())
- display=XOpenDisplay(0);
- else
- display=XOpenDisplay(disp_name.c_str());
- if(!display)
- throw Exception("Couldn't open X display");
-
- XSetErrorHandler(x_error_handler);
-
- int screen=DefaultScreen(display);
-
- int nmodes;
- XF86VidModeModeInfo **infos;
- XF86VidModeGetAllModeLines(display, screen, &nmodes, &infos);
- for(int i=0; i<nmodes; ++i)
- {
- XF86VidModeModeInfo &info=*infos[i];
-
- VideoMode mode(info.hdisplay, info.vdisplay);
- mode.rate=info.dotclock/(info.htotal*info.vtotal);
- modes.push_back(mode);
- }
-
- XFree(infos);
-
- XF86VidModeModeLine modeline;
- int dotclock;
- 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)
-{
- windows[wnd->get_handle()]=wnd;
-}
-
-void Display::remove_window(Window *wnd)
-{
- windows.erase(wnd->get_handle());
-}
-
-void Display::set_mode(const VideoMode &mode)
-{
-#ifndef WIN32
- int screen=DefaultScreen(display);
-
- int nmodes;
- XF86VidModeModeInfo **infos;
- XF86VidModeGetAllModeLines(display, screen, &nmodes, &infos);
- for(int i=0; i<nmodes; ++i)
- {
- XF86VidModeModeInfo &info=*infos[i];
-
- unsigned rate=info.dotclock/(info.htotal*info.vtotal);
- if(info.hdisplay==mode.width && info.vdisplay==mode.height && (mode.rate==0 || rate==mode.rate))
- {
- XF86VidModeSwitchToMode(display, screen, &info);
- XF86VidModeSetViewPort(display, screen, 0, 0);
- return;
- }
- }
-
- throw InvalidParameterValue("Requested mode not supported");
-#else
- (void)mode;
-#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(display);
- if(pending==0)
- break;
-
- for(int i=0; i<pending; ++i)
- {
- XEvent event;
- XNextEvent(display, &event);
-
- check_error();
-
- map<WindowHandle, Window *>::iterator j=windows.find(event.xany.window);
- if(j!=windows.end())
- j->second->event(event);
- }
-#endif
- }
-}
-
-void Display::check_error()
-{
- if(error_flag)
- {
- error_flag=false;
- throw Exception(error_msg);
- }
-}
-
-} // namespace Graphics
-} // namespace Msp
+++ /dev/null
-/* $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 <list>
-#include <map>
-#include <string>
-#include "types.h"
-
-namespace Msp {
-namespace Graphics {
-
-class Window;
-
-struct VideoMode
-{
- unsigned width;
- unsigned height;
- unsigned rate;
-
- VideoMode(): width(0), height(0), rate(0) { }
- VideoMode(unsigned w, unsigned h): width(w), height(h), rate(0) { }
-};
-
-class Display
-{
-private:
-#ifndef WIN32
- ::Display *display;
-#endif
- std::list<VideoMode> modes;
- VideoMode orig_mode;
- std::map<WindowHandle, Window *> windows;
-
-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 *);
-
- const std::list<VideoMode> &get_modes() const { return modes; }
- void set_mode(const VideoMode &);
- void restore_mode() { set_mode(orig_mode); }
-
- void tick();
- void check_error();
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef WIN32
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <X11/Xutil.h>
-#endif
-#include <msp/core/except.h>
-#include "display.h"
-#include "drawcontext.h"
-#include "window.h"
-
-namespace Msp {
-namespace Graphics {
-
-DrawContext::DrawContext(Window &w):
- display(w.get_display()),
- window(w),
- image(0)
-{
-#ifndef WIN32
- ::Display *dpy=display.get_display();
-
- use_shm=XShmQueryExtension(dpy);
-
- XWindowAttributes wa;
- XGetWindowAttributes(dpy, window.get_handle(), &wa);
-
- if(use_shm)
- {
- image=XShmCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, &shminfo, wa.width, wa.height);
- if(!image)
- throw Exception("Could not create shared memory XImage");
-
- shminfo.shmid=shmget(IPC_PRIVATE, image->bytes_per_line*image->height, IPC_CREAT|0666);
- shminfo.shmaddr=image->data=reinterpret_cast<char *>(shmat(shminfo.shmid, 0, 0));
- shminfo.readOnly=false;
-
- XShmAttach(dpy, &shminfo);
-
- XSync(dpy, false);
- display.check_error();
- }
- else
- {
- image=XCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, 0, wa.width, wa.height, 8, 0);
- if(!image)
- throw Exception("Could not create XImage");
- image->data=new char[image->bytes_per_line*image->height];
- }
-#endif
-}
-
-DrawContext::~DrawContext()
-{
-#ifndef WIN32
- if(use_shm)
- {
- XShmDetach(display.get_display(), &shminfo);
- shmdt(shminfo.shmaddr);
- shmctl(shminfo.shmid, IPC_RMID, 0);
- }
-
- XDestroyImage(image);
-#endif
-}
-
-void DrawContext::update()
-{
-#ifndef WIN32
- ::Display *dpy=display.get_display();
-
- GC gc=XCreateGC(dpy, window.get_handle(), 0, 0);
-
- if(use_shm)
- XShmPutImage(dpy, window.get_handle(), gc, image, 0, 0, 0, 0, image->width, image->height, false);
- else
- XPutImage(dpy, window.get_handle(), gc, image, 0, 0, 0, 0, image->width, image->height);
-
- XFreeGC(dpy, gc);
-#endif
-}
-
-} // namespace Graphics
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_GBASE_DRAWCONTEXT_H_
-#define MSP_GBASE_DRAWCONTEXT_H_
-
-#ifndef WIN32
-#include <X11/Xlib.h>
-#include <X11/extensions/XShm.h>
-#endif
-
-namespace Msp {
-namespace Graphics {
-
-class Display;
-class Window;
-
-class DrawContext
-{
-private:
- Display &display;
- Window &window;
-#ifndef WIN32
- XImage *image;
- bool use_shm;
- XShmSegmentInfo shminfo;
-#endif
-
-public:
- DrawContext(Window &);
- ~DrawContext();
-
- Window &get_window() const { return window; }
- unsigned get_depth() const { return image->bits_per_pixel; }
- unsigned char *get_data() { return reinterpret_cast<unsigned char *>(image->data); }
- void update();
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+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>
+#include "display.h"
+#include "window.h"
+
+using namespace std;
+
+namespace {
+
+bool error_flag=false;
+std::string error_msg;
+
+#ifndef WIN32
+int x_error_handler(Display *display, XErrorEvent *event)
+{
+ char err[128];
+ XGetErrorText(display, event->error_code, err, sizeof(err));
+
+ string request_code=Msp::lexical_cast(static_cast<int>(event->request_code));
+ char req[128];
+ XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req));
+
+ string msg=Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid);
+ if(error_flag)
+ cerr<<"Discarding error: "<<msg<<'\n';
+ else
+ {
+ cerr<<msg<<'\n';
+ error_msg=msg;
+ error_flag=true;
+ }
+
+ return 0;
+}
+#endif
+
+}
+
+namespace Msp {
+namespace Graphics {
+
+Display::Display(const string &disp_name)
+{
+#ifndef WIN32
+ if(disp_name.empty())
+ display=XOpenDisplay(0);
+ else
+ display=XOpenDisplay(disp_name.c_str());
+ if(!display)
+ throw Exception("Couldn't open X display");
+
+ XSetErrorHandler(x_error_handler);
+
+ int screen=DefaultScreen(display);
+
+ int nmodes;
+ XF86VidModeModeInfo **infos;
+ XF86VidModeGetAllModeLines(display, screen, &nmodes, &infos);
+ for(int i=0; i<nmodes; ++i)
+ {
+ XF86VidModeModeInfo &info=*infos[i];
+
+ VideoMode mode(info.hdisplay, info.vdisplay);
+ mode.rate=info.dotclock/(info.htotal*info.vtotal);
+ modes.push_back(mode);
+ }
+
+ XFree(infos);
+
+ XF86VidModeModeLine modeline;
+ int dotclock;
+ 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)
+{
+ windows[wnd->get_handle()]=wnd;
+}
+
+void Display::remove_window(Window *wnd)
+{
+ windows.erase(wnd->get_handle());
+}
+
+void Display::set_mode(const VideoMode &mode)
+{
+#ifndef WIN32
+ int screen=DefaultScreen(display);
+
+ int nmodes;
+ XF86VidModeModeInfo **infos;
+ XF86VidModeGetAllModeLines(display, screen, &nmodes, &infos);
+ for(int i=0; i<nmodes; ++i)
+ {
+ XF86VidModeModeInfo &info=*infos[i];
+
+ unsigned rate=info.dotclock/(info.htotal*info.vtotal);
+ if(info.hdisplay==mode.width && info.vdisplay==mode.height && (mode.rate==0 || rate==mode.rate))
+ {
+ XF86VidModeSwitchToMode(display, screen, &info);
+ XF86VidModeSetViewPort(display, screen, 0, 0);
+ return;
+ }
+ }
+
+ throw InvalidParameterValue("Requested mode not supported");
+#else
+ (void)mode;
+#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(display);
+ if(pending==0)
+ break;
+
+ for(int i=0; i<pending; ++i)
+ {
+ XEvent event;
+ XNextEvent(display, &event);
+
+ check_error();
+
+ map<WindowHandle, Window *>::iterator j=windows.find(event.xany.window);
+ if(j!=windows.end())
+ j->second->event(event);
+ }
+#endif
+ }
+}
+
+void Display::check_error()
+{
+ if(error_flag)
+ {
+ error_flag=false;
+ throw Exception(error_msg);
+ }
+}
+
+} // namespace Graphics
+} // namespace Msp
--- /dev/null
+/* $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 <list>
+#include <map>
+#include <string>
+#include "types.h"
+
+namespace Msp {
+namespace Graphics {
+
+class Window;
+
+struct VideoMode
+{
+ unsigned width;
+ unsigned height;
+ unsigned rate;
+
+ VideoMode(): width(0), height(0), rate(0) { }
+ VideoMode(unsigned w, unsigned h): width(w), height(h), rate(0) { }
+};
+
+class Display
+{
+private:
+#ifndef WIN32
+ ::Display *display;
+#endif
+ std::list<VideoMode> modes;
+ VideoMode orig_mode;
+ std::map<WindowHandle, Window *> windows;
+
+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 *);
+
+ const std::list<VideoMode> &get_modes() const { return modes; }
+ void set_mode(const VideoMode &);
+ void restore_mode() { set_mode(orig_mode); }
+
+ void tick();
+ void check_error();
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef WIN32
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/Xutil.h>
+#endif
+#include <msp/core/except.h>
+#include "display.h"
+#include "drawcontext.h"
+#include "window.h"
+
+namespace Msp {
+namespace Graphics {
+
+DrawContext::DrawContext(Window &w):
+ display(w.get_display()),
+ window(w),
+ image(0)
+{
+#ifndef WIN32
+ ::Display *dpy=display.get_display();
+
+ use_shm=XShmQueryExtension(dpy);
+
+ XWindowAttributes wa;
+ XGetWindowAttributes(dpy, window.get_handle(), &wa);
+
+ if(use_shm)
+ {
+ image=XShmCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, &shminfo, wa.width, wa.height);
+ if(!image)
+ throw Exception("Could not create shared memory XImage");
+
+ shminfo.shmid=shmget(IPC_PRIVATE, image->bytes_per_line*image->height, IPC_CREAT|0666);
+ shminfo.shmaddr=image->data=reinterpret_cast<char *>(shmat(shminfo.shmid, 0, 0));
+ shminfo.readOnly=false;
+
+ XShmAttach(dpy, &shminfo);
+
+ XSync(dpy, false);
+ display.check_error();
+ }
+ else
+ {
+ image=XCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, 0, wa.width, wa.height, 8, 0);
+ if(!image)
+ throw Exception("Could not create XImage");
+ image->data=new char[image->bytes_per_line*image->height];
+ }
+#endif
+}
+
+DrawContext::~DrawContext()
+{
+#ifndef WIN32
+ if(use_shm)
+ {
+ XShmDetach(display.get_display(), &shminfo);
+ shmdt(shminfo.shmaddr);
+ shmctl(shminfo.shmid, IPC_RMID, 0);
+ }
+
+ XDestroyImage(image);
+#endif
+}
+
+void DrawContext::update()
+{
+#ifndef WIN32
+ ::Display *dpy=display.get_display();
+
+ GC gc=XCreateGC(dpy, window.get_handle(), 0, 0);
+
+ if(use_shm)
+ XShmPutImage(dpy, window.get_handle(), gc, image, 0, 0, 0, 0, image->width, image->height, false);
+ else
+ XPutImage(dpy, window.get_handle(), gc, image, 0, 0, 0, 0, image->width, image->height);
+
+ XFreeGC(dpy, gc);
+#endif
+}
+
+} // namespace Graphics
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GBASE_DRAWCONTEXT_H_
+#define MSP_GBASE_DRAWCONTEXT_H_
+
+#ifndef WIN32
+#include <X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+#endif
+
+namespace Msp {
+namespace Graphics {
+
+class Display;
+class Window;
+
+class DrawContext
+{
+private:
+ Display &display;
+ Window &window;
+#ifndef WIN32
+ XImage *image;
+ bool use_shm;
+ XShmSegmentInfo shminfo;
+#endif
+
+public:
+ DrawContext(Window &);
+ ~DrawContext();
+
+ Window &get_window() const { return window; }
+ unsigned get_depth() const { return image->bits_per_pixel; }
+ unsigned char *get_data() { return reinterpret_cast<unsigned char *>(image->data); }
+ void update();
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+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 {
+
+GLOptions::GLOptions():
+ alpha(false),
+ stencil(false),
+ doublebuffer(true),
+ multisample(0)
+{ }
+
+
+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);
+ 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 suitable GLX visual");
+ context=glXCreateContext(dpy, vi, 0, true);
+
+ XSetWindowAttributes attr;
+ attr.colormap=XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
+
+ 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, subwnd, context);
+
+ window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized));
+#endif
+}
+
+GLContext::~GLContext()
+{
+#ifdef WIN32
+ wglMakeCurrent(0, 0);
+ wglDeleteContext(context);
+#else
+ ::Display *dpy=display.get_display();
+
+ glXMakeCurrent(dpy, 0, 0);
+ glXDestroyContext(dpy, context);
+ XDestroyWindow(dpy, subwnd);
+#endif
+}
+
+void GLContext::swap_buffers()
+{
+#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)
+{
+#ifndef WIN32
+ XMoveResizeWindow(display.get_display(), subwnd, 0, 0, w, h);
+#endif
+ glViewport(0, 0, w, h);
+}
+
+} // namespace Graphics
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+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 {
+namespace Graphics {
+
+class Display;
+
+struct GLOptions
+{
+ bool alpha;
+ bool stencil;
+ bool doublebuffer;
+ unsigned multisample;
+
+ GLOptions();
+};
+
+class GLContext
+{
+private:
+#ifdef WIN32
+ typedef HGLRC Context;
+#else
+ typedef GLXContext Context;
+#endif
+
+ Display &display;
+ Window &window;
+ Context context;
+#ifndef WIN32
+ WindowHandle subwnd;
+#endif
+
+public:
+ GLContext(Window &wnd, const GLOptions &opts=GLOptions());
+ ~GLContext();
+
+ void swap_buffers();
+private:
+ void window_resized(unsigned, unsigned);
+};
+
+} // namespace Graphics
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $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_
+
+#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
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+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 {
+
+WindowOptions::WindowOptions():
+ width(640),
+ height(480),
+ fullscreen(false),
+ resizable(false)
+{ }
+
+
+Window::Window(Display &dpy, unsigned w, unsigned h, bool fs):
+ display(dpy)
+{
+ options.width=w;
+ options.height=h;
+ options.fullscreen=fs;
+
+ init();
+}
+
+Window::Window(Display &dpy, const WindowOptions &opts):
+ display(dpy),
+ options(opts)
+{
+ init();
+}
+
+Window::~Window()
+{
+ if(window)
+#ifdef WIN32
+ CloseWindow(window);
+#else
+ XDestroyWindow(display.get_display(), window);
+#endif
+
+ display.remove_window(this);
+
+ if(options.fullscreen)
+ display.restore_mode();
+}
+
+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];
+ prop.encoding=XA_STRING;
+ prop.format=8;
+ prop.nitems=title.size();
+ XSetWMName(display.get_display(), window, &prop);
+ display.check_error();
+#endif
+}
+
+void Window::reconfigure(const WindowOptions &opts)
+{
+ bool fullscreen_changed=(opts.fullscreen!=options.fullscreen);
+
+ 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);
+
+ if(fullscreen_changed)
+ {
+ hide();
+ XSetWindowAttributes attr;
+ attr.override_redirect=options.fullscreen;
+ XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr);
+ show();
+ }
+
+ if(options.fullscreen)
+ 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=LoadCursor(0, IDC_ARROW);
+ 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);
+
+ XSetWindowAttributes attr;
+ 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);
+
+ XSetWMProtocols(dpy, window, &wm_delete_window, 1);
+
+ if(options.fullscreen)
+ {
+ 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)
+ {
+ case ButtonPress:
+ signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
+ break;
+ case ButtonRelease:
+ signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
+ break;
+ case MotionNotify:
+ signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y);
+ break;
+ case KeyPress:
+ {
+ char buf[16];
+ XLookupString(const_cast<XKeyEvent *>(&ev.xkey), buf, sizeof(buf), 0, 0);
+ // XXX Handle the result according to locale
+ signal_key_press.emit(ev.xkey.keycode, ev.xkey.state, buf[0]);
+ }
+ break;
+ case KeyRelease:
+ signal_key_release.emit(ev.xkey.keycode, ev.xkey.state);
+ break;
+ case ConfigureNotify:
+ options.width=ev.xconfigure.width;
+ options.height=ev.xconfigure.height;
+ signal_resize.emit(options.width, options.height);
+ break;
+ case ClientMessage:
+ if(ev.xclient.data.l[0]==static_cast<long>(wm_delete_window))
+ signal_close.emit();
+ break;
+ case EnterNotify:
+ XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime);
+ break;
+ case MapNotify:
+ if(options.fullscreen)
+ XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
+ break;
+ default:;
+ }
+}
+#endif
+
+#ifdef WIN32
+int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp)
+{
+ switch(msg)
+ {
+ case WM_KEYDOWN:
+ signal_key_press.emit((lp>>16)&0x1FF, 0, wp);
+ break;
+ case WM_KEYUP:
+ signal_key_release.emit((lp>>16)&0x1FF, 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
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GBASE_WINDOW_H_
+#define MSP_GBASE_WINDOW_H_
+
+#include <string>
+#include <sigc++/signal.h>
+#include "types.h"
+
+namespace Msp {
+namespace Graphics {
+
+class Display;
+
+struct WindowOptions
+{
+ unsigned width;
+ unsigned height;
+ bool fullscreen;
+ bool resizable;
+
+ WindowOptions();
+};
+
+class Window
+{
+public:
+ sigc::signal<void, int, int, unsigned, unsigned> signal_button_press;
+ sigc::signal<void, int, int, unsigned, unsigned> signal_button_release;
+ sigc::signal<void, int, int> signal_pointer_motion;
+ sigc::signal<void, unsigned, unsigned, unsigned> signal_key_press;
+ sigc::signal<void, unsigned, unsigned> signal_key_release;
+ sigc::signal<void, unsigned, unsigned> signal_resize;
+ sigc::signal<void> signal_close;
+
+protected:
+ Display &display;
+ WindowOptions options;
+ WindowHandle window;
+#ifndef WIN32
+ Atom wm_delete_window;
+#endif
+
+public:
+ Window(Display &, unsigned w, unsigned h, bool fs=false);
+ Window(Display &, const WindowOptions &);
+ ~Window();
+
+ 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; }
+ WindowHandle get_handle() const { return window; }
+
+ 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
+} // namespace Msp
+
+#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-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 {
-
-GLOptions::GLOptions():
- alpha(false),
- stencil(false),
- doublebuffer(true),
- multisample(0)
-{ }
-
-
-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);
- 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 suitable GLX visual");
- context=glXCreateContext(dpy, vi, 0, true);
-
- XSetWindowAttributes attr;
- attr.colormap=XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
-
- 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, subwnd, context);
-
- window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized));
-#endif
-}
-
-GLContext::~GLContext()
-{
-#ifdef WIN32
- wglMakeCurrent(0, 0);
- wglDeleteContext(context);
-#else
- ::Display *dpy=display.get_display();
-
- glXMakeCurrent(dpy, 0, 0);
- glXDestroyContext(dpy, context);
- XDestroyWindow(dpy, subwnd);
-#endif
-}
-
-void GLContext::swap_buffers()
-{
-#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)
-{
-#ifndef WIN32
- XMoveResizeWindow(display.get_display(), subwnd, 0, 0, w, h);
-#endif
- glViewport(0, 0, w, h);
-}
-
-} // namespace Graphics
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-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 {
-namespace Graphics {
-
-class Display;
-
-struct GLOptions
-{
- bool alpha;
- bool stencil;
- bool doublebuffer;
- unsigned multisample;
-
- GLOptions();
-};
-
-class GLContext
-{
-private:
-#ifdef WIN32
- typedef HGLRC Context;
-#else
- typedef GLXContext Context;
-#endif
-
- Display &display;
- Window &window;
- Context context;
-#ifndef WIN32
- WindowHandle subwnd;
-#endif
-
-public:
- GLContext(Window &wnd, const GLOptions &opts=GLOptions());
- ~GLContext();
-
- void swap_buffers();
-private:
- void window_resized(unsigned, unsigned);
-};
-
-} // namespace Graphics
-} // namespace Msp
-
-#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "binarycontrol.h"
+#include "device.h"
+
+namespace Msp {
+namespace Input {
+
+BinaryControl::BinaryControl():
+ state(false)
+{ }
+
+BinaryControl::BinaryControl(const ControlSource &s):
+ Control(s),
+ state(false)
+{ }
+
+BinaryControl::BinaryControl(Device &d, ControlSrcType t, unsigned i):
+ Control(d, t, i),
+ state(false)
+{ }
+
+void BinaryControl::on_press()
+{
+ if(!state)
+ {
+ state=true;
+ signal_press.emit();
+ }
+}
+
+void BinaryControl::on_release()
+{
+ if(state)
+ {
+ state=false;
+ signal_release.emit();
+ }
+}
+
+void BinaryControl::on_motion(float value, float)
+{
+ if(value>src.dev->get_axis_threshold())
+ on_press();
+ else
+ on_release();
+}
+
+} // namespace Input
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GBASE_BINARYCONTROL_H_
+#define MSP_GBASE_BINARYCONTROL_H_
+
+#include "control.h"
+
+namespace Msp {
+namespace Input {
+
+/**
+A control with two possible states. Button state is mapped directly. An axis
+is considered to be active when its value is above a threshold (defined by the
+input device).
+*/
+class BinaryControl: public Control
+{
+public:
+ sigc::signal<void> signal_press;
+ sigc::signal<void> signal_release;
+
+private:
+ bool state;
+
+public:
+ BinaryControl();
+ BinaryControl(const ControlSource &);
+ BinaryControl(Device &, ControlSrcType, unsigned);
+ bool get_state() const { return state; }
+
+private:
+ virtual void on_press();
+ virtual void on_release();
+ virtual void on_motion(float, float);
+};
+
+} // namespace Input
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <msp/core/except.h>
+#include <msp/strings/lexicalcast.h>
+#include "control.h"
+#include "device.h"
+
+namespace Msp {
+namespace Input {
+
+ControlSource::ControlSource():
+ dev(0),
+ type(NONE),
+ index(0)
+{ }
+
+ControlSource::ControlSource(Device &d, ControlSrcType t, unsigned i):
+ dev(&d),
+ type(t),
+ index(i)
+{ }
+
+std::string ControlSource::str() const
+{
+ if(type==BUTTON)
+ return dev->get_button_name(index);
+ else if(type==AXIS_POS || type==AXIS_NEG)
+ return dev->get_axis_name(index);
+ else if(type==NONE)
+ return "None";
+
+ return lexical_cast(index);
+}
+
+
+Control::Control():
+ capture_dev(0)
+{ }
+
+Control::Control(const ControlSource &s):
+ src(s),
+ capture_dev(0)
+{ }
+
+Control::Control(Device &d, ControlSrcType t, unsigned i):
+ src(d, t, i),
+ capture_dev(0)
+{
+ connect_signals();
+}
+
+Control::Control(const Control &c):
+ trackable(c),
+ src(c.src),
+ capture_dev(0)
+{
+ connect_signals();
+}
+
+Control &Control::operator=(const Control &c)
+{
+ notify_callbacks();
+ src=c.src;
+ capture_dev=0;
+ connect_signals();
+
+ return *this;
+}
+
+void Control::capture(Device &d)
+{
+ notify_callbacks();
+ capture_dev=&d;
+ capture_dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press));
+ capture_dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion));
+}
+
+void Control::cancel_capture()
+{
+ notify_callbacks();
+ capture_dev=0;
+ connect_signals();
+}
+
+void Control::connect_signals()
+{
+ switch(src.type)
+ {
+ case NONE:
+ break;
+ case BUTTON:
+ src.dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press));
+ src.dev->signal_button_release.connect(sigc::mem_fun(this, &Control::button_release));
+ break;
+ case AXIS_POS:
+ case AXIS_NEG:
+ src.dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion));
+ break;
+ default:
+ throw Exception("Invalid source in Control");
+ }
+}
+
+void Control::button_press(unsigned i)
+{
+ if(capture_dev)
+ {
+ src.dev=capture_dev;
+ src.type=BUTTON;
+ src.index=i;
+
+ notify_callbacks();
+ capture_dev=0;
+ connect_signals();
+ signal_capture_complete.emit();
+ }
+ else if(src.type==BUTTON && i==src.index)
+ on_press();
+}
+
+void Control::button_release(unsigned i)
+{
+ if(src.type==BUTTON && i==src.index)
+ on_release();
+}
+
+void Control::axis_motion(unsigned i, float v, float r)
+{
+ if(capture_dev)
+ {
+ ControlSrcType type=NONE;
+ if(v<-src.dev->get_axis_threshold())
+ type=AXIS_NEG;
+ else if(v>src.dev->get_axis_threshold())
+ type=AXIS_POS;
+
+ if(type!=NONE)
+ {
+ src.dev=capture_dev;
+ src.type=type;
+ src.index=i;
+
+ notify_callbacks();
+ capture_dev=0;
+ connect_signals();
+ signal_capture_complete.emit();
+ }
+ }
+ else if(src.type==AXIS_POS && i==src.index && v>=0)
+ on_motion(v, r);
+ else if(src.type==AXIS_NEG && i==src.index && v<=0)
+ on_motion(-v, -r);
+}
+
+} // namespace Input
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GBASE_CONTROL_H_
+#define MSP_GBASE_CONTROL_H_
+
+#include <sigc++/signal.h>
+#include <sigc++/trackable.h>
+
+namespace Msp {
+namespace Input {
+
+class Device;
+
+enum ControlSrcType
+{
+ NONE,
+ BUTTON,
+ AXIS_POS,
+ AXIS_NEG
+};
+
+/**
+Specifies the source of a control. This provides a way for setting sources for
+different types of controls in a uniform way.
+*/
+struct ControlSource
+{
+ Device *dev;
+ ControlSrcType type;
+ unsigned index;
+
+ ControlSource();
+ ControlSource(Device &, ControlSrcType, unsigned);
+ std::string str() const;
+};
+
+/**
+Provides further abstraction on top of input devices. There are two types of
+controls currently defined: BinaryControl and SmoothControl.
+
+A control uses either a button or half of an axis (positive or negative) as its
+source. How the source values are interpreted depends on the exact type of the
+control. Controls also support interactive binding by capturing a button press
+or axis motion.
+*/
+class Control: public sigc::trackable
+{
+public:
+ sigc::signal<void> signal_capture_complete;
+
+protected:
+ ControlSource src;
+ Device *capture_dev;
+
+ Control();
+ Control(const ControlSource &);
+ Control(Device &, ControlSrcType, unsigned);
+ Control(const Control &);
+public:
+ Control &operator=(const Control &);
+ virtual ~Control() { }
+
+ void capture(Device &);
+ void cancel_capture();
+ const ControlSource &get_source() const { return src; }
+protected:
+ virtual void on_press() =0;
+ virtual void on_release() =0;
+ virtual void on_motion(float, float) =0;
+
+private:
+ void connect_signals();
+ void button_press(unsigned);
+ void button_release(unsigned);
+ void axis_motion(unsigned, float, float);
+};
+
+} // namespace Input
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <msp/strings/formatter.h>
+#include "device.h"
+
+namespace Msp {
+namespace Input {
+
+bool Device::get_button_state(unsigned btn) const
+{
+ if(btn>buttons.size())
+ return false;
+
+ return buttons[btn];
+}
+
+float Device::get_axis_value(unsigned axis) const
+{
+ if(axis>axes.size())
+ return 0;
+
+ return axes[axis];
+}
+
+std::string Device::get_button_name(unsigned btn) const
+{
+ return format("Button %d", btn);
+}
+
+std::string Device::get_axis_name(unsigned axis) const
+{
+ return format("Axis %d", axis);
+}
+
+void Device::set_button_state(unsigned btn, bool state, bool event)
+{
+ if(btn>=buttons.size())
+ buttons.resize(btn+1, false);
+
+ if(state!=buttons[btn])
+ {
+ buttons[btn]=state;
+
+ if(event)
+ {
+ if(state)
+ signal_button_press.emit(btn);
+ else
+ signal_button_release.emit(btn);
+ }
+ }
+}
+
+void Device::set_axis_value(unsigned axis, float value, bool event)
+{
+ if(axis>=axes.size())
+ axes.resize(axis+1, 0);
+
+ if(value!=axes[axis])
+ {
+ float old=axes[axis];
+ axes[axis]=value;
+
+ if(event)
+ signal_axis_motion.emit(axis, value, value-old);
+ }
+}
+
+} // namespace Input
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GBASE_INPUTDEVICE_H_
+#define MSP_GBASE_INPUTDEVICE_H_
+
+#include <string>
+#include <vector>
+#include <sigc++/signal.h>
+
+namespace Msp {
+namespace Input {
+
+/**
+Base class for input devices. Input devices have two types of controls:
+buttons and axes. Buttons are either on or off. Axes have a floating-point
+value, with range depending on the device.
+*/
+class Device
+{
+public:
+ sigc::signal<void, unsigned> signal_button_press;
+ sigc::signal<void, unsigned> signal_button_release;
+ sigc::signal<void, unsigned, float, float> signal_axis_motion;
+
+protected:
+ std::string name;
+ std::vector<char> buttons;
+ std::vector<float> axes;
+ float axis_threshold;
+ float axis_dead_zone;
+
+ Device() { }
+public:
+ virtual ~Device() { }
+ const std::string &get_name() const { return name; }
+ bool get_button_state(unsigned) const;
+ float get_axis_value(unsigned) const;
+ float get_axis_threshold() const { return axis_threshold; }
+
+ virtual std::string get_button_name(unsigned) const;
+ virtual std::string get_axis_name(unsigned) const;
+protected:
+ void set_button_state(unsigned, bool, bool);
+ void set_axis_value(unsigned, float, bool);
+};
+
+} // namespace Input
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <sigc++/bind.h>
+#include <msp/core/except.h>
+#include "hub.h"
+
+namespace Msp {
+namespace Input {
+
+Hub::Hub()
+{
+ name="Hub";
+}
+
+unsigned Hub::attach(Device &dev)
+{
+ unsigned index=devices.size();
+ devices.push_back(&dev);
+ dev.signal_button_press.connect(sigc::bind(sigc::mem_fun(this, &Hub::button_press), index));
+ dev.signal_button_release.connect(sigc::bind(sigc::mem_fun(this, &Hub::button_release), index));
+ dev.signal_axis_motion.connect(sigc::bind(sigc::mem_fun(this, &Hub::axis_motion), index));
+ return index;
+}
+
+std::string Hub::get_button_name(unsigned btn) const
+{
+ unsigned dev_index=btn>>12;
+ if(dev_index>devices.size())
+ throw InvalidParameterValue("Button does not exist");
+
+ const Device &dev=*devices[dev_index];
+ return dev.get_name()+": "+dev.get_button_name(btn&0xFFF);
+}
+
+void Hub::button_press(unsigned btn, unsigned index)
+{
+ set_button_state(index<<12 | btn&0xFFF, true, true);
+}
+
+void Hub::button_release(unsigned btn, unsigned index)
+{
+ set_button_state(index<<12 | btn&0xFFF, false, true);
+}
+
+void Hub::axis_motion(unsigned axis, float value, float, unsigned index)
+{
+ set_axis_value(index<<12 | axis&0xFFF, value, true);
+}
+
+} // namespace Input
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GBASE_INPUTHUB_H_
+#define MSP_GBASE_INPUTHUB_H_
+
+#include "device.h"
+
+namespace Msp {
+namespace Input {
+
+/**
+The Hub device collects events from multiple input devices and presents an
+aggregate of them. Button and axis numbers are mapped to unique values.
+*/
+class Hub: public Device
+{
+protected:
+ std::vector<Device *> devices;
+
+public:
+ Hub();
+
+ /**
+ Attaches an input device to the hub.
+
+ @param dev Device to attach
+
+ @return Index of the device within the hub
+ */
+ unsigned attach(Device &dev);
+
+ virtual std::string get_button_name(unsigned) const;
+protected:
+ void button_press(unsigned, unsigned);
+ void button_release(unsigned, unsigned);
+ void axis_motion(unsigned, float, float, unsigned);
+};
+
+} // namespace Input
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <msp/strings/formatter.h>
+#include "../gbase/display.h"
+#include "keyboard.h"
+
+namespace Msp {
+namespace Input {
+
+Keyboard::Keyboard(Graphics::Window &w):
+ window(w)
+{
+ name="Keyboard";
+
+ buttons.resize(256, false);
+
+ window.signal_key_press.connect(sigc::mem_fun(this, &Keyboard::key_press));
+ window.signal_key_release.connect(sigc::mem_fun(this, &Keyboard::key_release));
+}
+
+std::string Keyboard::get_button_name(unsigned btn) const
+{
+#ifndef WIN32
+ KeySym ksym=XKeycodeToKeysym(window.get_display().get_display(), btn, 0);
+ return XKeysymToString(ksym);
+#else
+ char buf[128];
+ if(!GetKeyNameText(btn<<16, buf, sizeof(buf)))
+ return format("Key %d", btn);
+ return buf;
+#endif
+}
+
+void Keyboard::key_press(unsigned key, unsigned, unsigned)
+{
+ set_button_state(key, true, true);
+}
+
+void Keyboard::key_release(unsigned key, unsigned)
+{
+ set_button_state(key, false, true);
+}
+
+} // namespace Input
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GBASE_KEYBOARD_H_
+#define MSP_GBASE_KEYBOARD_H_
+
+#include "device.h"
+#include "../gbase/window.h"
+
+namespace Msp {
+namespace Input {
+
+class Keyboard: public Device
+{
+private:
+ Graphics::Window &window;
+
+public:
+ Keyboard(Graphics::Window &);
+
+ virtual std::string get_button_name(unsigned) const;
+private:
+ void key_press(unsigned, unsigned, unsigned);
+ void key_release(unsigned, unsigned);
+};
+
+} // namespace Input
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <msp/strings/formatter.h>
+#include "mouse.h"
+
+namespace Msp {
+namespace Input {
+
+Mouse::Mouse(Graphics::Window &w):
+ window(w),
+ axis_scale(0.01)
+{
+ name="Mouse";
+
+ buttons.resize(3);
+ axes.resize(2);
+
+ window.signal_button_press.connect(sigc::mem_fun(this, &Mouse::button_press));
+ window.signal_button_release.connect(sigc::mem_fun(this, &Mouse::button_release));
+ window.signal_pointer_motion.connect(sigc::mem_fun(this, &Mouse::pointer_motion));
+}
+
+std::string Mouse::get_button_name(unsigned btn) const
+{
+ switch(btn)
+ {
+ case 1:
+ return "Left";
+ case 2:
+ return "Middle";
+ case 3:
+ return "Right";
+ case 4:
+ return "Wheel Up";
+ case 5:
+ return "Wheel Down";
+ default:
+ return format("Button %d", btn);
+ }
+}
+
+void Mouse::button_press(int, int, unsigned btn, unsigned)
+{
+ set_button_state(btn, true, true);
+}
+
+void Mouse::button_release(int, int, unsigned btn, unsigned)
+{
+ set_button_state(btn, false, true);
+}
+
+void Mouse::pointer_motion(int x, int y)
+{
+ set_axis_value(0, x*axis_scale, true);
+ set_axis_value(1, y*axis_scale, true);
+}
+
+} // namespace Input
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GBASE_MOUSE_H_
+#define MSP_GBASE_MOUSE_H_
+
+#include "device.h"
+#include "../gbase/window.h"
+
+namespace Msp {
+namespace Input {
+
+class Mouse: public Device
+{
+private:
+ Graphics::Window &window;
+ float axis_scale;
+
+public:
+ Mouse(Graphics::Window &);
+ virtual std::string get_button_name(unsigned) const;
+private:
+ void button_press(int, int, unsigned, unsigned);
+ void button_release(int, int, unsigned, unsigned);
+ void pointer_motion(int, int);
+};
+
+} // namespace Input
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "smoothcontrol.h"
+
+namespace Msp {
+namespace Input {
+
+SmoothControl::SmoothControl():
+ value(0),
+ paired_ctrl(0)
+{ }
+
+SmoothControl::SmoothControl(const ControlSource &s):
+ Control(s),
+ value(0),
+ paired_ctrl(0)
+{ }
+
+SmoothControl::SmoothControl(Device &d, ControlSrcType t, unsigned i):
+ Control(d, t, i),
+ value(0),
+ paired_ctrl(0)
+{ }
+
+SmoothControl &SmoothControl::operator=(const SmoothControl &sc)
+{
+ Control::operator=(sc);
+
+ return *this;
+}
+
+SmoothControl::~SmoothControl()
+{
+ pair(0);
+}
+
+void SmoothControl::pair(SmoothControl *ctrl)
+{
+ if(ctrl==paired_ctrl)
+ return;
+
+ if(paired_ctrl)
+ {
+ SmoothControl *old_pair=paired_ctrl;
+ paired_ctrl=0;
+ old_pair->pair(0);
+ }
+
+ paired_ctrl=ctrl;
+
+ if(paired_ctrl)
+ paired_ctrl->pair(this);
+}
+
+void SmoothControl::on_press()
+{
+ on_motion(1, 1-value);
+}
+
+void SmoothControl::on_release()
+{
+ if(value>0)
+ on_motion(0, -value);
+}
+
+void SmoothControl::on_motion(float v, float)
+{
+ value=v;
+ signal_motion.emit(value);
+
+ if(paired_ctrl && paired_ctrl->get_value()!=-value)
+ paired_ctrl->on_motion(-value, -value-paired_ctrl->get_value());
+}
+
+} // namespace Input
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GBASE_SMOOTHCONTROL_H_
+#define MSP_GBASE_SMOOTHCONTROL_H_
+
+#include "control.h"
+
+namespace Msp {
+namespace Input {
+
+/**
+A control with a continuous range of values. A button is treated as either 1
+or 0. Axis values are mapped to absolute value.
+
+Two smooth controls can also be paired to each other. Motion on one control of
+the pair will cause negative motion on the other. This works best when the
+controls are bound to the opposite sides of the same joystick axis.
+*/
+class SmoothControl: public Control
+{
+public:
+ sigc::signal<void, float> signal_motion;
+
+private:
+ float value;
+ SmoothControl *paired_ctrl;
+
+public:
+ SmoothControl();
+ SmoothControl(const ControlSource &);
+ SmoothControl(Device &, ControlSrcType, unsigned);
+ SmoothControl &operator=(const SmoothControl &);
+ virtual ~SmoothControl();
+
+ void pair(SmoothControl *ctrl);
+ float get_value() const { return value; }
+
+private:
+ virtual void on_press();
+ virtual void on_release();
+ virtual void on_motion(float, float);
+};
+
+} // namespace Input
+} // namespace Msp
+
+#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <msp/strings/formatter.h>
-#include "inputdevice.h"
-
-namespace Msp {
-namespace Input {
-
-bool Device::get_button_state(unsigned btn) const
-{
- if(btn>buttons.size())
- return false;
-
- return buttons[btn];
-}
-
-float Device::get_axis_value(unsigned axis) const
-{
- if(axis>axes.size())
- return 0;
-
- return axes[axis];
-}
-
-std::string Device::get_button_name(unsigned btn) const
-{
- return format("Button %d", btn);
-}
-
-std::string Device::get_axis_name(unsigned axis) const
-{
- return format("Axis %d", axis);
-}
-
-void Device::set_button_state(unsigned btn, bool state, bool event)
-{
- if(btn>=buttons.size())
- buttons.resize(btn+1, false);
-
- if(state!=buttons[btn])
- {
- buttons[btn]=state;
-
- if(event)
- {
- if(state)
- signal_button_press.emit(btn);
- else
- signal_button_release.emit(btn);
- }
- }
-}
-
-void Device::set_axis_value(unsigned axis, float value, bool event)
-{
- if(axis>=axes.size())
- axes.resize(axis+1, 0);
-
- if(value!=axes[axis])
- {
- float old=axes[axis];
- axes[axis]=value;
-
- if(event)
- signal_axis_motion.emit(axis, value, value-old);
- }
-}
-
-} // namespace Input
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_GBASE_INPUTDEVICE_H_
-#define MSP_GBASE_INPUTDEVICE_H_
-
-#include <string>
-#include <vector>
-#include <sigc++/signal.h>
-
-namespace Msp {
-namespace Input {
-
-/**
-Base class for input devices. Input devices have two types of controls:
-buttons and axes. Buttons are either on or off. Axes have a floating-point
-value, with range depending on the device.
-*/
-class Device
-{
-public:
- sigc::signal<void, unsigned> signal_button_press;
- sigc::signal<void, unsigned> signal_button_release;
- sigc::signal<void, unsigned, float, float> signal_axis_motion;
-
-protected:
- std::string name;
- std::vector<char> buttons;
- std::vector<float> axes;
- float axis_threshold;
- float axis_dead_zone;
-
- Device() { }
-public:
- virtual ~Device() { }
- const std::string &get_name() const { return name; }
- bool get_button_state(unsigned) const;
- float get_axis_value(unsigned) const;
- float get_axis_threshold() const { return axis_threshold; }
-
- virtual std::string get_button_name(unsigned) const;
- virtual std::string get_axis_name(unsigned) const;
-protected:
- void set_button_state(unsigned, bool, bool);
- void set_axis_value(unsigned, float, bool);
-};
-
-} // namespace Input
-} // namespace Msp
-
-#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <sigc++/bind.h>
-#include <msp/core/except.h>
-#include "inputhub.h"
-
-namespace Msp {
-namespace Input {
-
-Hub::Hub()
-{
- name="Hub";
-}
-
-unsigned Hub::attach(Device &dev)
-{
- unsigned index=devices.size();
- devices.push_back(&dev);
- dev.signal_button_press.connect(sigc::bind(sigc::mem_fun(this, &Hub::button_press), index));
- dev.signal_button_release.connect(sigc::bind(sigc::mem_fun(this, &Hub::button_release), index));
- dev.signal_axis_motion.connect(sigc::bind(sigc::mem_fun(this, &Hub::axis_motion), index));
- return index;
-}
-
-std::string Hub::get_button_name(unsigned btn) const
-{
- unsigned dev_index=btn>>12;
- if(dev_index>devices.size())
- throw InvalidParameterValue("Button does not exist");
-
- const Device &dev=*devices[dev_index];
- return dev.get_name()+": "+dev.get_button_name(btn&0xFFF);
-}
-
-void Hub::button_press(unsigned btn, unsigned index)
-{
- set_button_state(index<<12 | btn&0xFFF, true, true);
-}
-
-void Hub::button_release(unsigned btn, unsigned index)
-{
- set_button_state(index<<12 | btn&0xFFF, false, true);
-}
-
-void Hub::axis_motion(unsigned axis, float value, float, unsigned index)
-{
- set_axis_value(index<<12 | axis&0xFFF, value, true);
-}
-
-} // namespace Input
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_GBASE_INPUTHUB_H_
-#define MSP_GBASE_INPUTHUB_H_
-
-#include "inputdevice.h"
-
-namespace Msp {
-namespace Input {
-
-/**
-The Hub device collects events from multiple input devices and presents an
-aggregate of them. Button and axis numbers are mapped to unique values.
-*/
-class Hub: public Device
-{
-protected:
- std::vector<Device *> devices;
-
-public:
- Hub();
-
- /**
- Attaches an input device to the hub.
-
- @param dev Device to attach
-
- @return Index of the device within the hub
- */
- unsigned attach(Device &dev);
-
- virtual std::string get_button_name(unsigned) const;
-protected:
- void button_press(unsigned, unsigned);
- void button_release(unsigned, unsigned);
- void axis_motion(unsigned, float, float, unsigned);
-};
-
-} // namespace Input
-} // namespace Msp
-
-#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <msp/strings/formatter.h>
-#include "display.h"
-#include "keyboard.h"
-
-namespace Msp {
-namespace Input {
-
-Keyboard::Keyboard(Graphics::Window &w):
- window(w)
-{
- name="Keyboard";
-
- buttons.resize(256, false);
-
- window.signal_key_press.connect(sigc::mem_fun(this, &Keyboard::key_press));
- window.signal_key_release.connect(sigc::mem_fun(this, &Keyboard::key_release));
-}
-
-std::string Keyboard::get_button_name(unsigned btn) const
-{
-#ifndef WIN32
- KeySym ksym=XKeycodeToKeysym(window.get_display().get_display(), btn, 0);
- return XKeysymToString(ksym);
-#else
- char buf[128];
- if(!GetKeyNameText(btn<<16, buf, sizeof(buf)))
- return format("Key %d", btn);
- return buf;
-#endif
-}
-
-void Keyboard::key_press(unsigned key, unsigned, unsigned)
-{
- set_button_state(key, true, true);
-}
-
-void Keyboard::key_release(unsigned key, unsigned)
-{
- set_button_state(key, false, true);
-}
-
-} // namespace Input
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_GBASE_KEYBOARD_H_
-#define MSP_GBASE_KEYBOARD_H_
-
-#include "inputdevice.h"
-#include "window.h"
-
-namespace Msp {
-namespace Input {
-
-class Keyboard: public Device
-{
-private:
- Graphics::Window &window;
-
-public:
- Keyboard(Graphics::Window &);
-
- virtual std::string get_button_name(unsigned) const;
-private:
- void key_press(unsigned, unsigned, unsigned);
- void key_release(unsigned, unsigned);
-};
-
-} // namespace Input
-} // namespace Msp
-
-#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <msp/strings/formatter.h>
-#include "mouse.h"
-
-namespace Msp {
-namespace Input {
-
-Mouse::Mouse(Graphics::Window &w):
- window(w),
- axis_scale(0.01)
-{
- name="Mouse";
-
- buttons.resize(3);
- axes.resize(2);
-
- window.signal_button_press.connect(sigc::mem_fun(this, &Mouse::button_press));
- window.signal_button_release.connect(sigc::mem_fun(this, &Mouse::button_release));
- window.signal_pointer_motion.connect(sigc::mem_fun(this, &Mouse::pointer_motion));
-}
-
-std::string Mouse::get_button_name(unsigned btn) const
-{
- switch(btn)
- {
- case 1:
- return "Left";
- case 2:
- return "Middle";
- case 3:
- return "Right";
- case 4:
- return "Wheel Up";
- case 5:
- return "Wheel Down";
- default:
- return format("Button %d", btn);
- }
-}
-
-void Mouse::button_press(int, int, unsigned btn, unsigned)
-{
- set_button_state(btn, true, true);
-}
-
-void Mouse::button_release(int, int, unsigned btn, unsigned)
-{
- set_button_state(btn, false, true);
-}
-
-void Mouse::pointer_motion(int x, int y)
-{
- set_axis_value(0, x*axis_scale, true);
- set_axis_value(1, y*axis_scale, true);
-}
-
-} // namespace Input
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_GBASE_MOUSE_H_
-#define MSP_GBASE_MOUSE_H_
-
-#include "inputdevice.h"
-#include "window.h"
-
-namespace Msp {
-namespace Input {
-
-class Mouse: public Device
-{
-private:
- Graphics::Window &window;
- float axis_scale;
-
-public:
- Mouse(Graphics::Window &);
- virtual std::string get_button_name(unsigned) const;
-private:
- void button_press(int, int, unsigned, unsigned);
- void button_release(int, int, unsigned, unsigned);
- void pointer_motion(int, int);
-};
-
-} // namespace Input
-} // namespace Msp
-
-#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include "smoothcontrol.h"
-
-namespace Msp {
-namespace Input {
-
-SmoothControl::SmoothControl():
- value(0),
- paired_ctrl(0)
-{ }
-
-SmoothControl::SmoothControl(const ControlSource &s):
- Control(s),
- value(0),
- paired_ctrl(0)
-{ }
-
-SmoothControl::SmoothControl(Device &d, ControlSrcType t, unsigned i):
- Control(d, t, i),
- value(0),
- paired_ctrl(0)
-{ }
-
-SmoothControl &SmoothControl::operator=(const SmoothControl &sc)
-{
- Control::operator=(sc);
-
- return *this;
-}
-
-SmoothControl::~SmoothControl()
-{
- pair(0);
-}
-
-void SmoothControl::pair(SmoothControl *ctrl)
-{
- if(ctrl==paired_ctrl)
- return;
-
- if(paired_ctrl)
- {
- SmoothControl *old_pair=paired_ctrl;
- paired_ctrl=0;
- old_pair->pair(0);
- }
-
- paired_ctrl=ctrl;
-
- if(paired_ctrl)
- paired_ctrl->pair(this);
-}
-
-void SmoothControl::on_press()
-{
- on_motion(1, 1-value);
-}
-
-void SmoothControl::on_release()
-{
- if(value>0)
- on_motion(0, -value);
-}
-
-void SmoothControl::on_motion(float v, float)
-{
- value=v;
- signal_motion.emit(value);
-
- if(paired_ctrl && paired_ctrl->get_value()!=-value)
- paired_ctrl->on_motion(-value, -value-paired_ctrl->get_value());
-}
-
-} // namespace Input
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_GBASE_SMOOTHCONTROL_H_
-#define MSP_GBASE_SMOOTHCONTROL_H_
-
-#include "control.h"
-
-namespace Msp {
-namespace Input {
-
-/**
-A control with a continuous range of values. A button is treated as either 1
-or 0. Axis values are mapped to absolute value.
-
-Two smooth controls can also be paired to each other. Motion on one control of
-the pair will cause negative motion on the other. This works best when the
-controls are bound to the opposite sides of the same joystick axis.
-*/
-class SmoothControl: public Control
-{
-public:
- sigc::signal<void, float> signal_motion;
-
-private:
- float value;
- SmoothControl *paired_ctrl;
-
-public:
- SmoothControl();
- SmoothControl(const ControlSource &);
- SmoothControl(Device &, ControlSrcType, unsigned);
- SmoothControl &operator=(const SmoothControl &);
- virtual ~SmoothControl();
-
- void pair(SmoothControl *ctrl);
- float get_value() const { return value; }
-
-private:
- virtual void on_press();
- virtual void on_release();
- virtual void on_motion(float, float);
-};
-
-} // namespace Input
-} // namespace Msp
-
-#endif
+++ /dev/null
-/* $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_
-
-#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
-
-#endif
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-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 {
-
-WindowOptions::WindowOptions():
- width(640),
- height(480),
- fullscreen(false),
- resizable(false)
-{ }
-
-
-Window::Window(Display &dpy, unsigned w, unsigned h, bool fs):
- display(dpy)
-{
- options.width=w;
- options.height=h;
- options.fullscreen=fs;
-
- init();
-}
-
-Window::Window(Display &dpy, const WindowOptions &opts):
- display(dpy),
- options(opts)
-{
- init();
-}
-
-Window::~Window()
-{
- if(window)
-#ifdef WIN32
- CloseWindow(window);
-#else
- XDestroyWindow(display.get_display(), window);
-#endif
-
- display.remove_window(this);
-
- if(options.fullscreen)
- display.restore_mode();
-}
-
-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];
- prop.encoding=XA_STRING;
- prop.format=8;
- prop.nitems=title.size();
- XSetWMName(display.get_display(), window, &prop);
- display.check_error();
-#endif
-}
-
-void Window::reconfigure(const WindowOptions &opts)
-{
- bool fullscreen_changed=(opts.fullscreen!=options.fullscreen);
-
- 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);
-
- if(fullscreen_changed)
- {
- hide();
- XSetWindowAttributes attr;
- attr.override_redirect=options.fullscreen;
- XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr);
- show();
- }
-
- if(options.fullscreen)
- 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=LoadCursor(0, IDC_ARROW);
- 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);
-
- XSetWindowAttributes attr;
- 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);
-
- XSetWMProtocols(dpy, window, &wm_delete_window, 1);
-
- if(options.fullscreen)
- {
- 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)
- {
- case ButtonPress:
- signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
- break;
- case ButtonRelease:
- signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
- break;
- case MotionNotify:
- signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y);
- break;
- case KeyPress:
- {
- char buf[16];
- XLookupString(const_cast<XKeyEvent *>(&ev.xkey), buf, sizeof(buf), 0, 0);
- // XXX Handle the result according to locale
- signal_key_press.emit(ev.xkey.keycode, ev.xkey.state, buf[0]);
- }
- break;
- case KeyRelease:
- signal_key_release.emit(ev.xkey.keycode, ev.xkey.state);
- break;
- case ConfigureNotify:
- options.width=ev.xconfigure.width;
- options.height=ev.xconfigure.height;
- signal_resize.emit(options.width, options.height);
- break;
- case ClientMessage:
- if(ev.xclient.data.l[0]==static_cast<long>(wm_delete_window))
- signal_close.emit();
- break;
- case EnterNotify:
- XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime);
- break;
- case MapNotify:
- if(options.fullscreen)
- XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
- break;
- default:;
- }
-}
-#endif
-
-#ifdef WIN32
-int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp)
-{
- switch(msg)
- {
- case WM_KEYDOWN:
- signal_key_press.emit((lp>>16)&0x1FF, 0, wp);
- break;
- case WM_KEYUP:
- signal_key_release.emit((lp>>16)&0x1FF, 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
+++ /dev/null
-/* $Id$
-
-This file is part of libmspgbase
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_GBASE_WINDOW_H_
-#define MSP_GBASE_WINDOW_H_
-
-#include <string>
-#include <sigc++/signal.h>
-#include "types.h"
-
-namespace Msp {
-namespace Graphics {
-
-class Display;
-
-struct WindowOptions
-{
- unsigned width;
- unsigned height;
- bool fullscreen;
- bool resizable;
-
- WindowOptions();
-};
-
-class Window
-{
-public:
- sigc::signal<void, int, int, unsigned, unsigned> signal_button_press;
- sigc::signal<void, int, int, unsigned, unsigned> signal_button_release;
- sigc::signal<void, int, int> signal_pointer_motion;
- sigc::signal<void, unsigned, unsigned, unsigned> signal_key_press;
- sigc::signal<void, unsigned, unsigned> signal_key_release;
- sigc::signal<void, unsigned, unsigned> signal_resize;
- sigc::signal<void> signal_close;
-
-protected:
- Display &display;
- WindowOptions options;
- WindowHandle window;
-#ifndef WIN32
- Atom wm_delete_window;
-#endif
-
-public:
- Window(Display &, unsigned w, unsigned h, bool fs=false);
- Window(Display &, const WindowOptions &);
- ~Window();
-
- 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; }
- WindowHandle get_handle() const { return window; }
-
- 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
-} // namespace Msp
-
-#endif