]> git.tdb.fi Git - libs/gui.git/blobdiff - source/graphics/x11/display.cpp
Use lambdas for comparison functions
[libs/gui.git] / source / graphics / x11 / display.cpp
index ba8d2532d914494e31ca847abdb5052926c2b6df..482e1c34383a073dc9571a5eb957a6c0a93a582d 100644 (file)
@@ -1,20 +1,21 @@
+#include "display.h"
+#include "display_private.h"
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
 #ifdef WITH_XRANDR
 #include <X11/extensions/Xrandr.h>
 #endif
+#include <msp/core/algorithm.h>
 #include <msp/io/print.h>
 #include <msp/strings/format.h>
 #include <msp/strings/lexicalcast.h>
-#include "display.h"
-#include "display_private.h"
 
 using namespace std;
 
 namespace {
 
 bool error_flag = false;
-std::string error_msg;
+string error_msg;
 
 int x_error_handler(Display *display, XErrorEvent *event)
 {
@@ -60,13 +61,6 @@ inline Rotation rotation_to_sys(Msp::Graphics::VideoRotation r)
        default: return RR_Rotate_0;
        }
 }
-
-inline bool monitor_x_compare(const Msp::Graphics::Monitor &m1, const Msp::Graphics::Monitor &m2)
-{
-       if(m1.desktop_settings.mode && !m2.desktop_settings.mode)
-               return true;
-       return m1.desktop_settings.x<m2.desktop_settings.x;
-}
 #endif
 
 inline unsigned mode_width(const Msp::Graphics::VideoMode &m, Msp::Graphics::VideoRotation r)
