From 9bc0825e93b1385a4aaf9f90d666a1ac409ffb17 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 26 Sep 2013 15:32:49 +0300 Subject: [PATCH] Initial XRandR support It can't yet restore most multi-monitor configurations correctly. --- Build | 6 +- source/graphics/display_private.h | 1 + source/graphics/videomode.cpp | 2 + source/graphics/videomode.h | 1 + source/graphics/window.cpp | 2 +- source/graphics/windows/display.cpp | 1 + source/graphics/windows/display_platform.h | 1 + source/graphics/x11/display.cpp | 156 ++++++++++++++------- source/graphics/x11/display_platform.h | 4 +- 9 files changed, 122 insertions(+), 52 deletions(-) diff --git a/Build b/Build index a0f437c..91255ce 100644 --- a/Build +++ b/Build @@ -43,12 +43,12 @@ package "mspgui" if_arch "!windows" { - feature "xf86vidmode" "Include support for video mode switching with xf86vidmode"; - if_feature "xf86vidmode" + feature "xrandr" "Include support for video mode switching with XRandR"; + if_feature "xrandr" { build_info { - library "Xxf86vm"; + library "Xrandr"; }; }; }; diff --git a/source/graphics/display_private.h b/source/graphics/display_private.h index e5ece56..4a88ced 100644 --- a/source/graphics/display_private.h +++ b/source/graphics/display_private.h @@ -15,6 +15,7 @@ struct Display::Private DisplayHandle display; std::map windows; std::vector monitors; + std::vector modes; }; } // namespace Graphics diff --git a/source/graphics/videomode.cpp b/source/graphics/videomode.cpp index 5c9e821..888cad8 100644 --- a/source/graphics/videomode.cpp +++ b/source/graphics/videomode.cpp @@ -10,6 +10,7 @@ unsupported_video_mode::unsupported_video_mode(const VideoMode &mode): VideoMode::VideoMode(): + index(0), monitor(0), width(0), height(0), @@ -17,6 +18,7 @@ VideoMode::VideoMode(): { } VideoMode::VideoMode(unsigned w, unsigned h): + index(0), monitor(0), width(w), height(h), diff --git a/source/graphics/videomode.h b/source/graphics/videomode.h index 4054b4b..f1715c0 100644 --- a/source/graphics/videomode.h +++ b/source/graphics/videomode.h @@ -17,6 +17,7 @@ public: struct VideoMode { + unsigned index; const Monitor *monitor; unsigned width; unsigned height; diff --git a/source/graphics/window.cpp b/source/graphics/window.cpp index 166e49f..256ab2d 100644 --- a/source/graphics/window.cpp +++ b/source/graphics/window.cpp @@ -86,7 +86,7 @@ void Window::show() if(options.fullscreen) { - display.set_mode(VideoMode(options.width, options.height)); + display.set_mode(VideoMode(options.width, options.height), true); warp_pointer(options.width/2, options.height/2); } } diff --git a/source/graphics/windows/display.cpp b/source/graphics/windows/display.cpp index ae19f57..43f8699 100644 --- a/source/graphics/windows/display.cpp +++ b/source/graphics/windows/display.cpp @@ -39,6 +39,7 @@ Display::Display(const string &): break; VideoMode mode(info.dmPelsWidth, info.dmPelsHeight); + mode.index = modes.size(); mode.monitor = &monitor; mode.rate = info.dmDisplayFrequency; if(find_matching_mode(mode)) diff --git a/source/graphics/windows/display_platform.h b/source/graphics/windows/display_platform.h index fd7cce3..4abaee7 100644 --- a/source/graphics/windows/display_platform.h +++ b/source/graphics/windows/display_platform.h @@ -6,6 +6,7 @@ namespace Graphics { typedef void *DisplayHandle; typedef std::string MonitorHandle; +typedef int ModeHandle; } // namespace Graphics } // namespace Msp diff --git a/source/graphics/x11/display.cpp b/source/graphics/x11/display.cpp index 6fee30b..2f276a3 100644 --- a/source/graphics/x11/display.cpp +++ b/source/graphics/x11/display.cpp @@ -1,7 +1,7 @@ #include #include -#ifdef WITH_XF86VIDMODE -#include +#ifdef WITH_XRANDR +#include #endif #include #include @@ -57,37 +57,67 @@ Display::Display(const string &disp_name): XSetErrorHandler(x_error_handler); -#ifdef WITH_XF86VIDMODE - int screen = DefaultScreen(priv->display); +#ifdef WITH_XRANDR + int event_base; + int error_base; + if(XRRQueryExtension(priv->display, &event_base, &error_base)) + { + 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); - monitors.push_back(Monitor()); - Monitor &monitor = monitors.back(); - primary_monitor = &monitor; + map modes_by_id; + for(int i=0; inmode; ++i) + modes_by_id[res->modes[i].id] = &res->modes[i]; - int nmodes; - XF86VidModeModeInfo **infos; - XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos); + 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); + monitors.push_back(Monitor()); + Monitor &monitor = monitors.back(); + monitor.index = monitors.size()-1; + priv->monitors.push_back(res->outputs[i]); - for(int i=0; i(dotclock)) - monitor.desktop_mode = &modes.back(); - } + 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_matching_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(); + } + + XRRFreeOutputInfo(output); + if(crtc) + XRRFreeCrtcInfo(crtc); + } - XFree(infos); + XRRFreeScreenResources(res); + } + } #endif } @@ -97,33 +127,65 @@ Display::~Display() delete priv; } -void Display::set_mode(const VideoMode &mode, bool) +void Display::set_mode(const VideoMode &requested_mode, bool exclusive) { -#ifdef WITH_XF86VIDMODE - int screen = DefaultScreen(priv->display); - - int nmodes; - XF86VidModeModeInfo **infos; - XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos); - for(int i=0; idisplay); + 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 { - XF86VidModeModeInfo &info = *infos[i]; + 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); + } - 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(!crtc) { - XF86VidModeSwitchToMode(priv->display, screen, &info); - XF86VidModeSetViewPort(priv->display, screen, 0, 0); - return; + XRRFreeOutputInfo(output_info); + throw unsupported_video_mode(requested_mode); } } - throw unsupported_video_mode(mode); + if(exclusive) + { + // Disable other outputs for exclusive mode + for(unsigned i=0; imonitors.size(); ++i) + if(i!=mode->monitor->index) + { + XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i]); + if(o->crtc) + XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, 0, 0, 0, RR_Rotate_0, 0, 0); + XRRFreeOutputInfo(o); + } + } + + XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, 0, 0, priv->modes[mode->index], RR_Rotate_0, &output, 1); + + 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 } diff --git a/source/graphics/x11/display_platform.h b/source/graphics/x11/display_platform.h index f56d37c..8db3e98 100644 --- a/source/graphics/x11/display_platform.h +++ b/source/graphics/x11/display_platform.h @@ -2,12 +2,14 @@ #define MSP_GRAPHICS_DISPLAY_PLATFORM_H_ #include +#include namespace Msp { namespace Graphics { typedef ::Display *DisplayHandle; -typedef int MonitorHandle; +typedef RROutput MonitorHandle; +typedef RRMode ModeHandle; } // namespace Graphics } // namespace Msp -- 2.43.0