--- /dev/null
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <iostream>
+#include <X11/Xlib.h>
+#include <X11/extensions/xf86vmode.h>
+#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;
+
+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;
+}
+
+}
+
+namespace Msp {
+namespace Graphics {
+
+Display::Display(const string &disp_name)
+{
+ 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 nmodes;
+ XF86VidModeModeInfo **infos;
+ XF86VidModeGetAllModeLines(display, DefaultScreen(display), &nmodes, &infos);
+ for(int i=0; i<nmodes; ++i)
+ {
+ XF86VidModeModeInfo &info=*infos[i];
+
+ VideoMode mode;
+ mode.width=info.hdisplay;
+ mode.height=info.vdisplay;
+ mode.rate=info.dotclock/(info.htotal*info.vtotal);
+ modes.push_back(mode);
+ }
+}
+
+Display::~Display()
+{
+ XCloseDisplay(display);
+ display=0;
+}
+
+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)
+{
+ 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 && rate==mode.rate)
+ {
+ XF86VidModeSwitchToMode(display, screen, &info);
+ return;
+ }
+ }
+
+ throw InvalidParameterValue("Requested mode not supported");
+}
+
+void Display::tick()
+{
+ check_error();
+
+ while(1)
+ {
+ 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);
+ }
+ }
+}
+
+void Display::check_error()
+{
+ if(error_flag)
+ {
+ error_flag=false;
+ throw Exception(error_msg);
+ }
+}
+
+} // namespace Graphics
+} // namespace Msp