]> git.tdb.fi Git - libs/gui.git/blobdiff - source/graphics/x11/display.cpp
Expose a lot more information through the Monitor struct
[libs/gui.git] / source / graphics / x11 / display.cpp
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);