-#include <iostream>
#include <X11/Xlib.h>
+#include <X11/Xatom.h>
#ifdef WITH_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
return 0;
}
+#ifdef WITH_XRANDR
inline Msp::Graphics::VideoRotation rotation_from_sys(Rotation r)
{
switch(r)
}
}
-bool monitor_x_compare(const Msp::Graphics::Monitor &m1, const Msp::Graphics::Monitor &m2)
+inline bool monitor_x_compare(const Msp::Graphics::Monitor &m1, const Msp::Graphics::Monitor &m2)
{
- if(m1.desktop_mode && !m2.desktop_mode)
+ if(m1.desktop_settings.mode && !m2.desktop_settings.mode)
return true;
- return m1.x<m2.x;
+ return m1.desktop_settings.x<m2.desktop_settings.x;
}
+#endif
inline unsigned mode_width(const Msp::Graphics::VideoMode &m, Msp::Graphics::VideoRotation r)
{
Display::Display(const string &disp_name):
primary_monitor(0),
- priv(new Private)
+ priv(new Private),
+ focus_window(0)
{
if(disp_name.empty())
priv->display = XOpenDisplay(0);
XSetErrorHandler(x_error_handler);
+ priv->root_window = DefaultRootWindow(priv->display);
+
err_dialog = new ErrorDialog(this);
#ifdef WITH_XRANDR
XRRQueryVersion(priv->display, &major, &minor);
if(major>1 || (major==1 && minor>=2))
{
- WindowHandle root = DefaultRootWindow(priv->display);
- XRRScreenResources *res = XRRGetScreenResources(priv->display, root);
- RROutput primary = XRRGetOutputPrimary(priv->display, root);
+ XRRScreenResources *res = XRRGetScreenResources(priv->display, priv->root_window);
+ RROutput primary = XRRGetOutputPrimary(priv->display, priv->root_window);
+ Atom edid_prop = XInternAtom(priv->display, RR_PROPERTY_RANDR_EDID, true);
map<RRMode, XRRModeInfo *> modes_by_id;
for(int i=0; i<res->nmode; ++i)
monitors.push_back(Monitor());
Monitor &monitor = monitors.back();
monitor.index = monitors.size()-1;
+ monitor.name.assign(output->name, output->nameLen);
priv->monitors.push_back(res->outputs[i]);
+ if(edid_prop)
+ {
+ Atom prop_type;
+ int prop_format;
+ unsigned long length;
+ unsigned long overflow;
+ unsigned char *edid = 0;
+ XRRGetOutputProperty(priv->display, res->outputs[i], edid_prop, 0, 32, false, false, XA_INTEGER, &prop_type, &prop_format, &length, &overflow, &edid);
+ if(prop_type==XA_INTEGER && prop_format==8)
+ {
+ for(unsigned j=0; j<4; ++j)
+ {
+ unsigned offset = 54+j*18;
+ if(edid[offset]==0 && edid[offset+1]==0 && edid[offset+3]==0xFC)
+ {
+ unsigned k;
+ for(k=0; (k<13 && edid[offset+5+k]!=0x0A); ++k) ;
+ monitor.name.assign(reinterpret_cast<char *>(edid+offset+5), k);
+ }
+ }
+ }
+ XFree(edid);
+ }
+
if(crtc)
{
- monitor.desktop_rotation = rotation_from_sys(crtc->rotation);
- monitor.current_rotation = monitor.desktop_rotation;
- monitor.x = crtc->x;
- monitor.y = crtc->y;
+ monitor.desktop_settings.rotation = rotation_from_sys(crtc->rotation);
+ monitor.desktop_settings.x = crtc->x;
+ monitor.desktop_settings.y = crtc->y;
}
if(res->outputs[i]==primary)
VideoMode mode(info->width, info->height);
mode.index = modes.size();
mode.monitor = &monitor;
- mode.rate = info->dotClock/(info->hTotal*info->vTotal);
- if(find_mode(mode))
+ mode.rate = static_cast<float>(info->dotClock)/(info->hTotal*info->vTotal);
+ if(find_mode(mode, 0.01f))
continue;
modes.push_back(mode);
monitor.video_modes.push_back(&modes.back());
if(crtc && info->id==crtc->mode)
- {
- monitor.desktop_mode = &modes.back();
- monitor.current_mode = monitor.desktop_mode;
- }
+ monitor.desktop_settings.mode = &modes.back();
}
+ monitor.current_settings = monitor.desktop_settings;
+
XRRFreeOutputInfo(output);
if(crtc)
XRRFreeCrtcInfo(crtc);
monitors.sort(monitor_x_compare);
Monitor *prev_enabled = 0;
for(list<Monitor>::iterator i=monitors.begin(); i!=monitors.end(); ++i)
- if(i->desktop_mode)
+ if(i->desktop_settings.mode)
{
i->next_left = prev_enabled;
if(prev_enabled)
prev_enabled = &*i;
}
- if(!primary_monitor || !primary_monitor->desktop_mode)
+ if(!primary_monitor || !primary_monitor->desktop_settings.mode)
{
// XRandR didn't give a sensible primary monitor. Try to guess one.
unsigned largest = 0;
for(list<Monitor>::iterator i=monitors.begin(); i!=monitors.end(); ++i)
- if(i->desktop_mode)
+ if(const VideoMode *desktop_mode = i->desktop_settings.mode)
{
- unsigned size = i->desktop_mode->width*i->desktop_mode->height;
+ unsigned size = desktop_mode->width*desktop_mode->height;
if(size>largest)
{
largest = size;
VideoRotation requested_rotation = requested_mode.rotation;
if(requested_rotation==ROTATE_ANY)
- requested_rotation = mode->monitor->desktop_rotation;
+ requested_rotation = mode->monitor->desktop_settings.rotation;
- WindowHandle root = DefaultRootWindow(priv->display);
- XRRScreenResources *res = XRRGetScreenResources(priv->display, root);
+ XRRScreenResources *res = XRRGetScreenResources(priv->display, priv->root_window);
RROutput output = priv->monitors[mode->monitor->index];
XRROutputInfo *output_info = XRRGetOutputInfo(priv->display, res, output);
}
}
- int x = 0;
- int y = 0;
+ /* Due to the semantics of find_mode, the mode's monitor pointer must point
+ to one of the elements of the monitors list, which is non-const here. */
+ Monitor *monitor = const_cast<Monitor *>(mode->monitor);
if(exclusive)
{
+ monitor->current_settings.mode = mode;
+ monitor->current_settings.rotation = requested_rotation;
+ monitor->current_settings.x = 0;
+ monitor->current_settings.y = 0;
+
// Disable other outputs for exclusive mode
for(list<Monitor>::iterator i=monitors.begin(); i!=monitors.end(); ++i)
if(&*i!=mode->monitor)
XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, 0, 0, 0, RR_Rotate_0, 0, 0);
XRRFreeOutputInfo(o);
- i->current_mode = 0;
- i->current_rotation = ROTATE_NORMAL;
- i->x = 0;
- i->y = 0;
+ i->current_settings.mode = 0;
+ i->current_settings.rotation = ROTATE_NORMAL;
+ i->current_settings.x = 0;
+ i->current_settings.y = 0;
}
}
else
{
- const Monitor *left = mode->monitor->next_left;
- while(left && !left->current_mode)
- left = left->next_left;
-
- if(left)
- {
- x = left->x+mode_width(*left->current_mode, left->current_rotation);
- y = left->y;
- }
+ monitor->current_settings.x = monitor->desktop_settings.x;
+ monitor->current_settings.y = monitor->desktop_settings.y;
}
- XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, x, y, priv->modes[mode->index], rotation_to_sys(requested_rotation), &output, 1);
-
- list<Monitor>::iterator i;
- for(i=monitors.begin(); i!=monitors.end(); ++i)
- if(&*i==mode->monitor)
- {
- i->current_mode = mode;
- i->current_rotation = requested_rotation;
- i->x = x;
- i->y = y;
-
- x += mode_width(*mode, requested_rotation);
- ++i;
- break;
- }
-
- for(; i!=monitors.end(); ++i)
- if(i->current_mode)
- {
- XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i->index]);
- XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, x, y, priv->modes[i->current_mode->index], rotation_to_sys(i->current_rotation), &priv->monitors[i->index], 1);
- XRRFreeOutputInfo(o);
-
- i->x = x;
- i->y = y;
-
- x += mode_width(*i->current_mode, i->current_rotation);
- }
+ RRMode mode_id = priv->modes[mode->index];
+ int x = monitor->current_settings.x;
+ int y = monitor->current_settings.y;
+ Rotation sys_rot = rotation_to_sys(requested_rotation);
+ XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, x, y, mode_id, sys_rot, &output, 1);
XRRFreeOutputInfo(output_info);
XRRFreeCrtcInfo(crtc_info);