4 #include <X11/extensions/Xrandr.h>
6 #include <msp/io/print.h>
7 #include <msp/strings/format.h>
8 #include <msp/strings/lexicalcast.h>
10 #include "display_private.h"
16 bool error_flag = false;
17 std::string error_msg;
19 int x_error_handler(Display *display, XErrorEvent *event)
22 XGetErrorText(display, event->error_code, err, sizeof(err));
24 string request_code = Msp::lexical_cast<string, int>(event->request_code);
26 XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req));
28 string msg = Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid);
30 Msp::IO::print(Msp::IO::cerr, "Discarding error: %s\n", msg);
33 Msp::IO::print(Msp::IO::cerr, "%s\n", msg);
47 Display::Display(const string &disp_name):
52 priv->display = XOpenDisplay(0);
54 priv->display = XOpenDisplay(disp_name.c_str());
56 throw runtime_error("XOpenDisplay");
58 XSetErrorHandler(x_error_handler);
63 if(XRRQueryExtension(priv->display, &event_base, &error_base))
66 XRRQueryVersion(priv->display, &major, &minor);
67 if(major>1 || (major==1 && minor>=2))
69 WindowHandle root = DefaultRootWindow(priv->display);
70 XRRScreenResources *res = XRRGetScreenResources(priv->display, root);
71 RROutput primary = XRRGetOutputPrimary(priv->display, root);
73 map<RRMode, XRRModeInfo *> modes_by_id;
74 for(int i=0; i<res->nmode; ++i)
75 modes_by_id[res->modes[i].id] = &res->modes[i];
77 for(int i=0; i<res->noutput; ++i)
79 XRROutputInfo *output = XRRGetOutputInfo(priv->display, res, res->outputs[i]);
80 XRRCrtcInfo *crtc = (output->crtc ? XRRGetCrtcInfo(priv->display, res, output->crtc) : 0);
82 monitors.push_back(Monitor());
83 Monitor &monitor = monitors.back();
84 monitor.index = monitors.size()-1;
85 priv->monitors.push_back(res->outputs[i]);
87 if(res->outputs[i]==primary)
88 primary_monitor = &monitor;
90 for(int j=0; j<output->nmode; ++j)
92 map<RRMode, XRRModeInfo *>::iterator k = modes_by_id.find(output->modes[j]);
93 if(k==modes_by_id.end())
96 XRRModeInfo *info = k->second;
98 VideoMode mode(info->width, info->height);
99 mode.index = modes.size();
100 mode.monitor = &monitor;
101 mode.rate = info->dotClock/(info->hTotal*info->vTotal);
102 if(find_matching_mode(mode))
105 modes.push_back(mode);
106 priv->modes.push_back(info->id);
107 monitor.video_modes.push_back(&modes.back());
109 if(crtc && info->id==crtc->mode)
110 monitor.desktop_mode = &modes.back();
113 XRRFreeOutputInfo(output);
115 XRRFreeCrtcInfo(crtc);
118 XRRFreeScreenResources(res);
126 XCloseDisplay(priv->display);
130 void Display::set_mode(const VideoMode &requested_mode, bool exclusive)
133 const VideoMode *mode = find_matching_mode(requested_mode);
135 throw unsupported_video_mode(requested_mode);
137 WindowHandle root = DefaultRootWindow(priv->display);
138 XRRScreenResources *res = XRRGetScreenResources(priv->display, root);
139 RROutput output = priv->monitors[mode->monitor->index];
140 XRROutputInfo *output_info = XRRGetOutputInfo(priv->display, res, output);
142 // Check if the output already has a CRTC and find a free one if it doesn't
143 RRCrtc crtc = output_info->crtc;
144 XRRCrtcInfo *crtc_info = 0;
146 crtc_info = XRRGetCrtcInfo(priv->display, res, crtc);
149 for(int i=0; i<res->ncrtc; ++i)
151 crtc_info = XRRGetCrtcInfo(priv->display, res, res->crtcs[i]);
152 if(!crtc_info->noutput)
154 crtc = res->crtcs[i];
157 XRRFreeCrtcInfo(crtc_info);
162 XRRFreeOutputInfo(output_info);
163 throw unsupported_video_mode(requested_mode);
169 // Disable other outputs for exclusive mode
170 for(unsigned i=0; i<priv->monitors.size(); ++i)
171 if(i!=mode->monitor->index)
173 XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i]);
175 XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, 0, 0, 0, RR_Rotate_0, 0, 0);
176 XRRFreeOutputInfo(o);
180 XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, 0, 0, priv->modes[mode->index], RR_Rotate_0, &output, 1);
182 XRRFreeOutputInfo(output_info);
183 XRRFreeCrtcInfo(crtc_info);
184 XRRFreeScreenResources(res);
186 (void)requested_mode;
188 throw runtime_error("no xrandr support");
192 bool Display::process_events()
194 int pending = XPending(priv->display);
201 XNextEvent(priv->display, &event.xevent);
205 map<WindowHandle, Window *>::iterator j = priv->windows.find(event.xevent.xany.window);
206 if(j!=priv->windows.end())
208 /* Filter keyboard autorepeat. If this packet is a KeyRelease and
209 the next one is a KeyPress with the exact same parameters, they
210 indicate autorepeat and must be dropped. */
211 if(event.xevent.type==KeyRelease && !j->second->get_keyboard_autorepeat() && pending>0)
213 XKeyEvent &kev = event.xevent.xkey;
215 XPeekEvent(priv->display, &ev2);
216 if(ev2.type==KeyPress)
218 XKeyEvent &kev2 = ev2.xkey;
219 if(kev2.window==kev.window && kev2.time==kev.time && kev2.keycode==kev.keycode)
221 XNextEvent(priv->display, &ev2);
228 j->second->event(event);
235 void Display::check_error()
240 throw runtime_error(error_msg);
245 } // namespace Graphics