3 This file is part of libmspgbase
4 Copyright © 2007-2008 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
11 #ifdef WITH_XF86VIDMODE
12 #include <X11/extensions/xf86vmode.h>
15 #include <msp/core/except.h>
16 #include <msp/strings/formatter.h>
17 #include <msp/strings/lexicalcast.h>
20 #include "display_priv.h"
26 bool error_flag=false;
27 std::string error_msg;
30 int x_error_handler(Display *display, XErrorEvent *event)
33 XGetErrorText(display, event->error_code, err, sizeof(err));
35 string request_code=Msp::lexical_cast(static_cast<int>(event->request_code));
37 XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req));
39 string msg=Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid);
41 cerr<<"Discarding error: "<<msg<<'\n';
58 Display::Display(const string &disp_name):
64 for(unsigned i=0;; ++i)
67 if(!EnumDisplaySettings(0, i, &info))
70 VideoMode mode(info.dmPelsWidth, info.dmPelsHeight);
71 mode.rate=info.dmDisplayFrequency;
72 modes.push_back(mode);
76 if(EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &info))
78 orig_mode=VideoMode(info.dmPelsWidth, info.dmPelsHeight);
79 orig_mode.rate=info.dmDisplayFrequency;
83 priv->display=XOpenDisplay(0);
85 priv->display=XOpenDisplay(disp_name.c_str());
87 throw Exception("Couldn't open X display");
89 XSetErrorHandler(x_error_handler);
91 #ifdef WITH_XF86VIDMODE
92 int screen=DefaultScreen(priv->display);
95 XF86VidModeModeInfo **infos;
96 XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos);
97 for(int i=0; i<nmodes; ++i)
99 XF86VidModeModeInfo &info=*infos[i];
101 VideoMode mode(info.hdisplay, info.vdisplay);
102 if(info.htotal && info.vtotal)
103 mode.rate=info.dotclock/(info.htotal*info.vtotal);
104 modes.push_back(mode);
109 XF86VidModeModeLine modeline;
111 XF86VidModeGetModeLine(priv->display, screen, &dotclock, &modeline);
112 orig_mode=VideoMode(modeline.hdisplay, modeline.vdisplay);
113 if(modeline.htotal && modeline.vtotal)
114 orig_mode.rate=dotclock/(modeline.htotal*modeline.vtotal);
122 XCloseDisplay(priv->display);
127 void Display::add_window(Window &wnd)
129 priv->windows[wnd.get_private().window]=&wnd;
132 void Display::remove_window(Window &wnd)
134 priv->windows.erase(wnd.get_private().window);
137 void Display::set_mode(const VideoMode &mode)
141 info.dmSize=sizeof(DEVMODE);
142 info.dmFields=DM_PELSWIDTH|DM_PELSHEIGHT;
143 info.dmPelsWidth=mode.width;
144 info.dmPelsHeight=mode.height;
147 info.dmFields|=DM_DISPLAYFREQUENCY;
148 info.dmDisplayFrequency=mode.rate;
151 ChangeDisplaySettings(&info, CDS_FULLSCREEN);
152 #elif defined(WITH_XF86VIDMODE)
153 int screen=DefaultScreen(priv->display);
156 XF86VidModeModeInfo **infos;
157 XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos);
158 for(int i=0; i<nmodes; ++i)
160 XF86VidModeModeInfo &info=*infos[i];
163 if(info.htotal && info.vtotal)
164 rate=info.dotclock/(info.htotal*info.vtotal);
165 if(info.hdisplay==mode.width && info.vdisplay==mode.height && (mode.rate==0 || rate==mode.rate))
167 XF86VidModeSwitchToMode(priv->display, screen, &info);
168 XF86VidModeSetViewPort(priv->display, screen, 0, 0);
173 throw InvalidParameterValue("Requested mode not supported");
176 throw Exception("Video mode switching not supported");
188 if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
189 DispatchMessage(&msg);
193 int pending=XPending(priv->display);
200 XNextEvent(priv->display, &event.xevent);
204 map<WindowHandle, Window *>::iterator j=priv->windows.find(event.xevent.xany.window);
205 if(j!=priv->windows.end())
207 /* Filter keyboard autorepeat. If this packet is a KeyRelease and
208 the next one is a KeyPress with the exact same parameters, they
209 indicate autorepeat and must be dropped. */
210 if(event.xevent.type==KeyRelease && !j->second->get_keyboard_autorepeat() && pending>0)
212 XKeyEvent &kev=event.xevent.xkey;
214 XPeekEvent(priv->display, &ev2);
215 if(ev2.type==KeyPress)
217 XKeyEvent &kev2=ev2.xkey;
218 if(kev2.window==kev.window && kev2.time==kev.time && kev2.keycode==kev.keycode)
220 XNextEvent(priv->display, &ev2);
227 j->second->event(event);
234 void Display::check_error()
239 throw Exception(error_msg);
243 } // namespace Graphics