@@ -84,12 +78,10 @@ namespace Msp {
 namespace Graphics {
 
 Display::Display(const string &disp_name):
-       primary_monitor(0),
-       priv(new Private),
-       focus_window(0)
+       priv(new Private)
 {
        if(disp_name.empty())
-               priv->display = XOpenDisplay(0);
+               priv->display = XOpenDisplay(nullptr);
        else
                priv->display = XOpenDisplay(disp_name.c_str());
        if(!priv->display)
@@ -118,10 +110,13 @@ Display::Display(const string &disp_name):
                        for(int i=0; i<res->nmode; ++i)
                                modes_by_id[res->modes[i].id] = &res->modes[i];
 
+                       int primary_index = -1;
+                       vector<unsigned> mode_monitor_indices;
+                       vector<int> desktop_mode_indices;
                        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);
+                               XRRCrtcInfo *crtc = (output->crtc ? XRRGetCrtcInfo(priv->display, res, output->crtc) : nullptr);
 
                                monitors.push_back(Monitor());
                                Monitor &monitor = monitors.back();
@@ -135,7 +130,7 @@ Display::Display(const string &disp_name):
                                        int prop_format;
                                        unsigned long length;
                                        unsigned long overflow;
-                                       unsigned char *edid = 0;
+                                       unsigned char *edid = nullptr;
                                        XRRGetOutputProperty(priv->display, res->outputs[i], edid_prop, 0, 32, false, false, XA_INTEGER, &prop_type, &prop_format, &length, &overflow, &edid);
                                        if(prop_type==XA_INTEGER && prop_format==8)
                                        {
@@ -161,32 +156,36 @@ Display::Display(const string &disp_name):
                                }
 
                                if(res->outputs[i]==primary)
-                                       primary_monitor = &monitor;
+                                       primary_index = monitor.index;
 
+                               unsigned first_mode = modes.size();
+                               int desktop_mode_index = -1;
                                for(int j=0; j<output->nmode; ++j)
                                {
-                                       map<RRMode, XRRModeInfo *>::iterator k = modes_by_id.find(output->modes[j]);
+                                       auto k = modes_by_id.find(output->modes[j]);
                                        if(k==modes_by_id.end())
                                                continue;
 
                                        XRRModeInfo *info = k->second;
+                                       float rate = static_cast<float>(info->dotClock)/(info->hTotal*info->vTotal);
+
+                                       if(any_of(modes.begin()+first_mode, modes.end(), [&info, rate](const VideoMode &m){
+                                                       return (m.width==info->width && m.height==info->height && abs(m.rate-rate)<0.01f);
+                                               }))
+                                               continue;
 
                                        VideoMode mode(info->width, info->height);
                                        mode.index = modes.size();
-                                       mode.monitor = &monitor;
-                                       mode.rate = static_cast<float>(info->dotClock)/(info->hTotal*info->vTotal);
-                                       if(find_mode(mode, 0.01f))
-                                               continue;
+                                       mode.rate = rate;
 
                                        modes.push_back(mode);
                                        priv->modes.push_back(info->id);
-                                       monitor.video_modes.push_back(&modes.back());
+                                       mode_monitor_indices.push_back(monitor.index);
 
                                        if(crtc && info->id==crtc->mode)
-                                               monitor.desktop_settings.mode = &modes.back();
+                                               desktop_mode_index = mode.index;
                                }
-
-                               monitor.current_settings = monitor.desktop_settings;
+                               desktop_mode_indices.push_back(desktop_mode_index);
 
                                XRRFreeOutputInfo(output);
                                if(crtc)
@@ -195,29 +194,54 @@ 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_settings.mode)
+                       for(unsigned i=0; i<monitors.size(); ++i)
+                       {
+                               int j = desktop_mode_indices[i];
+                               if(j>=0)
+                                       monitors[i].desktop_settings.mode = &modes[j];
+                               monitors[i].current_settings = monitors[i].desktop_settings;
+                       }
+
+                       sort(monitors, [](const Msp::Graphics::Monitor &m1, const Msp::Graphics::Monitor &m2){
+                               if(m1.desktop_settings.mode && !m2.desktop_settings.mode)
+                                       return true;
+                               if(!m1.desktop_settings.mode && m2.desktop_settings.mode)
+                                       return false;
+                               return m1.desktop_settings.x<m2.desktop_settings.x;
+                       });
+
+                       for(unsigned i=0; i<modes.size(); ++i)
+                       {
+                               auto j = find_member(monitors, mode_monitor_indices[i], &Monitor::index);
+                               modes[i].monitor = &*j;
+                               j->video_modes.push_back(&modes[i]);
+                       }
+
+                       Monitor *prev_enabled = nullptr;
+                       for(Monitor &m: monitors)
+                               if(m.desktop_settings.mode)
                                {
-                                       i->next_left = prev_enabled;
+                                       m.next_left = prev_enabled;
                                        if(prev_enabled)
-                                               prev_enabled->next_right = &*i;
-                                       prev_enabled = &*i;
+                                               prev_enabled->next_right = &m;
+                                       prev_enabled = &m;
                                }
 
+                       if(primary_index>=0)
+                               primary_monitor = &*find_member(monitors, static_cast<unsigned>(primary_index), &Monitor::index);
+
                        if(!primary_monitor || !primary_monitor->desktop_settings.mode)
                        {
                                // XRandR didn't give a sensible primary monitor.  Try to guess one.
                                unsigned largest = 0;
-                               for(list<Monitor>::iterator i=monitors.begin(); i!=monitors.end(); ++i)
-                                       if(const VideoMode *desktop_mode = i->desktop_settings.mode)
+                               for(Monitor &m: monitors)
+                                       if(const VideoMode *desktop_mode = m.desktop_settings.mode)
                                        {
                                                unsigned size = desktop_mode->width*desktop_mode->height;
                                                if(size>largest)
                                                {
                                                        largest = size;
-                                                       primary_monitor = &*i;
+                                                       primary_monitor = &m;
                                                }
                                        }
                        }
@@ -250,7 +274,7 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive)
 
        // 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;
