X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgraphics%2Fx11%2Fdisplay.cpp;h=60c2182b9f5f09093f4fb89317b9174d1a5cbb1e;hb=27356249e3607c78f5da9823c88703a6f4f7bed1;hp=634e91096f38cf7ce78a4c47e177e3bab8c0c7e8;hpb=5089eb26984313f3a28ca7d941de97c509a45281;p=libs%2Fgui.git diff --git a/source/graphics/x11/display.cpp b/source/graphics/x11/display.cpp index 634e910..60c2182 100644 --- a/source/graphics/x11/display.cpp +++ b/source/graphics/x11/display.cpp @@ -1,19 +1,21 @@ +#include "display.h" +#include "display_private.h" #include +#include #ifdef WITH_XRANDR #include #endif +#include #include #include #include -#include "display.h" -#include "display_private.h" using namespace std; namespace { bool error_flag = false; -std::string error_msg; +string error_msg; int x_error_handler(Display *display, XErrorEvent *event) { @@ -62,9 +64,11 @@ inline Rotation rotation_to_sys(Msp::Graphics::VideoRotation r) 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.xdisplay = XOpenDisplay(0); + priv->display = XOpenDisplay(nullptr); else priv->display = XOpenDisplay(disp_name.c_str()); if(!priv->display) @@ -110,15 +113,19 @@ Display::Display(const string &disp_name): { 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 modes_by_id; for(int i=0; inmode; ++i) modes_by_id[res->modes[i].id] = &res->modes[i]; + int primary_index = -1; + vector mode_monitor_indices; + vector desktop_mode_indices; for(int i=0; inoutput; ++i) { XRROutputInfo *output = XRRGetOutputInfo(priv->display, res, res->outputs[i]); - XRRCrtcInfo *crtc = (output->crtc ? XRRGetCrtcInfo(priv->display, res, output->crtc) : 0); + XRRCrtcInfo *crtc = (output->crtc ? XRRGetCrtcInfo(priv->display, res, output->crtc) : nullptr); monitors.push_back(Monitor()); Monitor &monitor = monitors.back(); @@ -126,42 +133,68 @@ Display::Display(const string &disp_name): 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 = nullptr; + 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(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) - primary_monitor = &monitor; + primary_index = monitor.index; + unsigned first_mode = modes.size(); + int desktop_mode_index = -1; for(int j=0; jnmode; ++j) { - map::iterator k = modes_by_id.find(output->modes[j]); + auto k = modes_by_id.find(output->modes[j]); if(k==modes_by_id.end()) continue; XRRModeInfo *info = k->second; + float rate = static_cast(info->dotClock)/(info->hTotal*info->vTotal); + + if(any_of(modes.begin()+first_mode, modes.end(), [&info, rate](const VideoMode &m){ + return (m.width==info->width && m.height==info->height && abs(m.rate-rate)<0.01f); + })) + continue; VideoMode mode(info->width, info->height); mode.index = modes.size(); - mode.monitor = &monitor; - mode.rate = static_cast(info->dotClock)/(info->hTotal*info->vTotal); - if(find_mode(mode, 0.01f)) - continue; + mode.rate = rate; modes.push_back(mode); priv->modes.push_back(info->id); - monitor.video_modes.push_back(&modes.back()); + mode_monitor_indices.push_back(monitor.index); if(crtc && info->id==crtc->mode) - { - monitor.desktop_mode = &modes.back(); - monitor.current_mode = monitor.desktop_mode; - } + desktop_mode_index = mode.index; } + desktop_mode_indices.push_back(desktop_mode_index); XRRFreeOutputInfo(output); if(crtc) @@ -170,29 +203,48 @@ Display::Display(const string &disp_name): XRRFreeScreenResources(res); - monitors.sort(monitor_x_compare); - Monitor *prev_enabled = 0; - for(list::iterator i=monitors.begin(); i!=monitors.end(); ++i) - if(i->desktop_mode) + for(unsigned i=0; i=0) + monitors[i].desktop_settings.mode = &modes[j]; + monitors[i].current_settings = monitors[i].desktop_settings; + } + + sort(monitors, monitor_x_compare); + + for(unsigned i=0; ivideo_modes.push_back(&modes[i]); + } + + Monitor *prev_enabled = nullptr; + for(Monitor &m: monitors) + if(m.desktop_settings.mode) { - i->next_left = prev_enabled; + m.next_left = prev_enabled; if(prev_enabled) - prev_enabled->next_right = &*i; - prev_enabled = &*i; + prev_enabled->next_right = &m; + prev_enabled = &m; } - if(!primary_monitor || !primary_monitor->desktop_mode) + if(primary_index>=0) + primary_monitor = &*find_member(monitors, static_cast(primary_index), &Monitor::index); + + 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::iterator i=monitors.begin(); i!=monitors.end(); ++i) - if(i->desktop_mode) + for(Monitor &m: monitors) + if(const VideoMode *desktop_mode = m.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; - primary_monitor = &*i; + primary_monitor = &m; } } } @@ -217,7 +269,7 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) VideoRotation requested_rotation = requested_mode.rotation; if(requested_rotation==ROTATE_ANY) - requested_rotation = mode->monitor->desktop_rotation; + requested_rotation = mode->monitor->desktop_settings.rotation; XRRScreenResources *res = XRRGetScreenResources(priv->display, priv->root_window); RROutput output = priv->monitors[mode->monitor->index]; @@ -225,7 +277,7 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) // Check if the output already has a CRTC and find a free one if it doesn't RRCrtc crtc = output_info->crtc; - XRRCrtcInfo *crtc_info = 0; + XRRCrtcInfo *crtc_info = nullptr; if(crtc) crtc_info = XRRGetCrtcInfo(priv->display, res, crtc); else @@ -248,84 +300,43 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) } } - 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(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::iterator i=monitors.begin(); i!=monitors.end(); ++i) - if(&*i!=mode->monitor) + for(Monitor &m: monitors) + if(&m!=mode->monitor) { - XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i->index]); + XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[m.index]); if(o->crtc) - XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, 0, 0, 0, RR_Rotate_0, 0, 0); + XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, 0, 0, 0, RR_Rotate_0, nullptr, 0); XRRFreeOutputInfo(o); - i->current_mode = 0; - i->current_rotation = ROTATE_NORMAL; - i->x = 0; - i->y = 0; + m.current_settings.mode = nullptr; + m.current_settings.rotation = ROTATE_NORMAL; + m.current_settings.x = 0; + m.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::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); - - XRRPanning panning; - panning.timestamp = CurrentTime; - panning.left = x; - panning.top = y; - panning.width = i->current_mode->width; - panning.height = i->current_mode->height; - panning.track_left = panning.left; - panning.track_top = panning.top; - panning.track_width = panning.width; - panning.track_height = panning.height; - panning.border_left = 0; - panning.border_top = 0; - panning.border_right = 0; - panning.border_bottom = 0; - XRRSetPanning(priv->display, res, o->crtc, &panning); - - 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); @@ -350,7 +361,7 @@ bool Display::process_events() check_error(); - map::iterator j = priv->windows.find(event.xevent.xany.window); + auto j = priv->windows.find(event.xevent.xany.window); if(j!=priv->windows.end()) { /* Filter keyboard autorepeat. If this packet is a KeyRelease and