X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgraphics%2Fx11%2Fdisplay.cpp;h=c2a4eaf26371d1a190f8051f9e198590192d95a4;hb=b1a6dffafa27d689389b512668fd5c34757dbd1d;hp=0e89794f458205fc74a82dde078c027bf1aaef4a;hpb=1aca77b93853ee127ac3bbf6886f7f04920542ef;p=libs%2Fgui.git diff --git a/source/graphics/x11/display.cpp b/source/graphics/x11/display.cpp index 0e89794..c2a4eaf 100644 --- a/source/graphics/x11/display.cpp +++ b/source/graphics/x11/display.cpp @@ -1,8 +1,9 @@ #include #include -#ifdef WITH_XF86VIDMODE -#include +#ifdef WITH_XRANDR +#include #endif +#include #include #include #include "display.h" @@ -26,10 +27,10 @@ int x_error_handler(Display *display, XErrorEvent *event) string msg = Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid); if(error_flag) - cerr<<"Discarding error: "<display); + err_dialog = new ErrorDialog(this); - int nmodes; - XF86VidModeModeInfo **infos; - XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos); - for(int i=0; idisplay, &event_base, &error_base)) { - XF86VidModeModeInfo &info = *infos[i]; - - VideoMode mode(info.hdisplay, info.vdisplay); - if(info.htotal && info.vtotal) - mode.rate = info.dotclock/(info.htotal*info.vtotal); - modes.push_back(mode); - } + int major, minor; + 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); - XFree(infos); + map modes_by_id; + for(int i=0; inmode; ++i) + modes_by_id[res->modes[i].id] = &res->modes[i]; + + 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); - XF86VidModeModeLine modeline; - int dotclock; - XF86VidModeGetModeLine(priv->display, screen, &dotclock, &modeline); - orig_mode = VideoMode(modeline.hdisplay, modeline.vdisplay); - if(modeline.htotal && modeline.vtotal) - orig_mode.rate = dotclock/(modeline.htotal*modeline.vtotal); + monitors.push_back(Monitor()); + Monitor &monitor = monitors.back(); + monitor.index = monitors.size()-1; + 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; + + for(int j=0; jnmode; ++j) + { + map::iterator k = modes_by_id.find(output->modes[j]); + if(k==modes_by_id.end()) + continue; + + XRRModeInfo *info = k->second; + + 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)) + continue; + + modes.push_back(mode); + priv->modes.push_back(info->id); + 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); + if(crtc) + XRRFreeCrtcInfo(crtc); + } + + 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 } @@ -86,35 +202,136 @@ Display::~Display() { XCloseDisplay(priv->display); delete priv; + delete err_dialog; } -void Display::set_mode(const VideoMode &mode) +void Display::set_mode(const VideoMode &requested_mode, bool exclusive) { -#ifdef WITH_XF86VIDMODE - int screen = DefaultScreen(priv->display); +#ifdef WITH_XRANDR + const VideoMode *mode = find_mode(requested_mode); + if(!mode) + throw unsupported_video_mode(requested_mode); + + VideoRotation requested_rotation = requested_mode.rotation; + if(requested_rotation==ROTATE_ANY) + requested_rotation = mode->monitor->desktop_rotation; + + WindowHandle root = DefaultRootWindow(priv->display); + XRRScreenResources *res = XRRGetScreenResources(priv->display, root); + RROutput output = priv->monitors[mode->monitor->index]; + XRROutputInfo *output_info = XRRGetOutputInfo(priv->display, res, output); + + // 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; + if(crtc) + crtc_info = XRRGetCrtcInfo(priv->display, res, crtc); + else + { + for(int i=0; incrtc; ++i) + { + crtc_info = XRRGetCrtcInfo(priv->display, res, res->crtcs[i]); + if(!crtc_info->noutput) + { + crtc = res->crtcs[i]; + break; + } + XRRFreeCrtcInfo(crtc_info); + } + + if(!crtc) + { + XRRFreeOutputInfo(output_info); + throw unsupported_video_mode(requested_mode); + } + } + + int x = 0; + int y = 0; + + if(exclusive) + { + // Disable other outputs for exclusive mode + for(list::iterator i=monitors.begin(); i!=monitors.end(); ++i) + if(&*i!=mode->monitor) + { + 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); - int nmodes; - XF86VidModeModeInfo **infos; - XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos); - for(int i=0; icurrent_mode = 0; + i->current_rotation = ROTATE_NORMAL; + i->x = 0; + i->y = 0; + } + } + else { - XF86VidModeModeInfo &info = *infos[i]; + const Monitor *left = mode->monitor->next_left; + while(left && !left->current_mode) + left = left->next_left; - unsigned rate = 0; - if(info.htotal && info.vtotal) - rate = info.dotclock/(info.htotal*info.vtotal); - if(info.hdisplay==mode.width && info.vdisplay==mode.height && (mode.rate==0 || rate==mode.rate)) + if(left) { - XF86VidModeSwitchToMode(priv->display, screen, &info); - XF86VidModeSetViewPort(priv->display, screen, 0, 0); - return; + x = left->x+mode_width(*left->current_mode, left->current_rotation); + y = left->y; } } - throw unsupported_video_mode(mode); + 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); + XRRFreeScreenResources(res); #else - (void)mode; - throw runtime_error("no xf86vidmode support"); + (void)requested_mode; + (void)exclusive; + throw runtime_error("no xrandr support"); #endif }