+       XRRCrtcInfo *crtc_info = nullptr;
        if(crtc)
                crtc_info = XRRGetCrtcInfo(priv->display, res, crtc);
        else
@@ -273,85 +297,43 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive)
                }
        }
 
-       int x = 0;
-       int y = 0;
+       /* Due to the semantics of find_mode, the mode's monitor pointer must point
+       to one of the elements of the monitors list, which is non-const here. */
+       Monitor *monitor = const_cast<Monitor *>(mode->monitor);
 
        if(exclusive)
        {
+               monitor->current_settings.mode = mode;
+               monitor->current_settings.rotation = requested_rotation;
+               monitor->current_settings.x = 0;
+               monitor->current_settings.y = 0;
+
                // Disable other outputs for exclusive mode
-               for(list<Monitor>::iterator i=monitors.begin(); i!=monitors.end(); ++i)
-                       if(&*i!=mode->monitor)
+               for(Monitor &m: monitors)
+                       if(&m!=mode->monitor)
                        {
-                               XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i->index]);
+                               XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[m.index]);
                                if(o->crtc)
-                                       XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, 0, 0, 0, RR_Rotate_0, 0, 0);
+                                       XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, 0, 0, 0, RR_Rotate_0, nullptr, 0);
                                XRRFreeOutputInfo(o);
 
-                               i->current_settings.mode = 0;
-                               i->current_settings.rotation = ROTATE_NORMAL;
-                               i->current_settings.x = 0;
-                               i->current_settings.y = 0;
+                               m.current_settings.mode = nullptr;
+                               m.current_settings.rotation = ROTATE_NORMAL;
+                               m.current_settings.x = 0;
+                               m.current_settings.y = 0;
                        }
        }
        else
        {
-               const Monitor *left = mode->monitor->next_left;
-               while(left && !left->current_settings.mode)
-                       left = left->next_left;
-
-               if(left)
-               {
-                       const Monitor::Settings &cs = left->current_settings;
-                       x = cs.x+mode_width(*cs.mode, cs.rotation);
-                       y = cs.y;
-               }
+               monitor->current_settings.x = monitor->desktop_settings.x;
+               monitor->current_settings.y = monitor->desktop_settings.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_settings.mode = mode;
-                       i->current_settings.rotation = requested_rotation;
-                       i->current_settings.x = x;
-                       i->current_settings.y = y;
-
-                       x += mode_width(*mode, requested_rotation);
-                       ++i;
-                       break;
-               }
-
-       for(; i!=monitors.end(); ++i)
-               if(i->current_settings.mode)
-               {
-                       XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i->index]);
-                       XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, x, y, priv->modes[i->current_settings.mode->index], rotation_to_sys(i->current_settings.rotation), &priv->monitors[i->index], 1);
-
-                       XRRPanning panning;
-                       panning.timestamp = CurrentTime;
-                       panning.left = x;
-                       panning.top = y;
-                       panning.width = i->current_settings.mode->width;
-                       panning.height = i->current_settings.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->current_settings.x = x;
-                       i->current_settings.y = y;
-
-                       x += mode_width(*i->current_settings.mode, i->current_settings.rotation);
-               }
+       RRMode mode_id = priv->modes[mode->index];
+       int x = monitor->current_settings.x;
+       int y = monitor->current_settings.y;
+       Rotation sys_rot = rotation_to_sys(requested_rotation);
+       XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, x, y, mode_id, sys_rot, &output, 1);
 
        XRRFreeOutputInfo(output_info);
        XRRFreeCrtcInfo(crtc_info);
@@ -376,7 +358,7 @@ bool Display::process_events()
 
                check_error();
 
-               map<WindowHandle, Window *>::iterator j = priv->windows.find(event.xevent.xany.window);
+               auto j = priv->windows.find(event.xevent.xany.window);
                if(j!=priv->windows.end())
                {
                        /* Filter keyboard autorepeat.  If this packet is a KeyRelease and