X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgraphics%2Fx11%2Fdisplay.cpp;h=c23f46d26a21417cb14483c562401f3bbe7d9575;hb=e15959a69551c2027029470e65a17ea5a305545b;hp=2f276a32d5246666aeae56b722379fd46dff2d34;hpb=9bc0825e93b1385a4aaf9f90d666a1ac409ffb17;p=libs%2Fgui.git diff --git a/source/graphics/x11/display.cpp b/source/graphics/x11/display.cpp index 2f276a3..c23f46d 100644 --- a/source/graphics/x11/display.cpp +++ b/source/graphics/x11/display.cpp @@ -1,4 +1,3 @@ -#include #include #ifdef WITH_XRANDR #include @@ -38,6 +37,45 @@ int x_error_handler(Display *display, XErrorEvent *event) return 0; } +#ifdef WITH_XRANDR +inline Msp::Graphics::VideoRotation rotation_from_sys(Rotation r) +{ + switch(r) + { + case RR_Rotate_90: return Msp::Graphics::ROTATE_RIGHT; + case RR_Rotate_180: return Msp::Graphics::ROTATE_INVERTED; + case RR_Rotate_270: return Msp::Graphics::ROTATE_LEFT; + default: return Msp::Graphics::ROTATE_NORMAL; + } +} + +inline Rotation rotation_to_sys(Msp::Graphics::VideoRotation r) +{ + switch(r) + { + case Msp::Graphics::ROTATE_RIGHT: return RR_Rotate_90; + case Msp::Graphics::ROTATE_INVERTED: return RR_Rotate_180; + case Msp::Graphics::ROTATE_LEFT: return RR_Rotate_270; + default: return RR_Rotate_0; + } +} + +inline bool monitor_x_compare(const Msp::Graphics::Monitor &m1, const Msp::Graphics::Monitor &m2) +{ + if(m1.desktop_mode && !m2.desktop_mode) + return true; + return m1.xdisplay = XOpenDisplay(0); @@ -57,6 +96,10 @@ Display::Display(const string &disp_name): XSetErrorHandler(x_error_handler); + priv->root_window = DefaultRootWindow(priv->display); + + err_dialog = new ErrorDialog(this); + #ifdef WITH_XRANDR int event_base; int error_base; @@ -66,9 +109,8 @@ Display::Display(const string &disp_name): 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); map modes_by_id; for(int i=0; inmode; ++i) @@ -82,8 +124,17 @@ Display::Display(const string &disp_name): 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(crtc) + { + monitor.desktop_rotation = rotation_from_sys(crtc->rotation); + monitor.current_rotation = monitor.desktop_rotation; + monitor.x = crtc->x; + monitor.y = crtc->y; + } + if(res->outputs[i]==primary) primary_monitor = &monitor; @@ -98,8 +149,8 @@ Display::Display(const string &disp_name): VideoMode mode(info->width, info->height); mode.index = modes.size(); mode.monitor = &monitor; - mode.rate = info->dotClock/(info->hTotal*info->vTotal); - if(find_matching_mode(mode)) + mode.rate = static_cast(info->dotClock)/(info->hTotal*info->vTotal); + if(find_mode(mode, 0.01f)) continue; modes.push_back(mode); @@ -107,7 +158,10 @@ Display::Display(const string &disp_name): monitor.video_modes.push_back(&modes.back()); if(crtc && info->id==crtc->mode) + { monitor.desktop_mode = &modes.back(); + monitor.current_mode = monitor.desktop_mode; + } } XRRFreeOutputInfo(output); @@ -116,6 +170,33 @@ 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) + { + i->next_left = prev_enabled; + if(prev_enabled) + prev_enabled->next_right = &*i; + prev_enabled = &*i; + } + + if(!primary_monitor || !primary_monitor->desktop_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) + { + unsigned size = i->desktop_mode->width*i->desktop_mode->height; + if(size>largest) + { + largest = size; + primary_monitor = &*i; + } + } + } } } #endif @@ -125,17 +206,21 @@ Display::~Display() { XCloseDisplay(priv->display); delete priv; + delete err_dialog; } void Display::set_mode(const VideoMode &requested_mode, bool exclusive) { #ifdef WITH_XRANDR - const VideoMode *mode = find_matching_mode(requested_mode); + const VideoMode *mode = find_mode(requested_mode); if(!mode) throw unsupported_video_mode(requested_mode); - WindowHandle root = DefaultRootWindow(priv->display); - XRRScreenResources *res = XRRGetScreenResources(priv->display, root); + VideoRotation requested_rotation = requested_mode.rotation; + if(requested_rotation==ROTATE_ANY) + requested_rotation = mode->monitor->desktop_rotation; + + XRRScreenResources *res = XRRGetScreenResources(priv->display, priv->root_window); RROutput output = priv->monitors[mode->monitor->index]; XRROutputInfo *output_info = XRRGetOutputInfo(priv->display, res, output); @@ -164,20 +249,84 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) } } + int x = 0; + int y = 0; + if(exclusive) { // Disable other outputs for exclusive mode - for(unsigned i=0; imonitors.size(); ++i) - if(i!=mode->monitor->index) + for(list::iterator i=monitors.begin(); i!=monitors.end(); ++i) + if(&*i!=mode->monitor) { - XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i]); + XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i->index]); if(o->crtc) 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; } } + 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; + } + } - XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, 0, 0, priv->modes[mode->index], RR_Rotate_0, &output, 1); + 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); + } XRRFreeOutputInfo(output_info); XRRFreeCrtcInfo(crtc_info);