]> git.tdb.fi Git - libs/gui.git/commitdiff
Initial XRandR support
authorMikko Rasa <tdb@tdb.fi>
Thu, 26 Sep 2013 12:32:49 +0000 (15:32 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 26 Sep 2013 16:26:25 +0000 (19:26 +0300)
It can't yet restore most multi-monitor configurations correctly.

Build
source/graphics/display_private.h
source/graphics/videomode.cpp
source/graphics/videomode.h
source/graphics/window.cpp
source/graphics/windows/display.cpp
source/graphics/windows/display_platform.h
source/graphics/x11/display.cpp
source/graphics/x11/display_platform.h

diff --git a/Build b/Build
index a0f437caa8cd37f3e534672896902defdde577a2..91255cea1377423f7124d0ac026906282bd1621d 100644 (file)
--- 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";
                        };
                };
        };
index e5ece56ca050629af9bf6b7b62c9b15327bfd518..4a88cedb1aeb0164669fa1a6592966ef54e360a4 100644 (file)
@@ -15,6 +15,7 @@ struct Display::Private
        DisplayHandle display;
        std::map<WindowHandle, Window *> windows;
        std::vector<MonitorHandle> monitors;
+       std::vector<ModeHandle> modes;
 };
 
 } // namespace Graphics
index 5c9e821449c14b966b75562da13417fdcea615e8..888cad824d318a4a3a22f783cce88054745440a8 100644 (file)
@@ -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),
index 4054b4bb1308398e5278d926d082d811c529d003..f1715c0428d6dfc49a62d5a4de71af4bf9883afe 100644 (file)
@@ -17,6 +17,7 @@ public:
 
 struct VideoMode
 {
+       unsigned index;
        const Monitor *monitor;
        unsigned width;
        unsigned height;
index 166e49f716fc8f63944015360b8806068ff325b6..256ab2d470ace62169af6c938f42722482f76412 100644 (file)
@@ -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);
        }
 }
index ae19f57c2c3bf59de14d9ba5f509ddbbf4eb8e17..43f86995b893343b1a2257053c5ac61b95773d9c 100644 (file)
@@ -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))
index fd7cce3f6f53cb12348e36c4f5f58185c5cc94bd..4abaee7b5cdff3ec5322da63645daa04e7f49f1a 100644 (file)
@@ -6,6 +6,7 @@ namespace Graphics {
 
 typedef void *DisplayHandle;
 typedef std::string MonitorHandle;
+typedef int ModeHandle;
 
 } // namespace Graphics
 } // namespace Msp
index 6fee30b26ff6873d88b1f69e1b6ec789358e1c06..2f276a32d5246666aeae56b722379fd46dff2d34 100644 (file)
@@ -1,7 +1,7 @@
 #include <iostream>
 #include <X11/Xlib.h>
-#ifdef WITH_XF86VIDMODE
-#include <X11/extensions/xf86vmode.h>
+#ifdef WITH_XRANDR
+#include <X11/extensions/Xrandr.h>
 #endif
 #include <msp/io/print.h>
 #include <msp/strings/format.h>
@@ -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<RRMode, XRRModeInfo *> modes_by_id;
+                       for(int i=0; i<res->nmode; ++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; i<res->noutput; ++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<nmodes; ++i)
-       {
-               XF86VidModeModeInfo &info = *infos[i];
-       
-               VideoMode mode(info.hdisplay, info.vdisplay);
-               mode.monitor = &monitor;
-               if(info.htotal && info.vtotal)
-                       mode.rate = info.dotclock/(info.htotal*info.vtotal);
-               modes.push_back(mode);
-               monitor.video_modes.push_back(&modes.back());
-
-               if(info.htotal==modeline.htotal && info.vtotal==modeline.vtotal && info.dotclock==static_cast<unsigned>(dotclock))
-                       monitor.desktop_mode = &modes.back();
-       }
+                               if(res->outputs[i]==primary)
+                                       primary_monitor = &monitor;
+
+                               for(int j=0; j<output->nmode; ++j)
+                               {
+                                       map<RRMode, XRRModeInfo *>::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; i<nmodes; ++i)
+#ifdef WITH_XRANDR
+       const VideoMode *mode = find_matching_mode(requested_mode);
+       if(!mode)
+               throw unsupported_video_mode(requested_mode);
+
+       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
        {
-               XF86VidModeModeInfo &info = *infos[i];
+               for(int i=0; i<res->ncrtc; ++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; i<priv->monitors.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
 }
 
index f56d37c1789a81af760f3476953ad11787db46b9..8db3e98e8f79eab86f4d3a6aba6a8422aab9cae6 100644 (file)
@@ -2,12 +2,14 @@
 #define MSP_GRAPHICS_DISPLAY_PLATFORM_H_
 
 #include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
 
 namespace Msp {
 namespace Graphics {
 
 typedef ::Display *DisplayHandle;
-typedef int MonitorHandle;
+typedef RROutput MonitorHandle;
+typedef RRMode ModeHandle;
 
 } // namespace Graphics
 } // namespace Msp