]> git.tdb.fi Git - libs/gui.git/commitdiff
Expose a lot more information through the Monitor struct
authorMikko Rasa <tdb@tdb.fi>
Thu, 26 Sep 2013 16:29:18 +0000 (19:29 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 26 Sep 2013 16:29:18 +0000 (19:29 +0300)
This includes current mode and location in a multi-monitor setup.  Rotated
monitors and modes are also supported.  It's enough for many common cases,
though more exotic layouts still cannot be restored.

I'm not certain exactly how Windows handles multiple monitors.  Additional
research is required.

source/graphics/monitor.cpp
source/graphics/monitor.h
source/graphics/videomode.cpp
source/graphics/videomode.h
source/graphics/windows/display.cpp
source/graphics/x11/display.cpp

index 0bc33efe042911edc7058f844c082e17fa1c8a62..1ac438317b927a4b7e2dc145d9b8fbbcd842b5f3 100644 (file)
@@ -7,7 +7,14 @@ namespace Graphics {
 
 Monitor::Monitor():
        index(0),
-       desktop_mode(0)
+       desktop_mode(0),
+       desktop_rotation(ROTATE_NORMAL),
+       current_mode(0),
+       current_rotation(ROTATE_NORMAL),
+       x(0),
+       y(0),
+       next_left(0),
+       next_right(0)
 { }
 
 } // namespace Graphics
index d5e49bb3dbb210bc420f0bef3ff7e050b2cf728a..18586db50d4782f8871ca0c6e459b90df74b12bf 100644 (file)
@@ -3,17 +3,22 @@
 
 #include <list>
 #include <string>
+#include "videomode.h"
 
 namespace Msp {
 namespace Graphics {
 
-struct VideoMode;
-
 struct Monitor
 {
        unsigned index;
        std::list<const VideoMode *> video_modes;
        const VideoMode *desktop_mode;
+       VideoRotation desktop_rotation;
+       const VideoMode *current_mode;
+       VideoRotation current_rotation;
+       int x, y;
+       const Monitor *next_left;
+       const Monitor *next_right;
 
        Monitor();
 };
index 888cad824d318a4a3a22f783cce88054745440a8..b3ca948fb1f86b5161ed4fd4466eb3f3bd19ca71 100644 (file)
@@ -14,7 +14,8 @@ VideoMode::VideoMode():
        monitor(0),
        width(0),
        height(0),
-       rate(0)
+       rate(0),
+       rotation(ROTATE_ANY)
 { }
 
 VideoMode::VideoMode(unsigned w, unsigned h):
@@ -22,7 +23,8 @@ VideoMode::VideoMode(unsigned w, unsigned h):
        monitor(0),
        width(w),
        height(h),
-       rate(0)
+       rate(0),
+       rotation(ROTATE_ANY)
 { }
 
 } // namespace Graphics
index 328d6ea31d3034b81c68fa667f3b6b015d1fd48f..2836e11a5c134f00d0f610b54833089efeaa04ef 100644 (file)
@@ -17,6 +17,15 @@ public:
 };
 
 
+enum VideoRotation
+{
+       ROTATE_ANY,
+       ROTATE_NORMAL,
+       ROTATE_LEFT,
+       ROTATE_RIGHT,
+       ROTATE_INVERTED
+};
+
 struct VideoMode
 {
        unsigned index;
@@ -24,6 +33,7 @@ struct VideoMode
        unsigned width;
        unsigned height;
        unsigned rate;
+       VideoRotation rotation;
 
        VideoMode();
        VideoMode(unsigned, unsigned);
index 43f86995b893343b1a2257053c5ac61b95773d9c..6553a8c692163772ca877e09fa1f26a8d6834271 100644 (file)
@@ -78,6 +78,10 @@ void Display::set_mode(const VideoMode &requested_mode, bool)
        LONG ret = ChangeDisplaySettingsEx(priv->monitors[mode->monitor->index].c_str(), &info, NULL, CDS_FULLSCREEN, NULL);
        if(ret!=DISP_CHANGE_SUCCESSFUL)
                throw unsupported_video_mode(requested_mode);
+
+       for(list<Monitor>::iterator i=monitors.begin(); i!=monitors.end(); ++i)
+               if(&*i==mode->monitor)
+                       i->current_mode = mode;
 }
 
 bool Display::process_events()
index 2f276a32d5246666aeae56b722379fd46dff2d34..368b67cecdc5b6953db9e113664e16f30bed9889 100644 (file)
@@ -38,6 +38,43 @@ int x_error_handler(Display *display, XErrorEvent *event)
        return 0;
 }
 
+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;
+       }
+}
+
+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.x<m2.x;
+}
+
+inline unsigned mode_width(const Msp::Graphics::VideoMode &m, Msp::Graphics::VideoRotation r)
+{
+       if(r==Msp::Graphics::ROTATE_RIGHT || r==Msp::Graphics::ROTATE_LEFT)
+               return m.height;
+       else
+               return m.width;
+}
+
 }
 
 
@@ -84,6 +121,14 @@ Display::Display(const string &disp_name):
                                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;
 
@@ -107,7 +152,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 +164,17 @@ Display::Display(const string &disp_name):
                        }
 
                        XRRFreeScreenResources(res);
+
+                       monitors.sort(monitor_x_compare);
+                       Monitor *prev_enabled = 0;
+                       for(list<Monitor>::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;
+                               }
                }
        }
 #endif
@@ -134,6 +193,10 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive)
        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];
@@ -164,20 +227,67 @@ 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; i<priv->monitors.size(); ++i)
-                       if(i!=mode->monitor->index)
+               for(list<Monitor>::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;
 
-       XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, 0, 0, priv->modes[mode->index], RR_Rotate_0, &output, 1);
+               if(left)
+               {
+                       x = left->x+mode_width(*left->current_mode, left->current_rotation);
+                       y = left->y;
+               }
+       }
+
+       XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, x, y, priv->modes[mode->index], rotation_to_sys(requested_rotation), &output, 1);
+
+       list<Monitor>::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);
+                       XRRFreeOutputInfo(o);
+
+                       i->x = x;
+                       i->y = y;
+
+                       x += mode_width(*i->current_mode, i->current_rotation);
+               }
 
        XRRFreeOutputInfo(output_info);
        XRRFreeCrtcInfo(crtc_info);