From f7c02b73dc5ae068dac0723d0a8b50f756f3303e Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Thu, 16 Aug 2018 15:59:08 +0100 Subject: [PATCH 01/34] Introduce StaticDisplayConfigurationPolicy --- src/miral/display_configuration_option.cpp | 98 +++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index fa8ff043fa2..02815b59a6b 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -22,17 +22,29 @@ #include #include #include +#include +#include +#include + +#define MIR_LOG_COMPONENT "miral" +#include + +#include +#include +#include namespace mg = mir::graphics; +using namespace mir::geometry; namespace { char const* const display_config_opt = "display-config"; -char const* const display_config_descr = "Display configuration [{clone,sidebyside,single}]"; +char const* const display_config_descr = "Display configuration [{clone,sidebyside,single,static=}]"; //char const* const clone_opt_val = "clone"; char const* const sidebyside_opt_val = "sidebyside"; char const* const single_opt_val = "single"; +char const* const static_opt_val = "static="; char const* const display_alpha_opt = "translucent"; char const* const display_alpha_descr = "Select a display mode with alpha[{on,off}]"; @@ -67,6 +79,7 @@ PixelFormatSelector::PixelFormatSelector( void PixelFormatSelector::apply_to(mg::DisplayConfiguration& conf) { base_policy->apply_to(conf); + conf.for_each_output( [&](mg::UserDisplayConfigurationOutput& conf_output) { @@ -88,6 +101,87 @@ void PixelFormatSelector::apply_to(mg::DisplayConfiguration& conf) }); } +namespace +{ +class StaticDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy +{ +public: + StaticDisplayConfigurationPolicy(std::string const& filename); + virtual void apply_to(mg::DisplayConfiguration& conf); +private: + + using Id = std::tuple; + struct Config { mir::optional_value position; mir::optional_value size; }; + + std::map config; +}; + +size_t select_mode_index(size_t mode_index, std::vector const & modes) +{ + if (modes.empty()) + return std::numeric_limits::max(); + + if (mode_index >= modes.size()) + return 0; + + return mode_index; +} +} + +StaticDisplayConfigurationPolicy::StaticDisplayConfigurationPolicy(std::string const& filename) +{ + puts(filename.c_str()); + + // Just set up some dummy data + config[Id{0, 1}].position = Point{0, 0}; + config[Id{0, 1}].size = Size{1024, 768}; + config[Id{0, 2}].position = Point{1024, 0}; + config[Id{0, 2}].size = Size{1024, 768}; +} + +void StaticDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) +{ + conf.for_each_output([&](mg::UserDisplayConfigurationOutput& conf_output) + { + if (conf_output.connected && conf_output.modes.size() > 0) + { + conf_output.used = true; + conf_output.power_mode = mir_power_mode_on; + conf_output.orientation = mir_orientation_normal; + + auto& conf = config[Id{conf_output.card_id, conf_output.id}]; + + if (conf.position.is_set()) + { + conf_output.top_left = conf.position.value(); + } + else + { + conf_output.top_left = Point{0, 0}; + } + + size_t preferred_mode_index{select_mode_index(conf_output.preferred_mode_index, conf_output.modes)}; + conf_output.current_mode_index = preferred_mode_index; + + if (conf.size.is_set()) + { + for (auto mode = begin(conf_output.modes); mode != end(conf_output.modes); ++mode) + { + if (mode->size == conf.size.value()) + { + conf_output.current_mode_index = distance(begin(conf_output.modes), mode); + } + } + } + } + else + { + conf_output.used = false; + conf_output.power_mode = mir_power_mode_off; + } + }); +} + void miral::display_configuration_options(mir::Server& server) { // Add choice of monitor configuration @@ -108,6 +202,8 @@ void miral::display_configuration_options(mir::Server& server) layout_selector = std::make_shared(); else if (display_layout == single_opt_val) layout_selector = std::make_shared(); + else if (display_layout.compare(0, strlen(static_opt_val), static_opt_val) == 0) + layout_selector = std::make_shared(display_layout.substr(strlen(static_opt_val))); // Whatever the layout select a pixel format with requested alpha return std::make_shared(layout_selector, with_alpha); From c26c9541772fb815b9b2a0f9de2c05c35e2ecf8b Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Thu, 16 Aug 2018 18:13:06 +0100 Subject: [PATCH 02/34] Add parsing (pass one) --- src/miral/display_configuration_option.cpp | 118 +++++++++++++++++++-- 1 file changed, 111 insertions(+), 7 deletions(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index 02815b59a6b..9247d43cbbf 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include namespace mg = mir::graphics; using namespace mir::geometry; @@ -130,13 +132,111 @@ size_t select_mode_index(size_t mode_index, std::vector> card_no)) + goto error; + + if (!(in >> delimiter) || delimiter != '/') + goto error; + + if (!(in >> port_no)) + goto error; + + Id const output_id{card_no, port_no}; + Config output_config; + + if (in >> delimiter && delimiter != ':') + goto error; + + in >> std::ws; + std::string property; + while (std::getline(in, property, '=')) + { + puts(property.c_str()); + + if (property == "position") + { + int x; + int y; + + if (!(in >> x)) + goto error; + + if (!(in >> delimiter) || delimiter != ',') + goto error; + + if (!(in >> y)) + goto error; + + output_config.position = Point{x, y}; + } + else if (property == "size") + { + int width; + int height; + + if (!(in >> width)) + goto error; + + if (!(in >> delimiter) || delimiter != 'x') + goto error; + + if (!(in >> height)) + goto error; + + output_config.size = Size{width, height}; + } + else goto error; + + if (in >> delimiter && delimiter != ';') + goto error; + + in >> std::ws; + } + + config[output_id] = output_config; + } + + return; + +error: + throw mir::AbnormalExit{"ERROR: Syntax error in display configuration file: '" + filename + + "' line: " + std::to_string(line_count)}; } void StaticDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) @@ -169,7 +269,11 @@ void StaticDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) { if (mode->size == conf.size.value()) { - conf_output.current_mode_index = distance(begin(conf_output.modes), mode); + if (conf_output.modes[conf_output.current_mode_index].size != conf.size.value() + || conf_output.modes[conf_output.current_mode_index].vrefresh_hz < mode->vrefresh_hz) + { + conf_output.current_mode_index = distance(begin(conf_output.modes), mode); + } } } } From 9b300d8d933b43eabdff74a06e6be0c4f0ea77d3 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 17 Aug 2018 10:55:56 +0100 Subject: [PATCH 03/34] More robust parsing and rudimentary error reporting --- src/miral/display_configuration_option.cpp | 79 +++++++++++++++------- 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index 9247d43cbbf..680679d8335 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -29,9 +29,8 @@ #define MIR_LOG_COMPONENT "miral" #include +#include #include -#include -#include #include #include @@ -115,6 +114,8 @@ class StaticDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy using Id = std::tuple; struct Config { mir::optional_value position; mir::optional_value size; }; + static constexpr char const* const output_id = "output_id"; + std::map config; }; @@ -132,37 +133,39 @@ size_t select_mode_index(size_t mode_index, std::vector> std::ws; + std::getline(in, property, '='); + + if (property != output_id) + goto error; int card_no = -1; int port_no = -1; @@ -183,12 +186,8 @@ StaticDisplayConfigurationPolicy::StaticDisplayConfigurationPolicy(std::string c if (in >> delimiter && delimiter != ':') goto error; - in >> std::ws; - std::string property; - while (std::getline(in, property, '=')) + while (in >> std::ws, std::getline(in, property, '=')) { - puts(property.c_str()); - if (property == "position") { int x; @@ -223,10 +222,8 @@ StaticDisplayConfigurationPolicy::StaticDisplayConfigurationPolicy(std::string c } else goto error; - if (in >> delimiter && delimiter != ';') + if (in >> std::ws, in >> delimiter && delimiter != ';') goto error; - - in >> std::ws; } config[output_id] = output_config; @@ -235,12 +232,18 @@ StaticDisplayConfigurationPolicy::StaticDisplayConfigurationPolicy(std::string c return; error: + std::string error; + getline(in, error); throw mir::AbnormalExit{"ERROR: Syntax error in display configuration file: '" + filename + - "' line: " + std::to_string(line_count)}; + "' line: " + std::to_string(line_count) + + " before: " + error + "'"}; } void StaticDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) { + std::ostringstream out; + out << "Display config:\n8>< ---------------------------------------------------"; + conf.for_each_output([&](mg::UserDisplayConfigurationOutput& conf_output) { if (conf_output.connected && conf_output.modes.size() > 0) @@ -283,7 +286,37 @@ void StaticDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) conf_output.used = false; conf_output.power_mode = mir_power_mode_off; } + + auto const type = mir_output_type_name(static_cast(conf_output.type)); + + out << '\n' << output_id << '=' << conf_output.card_id << '/' << conf_output.id; + + if (conf_output.connected && conf_output.modes.size() > 0) + { + auto const& top_left = conf_output.top_left; + auto const& size = conf_output.modes[conf_output.current_mode_index].size; + out << ": " << "position=" << top_left.x << ',' << top_left.y + << "; " << "size="<< size.width << 'x' << size.height; + } + + out << " # " << type; + + if (!conf_output.connected || conf_output.modes.size() <= 0) + out << " (disconnected)"; + + if (conf_output.modes.size() > 0) + { + out << " modes: "; + for (size_t i = 0; i < conf_output.modes.size(); ++i) + { + if (i) out << ", "; + out << conf_output.modes[i]; + } + } }); + + out << "\n8>< ---------------------------------------------------"; + mir::log_info(out.str()); } void miral::display_configuration_options(mir::Server& server) From 22098aef78ebb74f1640a5b9510c9ef8c3886c6d Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 17 Aug 2018 12:32:03 +0100 Subject: [PATCH 04/34] Make things a bit more readable --- src/miral/CMakeLists.txt | 2 ++ src/miral/display_configuration_option.cpp | 34 ++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/miral/CMakeLists.txt b/src/miral/CMakeLists.txt index b48cd955b4d..46a7dbb7841 100644 --- a/src/miral/CMakeLists.txt +++ b/src/miral/CMakeLists.txt @@ -11,6 +11,8 @@ set(miral_include ${PROJECT_SOURCE_DIR}/include/miral) add_library(mirclientcpp INTERFACE) +add_definitions(-DMIR_LOG_COMPONENT_FALLBACK="miral") + add_library(miral-internal STATIC active_outputs.cpp active_outputs.h basic_window_manager.cpp basic_window_manager.h window_manager_tools_implementation.h diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index 680679d8335..6bdf2535306 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -1,5 +1,5 @@ /* - * Copyright © 2014, 2016 Canonical Ltd. + * Copyright © 2014-2018 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 or 3 as @@ -18,18 +18,14 @@ #include "miral/display_configuration_option.h" +#include #include #include +#include #include #include #include -#include -#include - -#define MIR_LOG_COMPONENT "miral" -#include -#include #include #include #include @@ -104,10 +100,10 @@ void PixelFormatSelector::apply_to(mg::DisplayConfiguration& conf) namespace { -class StaticDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy +class StaticDisplayConfig : public mg::DisplayConfigurationPolicy { public: - StaticDisplayConfigurationPolicy(std::string const& filename); + StaticDisplayConfig(std::string const& filename); virtual void apply_to(mg::DisplayConfiguration& conf); private: @@ -115,6 +111,8 @@ class StaticDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy struct Config { mir::optional_value position; mir::optional_value size; }; static constexpr char const* const output_id = "output_id"; + static constexpr char const* const position = "position"; + static constexpr char const* const size = "size"; std::map config; }; @@ -131,7 +129,7 @@ size_t select_mode_index(size_t mode_index, std::vector> std::ws, std::getline(in, property, '=')) { - if (property == "position") + if (property == position) { int x; int y; @@ -204,7 +202,7 @@ StaticDisplayConfigurationPolicy::StaticDisplayConfigurationPolicy(std::string c output_config.position = Point{x, y}; } - else if (property == "size") + else if (property == size) { int width; int height; @@ -239,7 +237,7 @@ StaticDisplayConfigurationPolicy::StaticDisplayConfigurationPolicy(std::string c " before: " + error + "'"}; } -void StaticDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) +void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) { std::ostringstream out; out << "Display config:\n8>< ---------------------------------------------------"; @@ -293,10 +291,10 @@ void StaticDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) if (conf_output.connected && conf_output.modes.size() > 0) { - auto const& top_left = conf_output.top_left; - auto const& size = conf_output.modes[conf_output.current_mode_index].size; - out << ": " << "position=" << top_left.x << ',' << top_left.y - << "; " << "size="<< size.width << 'x' << size.height; + auto const& tl = conf_output.top_left; + auto const& sz = conf_output.modes[conf_output.current_mode_index].size; + out << ": " << position << '=' << tl.x << ',' << tl.y + << "; " << size << '=' << sz.width << 'x' << sz.height; } out << " # " << type; @@ -340,7 +338,7 @@ void miral::display_configuration_options(mir::Server& server) else if (display_layout == single_opt_val) layout_selector = std::make_shared(); else if (display_layout.compare(0, strlen(static_opt_val), static_opt_val) == 0) - layout_selector = std::make_shared(display_layout.substr(strlen(static_opt_val))); + layout_selector = std::make_shared(display_layout.substr(strlen(static_opt_val))); // Whatever the layout select a pixel format with requested alpha return std::make_shared(layout_selector, with_alpha); From d0d4dad61900abaa8c1214c8cb7b9089e448a2ec Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 17 Aug 2018 16:13:55 +0100 Subject: [PATCH 05/34] Fix FTBFS on Ubuntu 16.04 --- src/miral/display_configuration_option.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index 6bdf2535306..e203aebc53a 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -178,7 +178,7 @@ StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) if (!(in >> port_no)) goto error; - Id const output_id{card_no, port_no}; + Id const output_id{mg::DisplayConfigurationCardId{card_no}, mg::DisplayConfigurationOutputId{port_no}}; Config output_config; if (in >> delimiter && delimiter != ':') From 57b71efdbf1fc2a953837a89f3040bd485a0a23b Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 17 Aug 2018 16:27:19 +0100 Subject: [PATCH 06/34] Rename "size" to "mode" --- src/miral/display_configuration_option.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index e203aebc53a..334851fcd9c 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -112,7 +112,7 @@ class StaticDisplayConfig : public mg::DisplayConfigurationPolicy static constexpr char const* const output_id = "output_id"; static constexpr char const* const position = "position"; - static constexpr char const* const size = "size"; + static constexpr char const* const mode = "mode"; std::map config; }; @@ -202,7 +202,7 @@ StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) output_config.position = Point{x, y}; } - else if (property == size) + else if (property == mode) { int width; int height; @@ -294,7 +294,7 @@ void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) auto const& tl = conf_output.top_left; auto const& sz = conf_output.modes[conf_output.current_mode_index].size; out << ": " << position << '=' << tl.x << ',' << tl.y - << "; " << size << '=' << sz.width << 'x' << sz.height; + << "; " << mode << '=' << sz.width << 'x' << sz.height; } out << " # " << type; From 7b11c41445e3bbed6791f5462ec5de4f8665a41c Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 17 Aug 2018 16:51:38 +0100 Subject: [PATCH 07/34] Add optional refresh rate to mode --- src/miral/display_configuration_option.cpp | 33 ++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index 334851fcd9c..aae9f0f15a3 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -108,7 +108,12 @@ class StaticDisplayConfig : public mg::DisplayConfigurationPolicy private: using Id = std::tuple; - struct Config { mir::optional_value position; mir::optional_value size; }; + struct Config + { + mir::optional_value position; + mir::optional_value size; + mir::optional_value refresh; + }; static constexpr char const* const output_id = "output_id"; static constexpr char const* const position = "position"; @@ -217,6 +222,18 @@ StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) goto error; output_config.size = Size{width, height}; + + if (in.peek() == '@') + { + double refresh; + if (!(in >> delimiter) || delimiter != '@') + goto error; + + if (!(in >> refresh)) + goto error; + + output_config.refresh = refresh; + } } else goto error; @@ -234,7 +251,7 @@ StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) getline(in, error); throw mir::AbnormalExit{"ERROR: Syntax error in display configuration file: '" + filename + "' line: " + std::to_string(line_count) + - " before: " + error + "'"}; + " before: '" + error + "'"}; } void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) @@ -270,7 +287,14 @@ void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) { if (mode->size == conf.size.value()) { - if (conf_output.modes[conf_output.current_mode_index].size != conf.size.value() + if (conf.refresh.is_set()) + { + if (abs(conf.refresh.value() - mode->vrefresh_hz) < 1.0) + { + conf_output.current_mode_index = distance(begin(conf_output.modes), mode); + } + } + else if (conf_output.modes[conf_output.current_mode_index].size != conf.size.value() || conf_output.modes[conf_output.current_mode_index].vrefresh_hz < mode->vrefresh_hz) { conf_output.current_mode_index = distance(begin(conf_output.modes), mode); @@ -292,9 +316,8 @@ void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) if (conf_output.connected && conf_output.modes.size() > 0) { auto const& tl = conf_output.top_left; - auto const& sz = conf_output.modes[conf_output.current_mode_index].size; out << ": " << position << '=' << tl.x << ',' << tl.y - << "; " << mode << '=' << sz.width << 'x' << sz.height; + << "; " << mode << '=' << conf_output.modes[conf_output.current_mode_index]; } out << " # " << type; From 7bf856273e63c67352232d7c91b3dcd15a2c8a2f Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 17 Aug 2018 17:08:22 +0100 Subject: [PATCH 08/34] Add optional "scale" property --- src/miral/display_configuration_option.cpp | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index aae9f0f15a3..abafaafc096 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -110,14 +110,16 @@ class StaticDisplayConfig : public mg::DisplayConfigurationPolicy using Id = std::tuple; struct Config { - mir::optional_value position; - mir::optional_value size; + mir::optional_value position; + mir::optional_value size; mir::optional_value refresh; + mir::optional_value scale; }; static constexpr char const* const output_id = "output_id"; static constexpr char const* const position = "position"; static constexpr char const* const mode = "mode"; + static constexpr char const* const scale = "scale"; std::map config; }; @@ -235,6 +237,15 @@ StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) output_config.refresh = refresh; } } + else if (property == scale) + { + double scale; + + if (!(in >> scale)) + goto error; + + output_config.scale = scale; + } else goto error; if (in >> std::ws, in >> delimiter && delimiter != ';') @@ -302,6 +313,11 @@ void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) } } } + + if (conf.scale.is_set()) + { + conf_output.scale = conf.scale.value(); + } } else { @@ -315,9 +331,9 @@ void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) if (conf_output.connected && conf_output.modes.size() > 0) { - auto const& tl = conf_output.top_left; - out << ": " << position << '=' << tl.x << ',' << tl.y - << "; " << mode << '=' << conf_output.modes[conf_output.current_mode_index]; + out << ": " << position << '=' << conf_output.top_left.x << ',' << conf_output.top_left.y + << "; " << mode << '=' << conf_output.modes[conf_output.current_mode_index] + << "; " << scale << '=' << conf_output.scale; } out << " # " << type; From 3d9791e31f2b147602e107903bb2b6ca31db4f38 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Mon, 20 Aug 2018 11:56:34 +0100 Subject: [PATCH 09/34] Remove support for "scale" (as it doesn't work) --- src/miral/display_configuration_option.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index abafaafc096..9ed8e5501c3 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -30,6 +30,9 @@ #include #include +// Scale is not supported when compositing. https://github.com/MirServer/mir/issues/552 +#define MIR_SCALE_NOT_SUPPORTED + namespace mg = mir::graphics; using namespace mir::geometry; @@ -237,6 +240,7 @@ StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) output_config.refresh = refresh; } } +#ifndef MIR_SCALE_NOT_SUPPORTED else if (property == scale) { double scale; @@ -246,6 +250,7 @@ StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) output_config.scale = scale; } +#endif else goto error; if (in >> std::ws, in >> delimiter && delimiter != ';') @@ -333,7 +338,10 @@ void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) { out << ": " << position << '=' << conf_output.top_left.x << ',' << conf_output.top_left.y << "; " << mode << '=' << conf_output.modes[conf_output.current_mode_index] - << "; " << scale << '=' << conf_output.scale; +#ifndef MIR_SCALE_NOT_SUPPORTED + << "; " << scale << '=' << conf_output.scale +#endif + ; } out << " # " << type; From bffc762cc71a8f9038a1e014457591f4d66e4531 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Mon, 20 Aug 2018 13:08:48 +0100 Subject: [PATCH 10/34] Add "orientation" property --- src/miral/display_configuration_option.cpp | 92 ++++++++++++++++------ 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index 9ed8e5501c3..ed1f40b7e08 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -117,16 +117,43 @@ class StaticDisplayConfig : public mg::DisplayConfigurationPolicy mir::optional_value size; mir::optional_value refresh; mir::optional_value scale; + mir::optional_value orientation; }; static constexpr char const* const output_id = "output_id"; static constexpr char const* const position = "position"; static constexpr char const* const mode = "mode"; static constexpr char const* const scale = "scale"; + static constexpr char const* const orientation = "orientation"; + std::map config; + + static constexpr char const* const orientation_value[] = + { "normal", "left", "inverted", "right" }; + + static auto as_string(MirOrientation orientation) -> char const* + { + return orientation_value[orientation/90]; + } + + static auto as_orientation(std::string const& orientation) -> MirOrientation + { + if (orientation == orientation_value[3]) + return mir_orientation_right; + + if (orientation == orientation_value[2]) + return mir_orientation_inverted; + + if (orientation == orientation_value[1]) + return mir_orientation_left; + + return mir_orientation_normal; + } }; +constexpr char const* const StaticDisplayConfig::orientation_value[]; + size_t select_mode_index(size_t mode_index, std::vector const & modes) { if (modes.empty()) @@ -251,6 +278,16 @@ StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) output_config.scale = scale; } #endif + else if (property == orientation) + { + std::string orientation; + + if (!(in >> std::ws, std::getline(in, orientation, ';'))) + goto error; + + puts(orientation.c_str()); + output_config.orientation = as_orientation(orientation); + } else goto error; if (in >> std::ws, in >> delimiter && delimiter != ';') @@ -311,7 +348,7 @@ void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) } } else if (conf_output.modes[conf_output.current_mode_index].size != conf.size.value() - || conf_output.modes[conf_output.current_mode_index].vrefresh_hz < mode->vrefresh_hz) + || conf_output.modes[conf_output.current_mode_index].vrefresh_hz < mode->vrefresh_hz) { conf_output.current_mode_index = distance(begin(conf_output.modes), mode); } @@ -323,6 +360,11 @@ void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) { conf_output.scale = conf.scale.value(); } + + if (conf.orientation.is_set()) + { + conf_output.orientation = conf.orientation.value(); + } } else { @@ -330,34 +372,34 @@ void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) conf_output.power_mode = mir_power_mode_off; } - auto const type = mir_output_type_name(static_cast(conf_output.type)); + auto const type = mir_output_type_name(static_cast(conf_output.type)); - out << '\n' << output_id << '=' << conf_output.card_id << '/' << conf_output.id; + out << '\n' << output_id << '=' << conf_output.card_id << '/' << conf_output.id; - if (conf_output.connected && conf_output.modes.size() > 0) - { - out << ": " << position << '=' << conf_output.top_left.x << ',' << conf_output.top_left.y - << "; " << mode << '=' << conf_output.modes[conf_output.current_mode_index] + if (conf_output.connected && conf_output.modes.size() > 0) + { + out << ": " << position << '=' << conf_output.top_left.x << ',' << conf_output.top_left.y + << "; " << mode << '=' << conf_output.modes[conf_output.current_mode_index] #ifndef MIR_SCALE_NOT_SUPPORTED - << "; " << scale << '=' << conf_output.scale + << "; " << scale << '=' << conf_output.scale #endif - ; - } - - out << " # " << type; - - if (!conf_output.connected || conf_output.modes.size() <= 0) - out << " (disconnected)"; - - if (conf_output.modes.size() > 0) - { - out << " modes: "; - for (size_t i = 0; i < conf_output.modes.size(); ++i) - { - if (i) out << ", "; - out << conf_output.modes[i]; - } - } + << "; " << orientation << '=' << as_string(conf_output.orientation); + } + + out << " # " << type; + + if (!conf_output.connected || conf_output.modes.size() <= 0) + out << " (disconnected)"; + + if (conf_output.modes.size() > 0) + { + out << " modes: "; + for (size_t i = 0; i < conf_output.modes.size(); ++i) + { + if (i) out << ", "; + out << conf_output.modes[i]; + } + } }); out << "\n8>< ---------------------------------------------------"; From fa7eb546612852a3435d44607c42fd4988317428 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Mon, 20 Aug 2018 13:48:19 +0100 Subject: [PATCH 11/34] Fix FTBFS with clang --- src/miral/display_configuration_option.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index ed1f40b7e08..6db47be6c9a 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -123,7 +123,9 @@ class StaticDisplayConfig : public mg::DisplayConfigurationPolicy static constexpr char const* const output_id = "output_id"; static constexpr char const* const position = "position"; static constexpr char const* const mode = "mode"; +#ifndef MIR_SCALE_NOT_SUPPORTED static constexpr char const* const scale = "scale"; +#endif static constexpr char const* const orientation = "orientation"; From 48875d55e8c64dd8ef31524a8b6564e6df737c52 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Tue, 21 Aug 2018 10:46:54 +0100 Subject: [PATCH 12/34] Split StaticDisplayConfig into its own files --- debian/control | 3 +- src/miral/CMakeLists.txt | 1 + src/miral/display_configuration_option.cpp | 318 +-------------------- src/miral/static_display_config.cpp | 284 ++++++++++++++++++ src/miral/static_display_config.h | 85 ++++++ 5 files changed, 373 insertions(+), 318 deletions(-) create mode 100644 src/miral/static_display_config.cpp create mode 100644 src/miral/static_display_config.h diff --git a/debian/control b/debian/control index 23b64673eb4..6bd2a84807e 100644 --- a/debian/control +++ b/debian/control @@ -54,7 +54,8 @@ Build-Depends: cmake, libxcb-xfixes0-dev, libxcb-render0-dev, libxcb-composite0-dev, - libxcursor-dev + libxcursor-dev, + libyaml-cpp-dev Standards-Version: 3.9.4 Homepage: https://launchpad.net/mir # If you aren't a member of ~mir-team but need to upload packaging changes, diff --git a/src/miral/CMakeLists.txt b/src/miral/CMakeLists.txt index 46a7dbb7841..96ae4665187 100644 --- a/src/miral/CMakeLists.txt +++ b/src/miral/CMakeLists.txt @@ -20,6 +20,7 @@ add_library(miral-internal STATIC display_configuration_listeners.cpp display_configuration_listeners.h launch_app.cpp launch_app.h mru_window_list.cpp mru_window_list.h + static_display_config.cpp static_display_config.h window_management_trace.cpp window_management_trace.h xcursor_loader.cpp xcursor_loader.h xcursor.c xcursor.h diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index 6db47be6c9a..8aa995abb13 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -17,21 +17,12 @@ */ #include "miral/display_configuration_option.h" +#include "static_display_config.h" -#include #include #include -#include #include #include -#include - -#include -#include -#include - -// Scale is not supported when compositing. https://github.com/MirServer/mir/issues/552 -#define MIR_SCALE_NOT_SUPPORTED namespace mg = mir::graphics; using namespace mir::geometry; @@ -101,313 +92,6 @@ void PixelFormatSelector::apply_to(mg::DisplayConfiguration& conf) }); } -namespace -{ -class StaticDisplayConfig : public mg::DisplayConfigurationPolicy -{ -public: - StaticDisplayConfig(std::string const& filename); - virtual void apply_to(mg::DisplayConfiguration& conf); -private: - - using Id = std::tuple; - struct Config - { - mir::optional_value position; - mir::optional_value size; - mir::optional_value refresh; - mir::optional_value scale; - mir::optional_value orientation; - }; - - static constexpr char const* const output_id = "output_id"; - static constexpr char const* const position = "position"; - static constexpr char const* const mode = "mode"; -#ifndef MIR_SCALE_NOT_SUPPORTED - static constexpr char const* const scale = "scale"; -#endif - static constexpr char const* const orientation = "orientation"; - - - std::map config; - - static constexpr char const* const orientation_value[] = - { "normal", "left", "inverted", "right" }; - - static auto as_string(MirOrientation orientation) -> char const* - { - return orientation_value[orientation/90]; - } - - static auto as_orientation(std::string const& orientation) -> MirOrientation - { - if (orientation == orientation_value[3]) - return mir_orientation_right; - - if (orientation == orientation_value[2]) - return mir_orientation_inverted; - - if (orientation == orientation_value[1]) - return mir_orientation_left; - - return mir_orientation_normal; - } -}; - -constexpr char const* const StaticDisplayConfig::orientation_value[]; - -size_t select_mode_index(size_t mode_index, std::vector const & modes) -{ - if (modes.empty()) - return std::numeric_limits::max(); - - if (mode_index >= modes.size()) - return 0; - - return mode_index; -} -} - -StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) -{ - std::ifstream config_file{filename}; - - if (!config_file) - { - mir::log_warning("Cannot read static display configuration file: '" + filename + "'"); - return; - } - - int line_count = 0; - std::string line; - std::istringstream in; - - while (std::getline(config_file, line)) - { - ++line_count; - - // Strip trailing comment - line.erase(find(begin(line), end(line), '#'), end(line)); - - // Ignore blank lines - if (line.empty()) - continue; - - in = std::istringstream{line}; - in.setf(std::ios::skipws); - - std::string property; - - in >> std::ws; - std::getline(in, property, '='); - - if (property != output_id) - goto error; - - int card_no = -1; - int port_no = -1; - char delimiter = '\0'; - - if (!(in >> card_no)) - goto error; - - if (!(in >> delimiter) || delimiter != '/') - goto error; - - if (!(in >> port_no)) - goto error; - - Id const output_id{mg::DisplayConfigurationCardId{card_no}, mg::DisplayConfigurationOutputId{port_no}}; - Config output_config; - - if (in >> delimiter && delimiter != ':') - goto error; - - while (in >> std::ws, std::getline(in, property, '=')) - { - if (property == position) - { - int x; - int y; - - if (!(in >> x)) - goto error; - - if (!(in >> delimiter) || delimiter != ',') - goto error; - - if (!(in >> y)) - goto error; - - output_config.position = Point{x, y}; - } - else if (property == mode) - { - int width; - int height; - - if (!(in >> width)) - goto error; - - if (!(in >> delimiter) || delimiter != 'x') - goto error; - - if (!(in >> height)) - goto error; - - output_config.size = Size{width, height}; - - if (in.peek() == '@') - { - double refresh; - if (!(in >> delimiter) || delimiter != '@') - goto error; - - if (!(in >> refresh)) - goto error; - - output_config.refresh = refresh; - } - } -#ifndef MIR_SCALE_NOT_SUPPORTED - else if (property == scale) - { - double scale; - - if (!(in >> scale)) - goto error; - - output_config.scale = scale; - } -#endif - else if (property == orientation) - { - std::string orientation; - - if (!(in >> std::ws, std::getline(in, orientation, ';'))) - goto error; - - puts(orientation.c_str()); - output_config.orientation = as_orientation(orientation); - } - else goto error; - - if (in >> std::ws, in >> delimiter && delimiter != ';') - goto error; - } - - config[output_id] = output_config; - } - - return; - -error: - std::string error; - getline(in, error); - throw mir::AbnormalExit{"ERROR: Syntax error in display configuration file: '" + filename + - "' line: " + std::to_string(line_count) + - " before: '" + error + "'"}; -} - -void StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) -{ - std::ostringstream out; - out << "Display config:\n8>< ---------------------------------------------------"; - - conf.for_each_output([&](mg::UserDisplayConfigurationOutput& conf_output) - { - if (conf_output.connected && conf_output.modes.size() > 0) - { - conf_output.used = true; - conf_output.power_mode = mir_power_mode_on; - conf_output.orientation = mir_orientation_normal; - - auto& conf = config[Id{conf_output.card_id, conf_output.id}]; - - if (conf.position.is_set()) - { - conf_output.top_left = conf.position.value(); - } - else - { - conf_output.top_left = Point{0, 0}; - } - - size_t preferred_mode_index{select_mode_index(conf_output.preferred_mode_index, conf_output.modes)}; - conf_output.current_mode_index = preferred_mode_index; - - if (conf.size.is_set()) - { - for (auto mode = begin(conf_output.modes); mode != end(conf_output.modes); ++mode) - { - if (mode->size == conf.size.value()) - { - if (conf.refresh.is_set()) - { - if (abs(conf.refresh.value() - mode->vrefresh_hz) < 1.0) - { - conf_output.current_mode_index = distance(begin(conf_output.modes), mode); - } - } - else if (conf_output.modes[conf_output.current_mode_index].size != conf.size.value() - || conf_output.modes[conf_output.current_mode_index].vrefresh_hz < mode->vrefresh_hz) - { - conf_output.current_mode_index = distance(begin(conf_output.modes), mode); - } - } - } - } - - if (conf.scale.is_set()) - { - conf_output.scale = conf.scale.value(); - } - - if (conf.orientation.is_set()) - { - conf_output.orientation = conf.orientation.value(); - } - } - else - { - conf_output.used = false; - conf_output.power_mode = mir_power_mode_off; - } - - auto const type = mir_output_type_name(static_cast(conf_output.type)); - - out << '\n' << output_id << '=' << conf_output.card_id << '/' << conf_output.id; - - if (conf_output.connected && conf_output.modes.size() > 0) - { - out << ": " << position << '=' << conf_output.top_left.x << ',' << conf_output.top_left.y - << "; " << mode << '=' << conf_output.modes[conf_output.current_mode_index] -#ifndef MIR_SCALE_NOT_SUPPORTED - << "; " << scale << '=' << conf_output.scale -#endif - << "; " << orientation << '=' << as_string(conf_output.orientation); - } - - out << " # " << type; - - if (!conf_output.connected || conf_output.modes.size() <= 0) - out << " (disconnected)"; - - if (conf_output.modes.size() > 0) - { - out << " modes: "; - for (size_t i = 0; i < conf_output.modes.size(); ++i) - { - if (i) out << ", "; - out << conf_output.modes[i]; - } - } - }); - - out << "\n8>< ---------------------------------------------------"; - mir::log_info(out.str()); -} - void miral::display_configuration_options(mir::Server& server) { // Add choice of monitor configuration diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp new file mode 100644 index 00000000000..d65e5a242da --- /dev/null +++ b/src/miral/static_display_config.cpp @@ -0,0 +1,284 @@ +/* + * Copyright © 2018 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authored by: Alan Griffiths + */ + +#include "static_display_config.h" + +#include + +#include + +#include +#include +#include + +namespace mg = mir::graphics; +using namespace mir::geometry; + +constexpr char const* const miral::StaticDisplayConfig::orientation_value[]; + +size_t select_mode_index(size_t mode_index, std::vector const & modes) +{ + if (modes.empty()) + return std::numeric_limits::max(); + + if (mode_index >= modes.size()) + return 0; + + return mode_index; +} + +miral::StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) +{ + std::ifstream config_file{filename}; + + if (!config_file) + { + mir::log_warning("Cannot read static display configuration file: '" + filename + "'"); + return; + } + + int line_count = 0; + std::string line; + std::istringstream in; + + while (std::getline(config_file, line)) + { + ++line_count; + + // Strip trailing comment + line.erase(find(begin(line), end(line), '#'), end(line)); + + // Ignore blank lines + if (line.empty()) + continue; + + in = std::istringstream{line}; + in.setf(std::ios::skipws); + + std::string property; + + in >> std::ws; + std::getline(in, property, '='); + + if (property != output_id) + goto error; + + int card_no = -1; + int port_no = -1; + char delimiter = '\0'; + + if (!(in >> card_no)) + goto error; + + if (!(in >> delimiter) || delimiter != '/') + goto error; + + if (!(in >> port_no)) + goto error; + + Id const output_id{mg::DisplayConfigurationCardId{card_no}, mg::DisplayConfigurationOutputId{port_no}}; + Config output_config; + + if (in >> delimiter && delimiter != ':') + goto error; + + while (in >> std::ws, std::getline(in, property, '=')) + { + if (property == position) + { + int x; + int y; + + if (!(in >> x)) + goto error; + + if (!(in >> delimiter) || delimiter != ',') + goto error; + + if (!(in >> y)) + goto error; + + output_config.position = Point{x, y}; + } + else if (property == mode) + { + int width; + int height; + + if (!(in >> width)) + goto error; + + if (!(in >> delimiter) || delimiter != 'x') + goto error; + + if (!(in >> height)) + goto error; + + output_config.size = Size{width, height}; + + if (in.peek() == '@') + { + double refresh; + if (!(in >> delimiter) || delimiter != '@') + goto error; + + if (!(in >> refresh)) + goto error; + + output_config.refresh = refresh; + } + } +#ifndef MIR_SCALE_NOT_SUPPORTED + else if (property == scale) + { + double scale; + + if (!(in >> scale)) + goto error; + + output_config.scale = scale; + } +#endif + else if (property == orientation) + { + std::string orientation; + + if (!(in >> std::ws, std::getline(in, orientation, ';'))) + goto error; + + puts(orientation.c_str()); + output_config.orientation = as_orientation(orientation); + } + else goto error; + + if (in >> std::ws, in >> delimiter && delimiter != ';') + goto error; + } + + config[output_id] = output_config; + } + + return; + +error: + std::string error; + getline(in, error); + throw mir::AbnormalExit{"ERROR: Syntax error in display configuration file: '" + filename + + "' line: " + std::to_string(line_count) + + " before: '" + error + "'"}; +} + +void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) +{ + std::ostringstream out; + out << "Display config:\n8>< ---------------------------------------------------"; + + conf.for_each_output([&](mg::UserDisplayConfigurationOutput& conf_output) + { + if (conf_output.connected && conf_output.modes.size() > 0) + { + conf_output.used = true; + conf_output.power_mode = mir_power_mode_on; + conf_output.orientation = mir_orientation_normal; + + auto& conf = config[Id{conf_output.card_id, conf_output.id}]; + + if (conf.position.is_set()) + { + conf_output.top_left = conf.position.value(); + } + else + { + conf_output.top_left = Point{0, 0}; + } + + size_t preferred_mode_index{select_mode_index(conf_output.preferred_mode_index, conf_output.modes)}; + conf_output.current_mode_index = preferred_mode_index; + + if (conf.size.is_set()) + { + for (auto mode = begin(conf_output.modes); mode != end(conf_output.modes); ++mode) + { + if (mode->size == conf.size.value()) + { + if (conf.refresh.is_set()) + { + if (abs(conf.refresh.value() - mode->vrefresh_hz) < 1.0) + { + conf_output.current_mode_index = distance(begin(conf_output.modes), mode); + } + } + else if (conf_output.modes[conf_output.current_mode_index].size != conf.size.value() + || conf_output.modes[conf_output.current_mode_index].vrefresh_hz < mode->vrefresh_hz) + { + conf_output.current_mode_index = distance(begin(conf_output.modes), mode); + } + } + } + } + + if (conf.scale.is_set()) + { + conf_output.scale = conf.scale.value(); + } + + if (conf.orientation.is_set()) + { + conf_output.orientation = conf.orientation.value(); + } + } + else + { + conf_output.used = false; + conf_output.power_mode = mir_power_mode_off; + } + + auto const type = mir_output_type_name(static_cast(conf_output.type)); + + out << '\n' << output_id << '=' << conf_output.card_id << '/' << conf_output.id; + + if (conf_output.connected && conf_output.modes.size() > 0) + { + out << ": " << position << '=' << conf_output.top_left.x << ',' << conf_output.top_left.y + << "; " << mode << '=' << conf_output.modes[conf_output.current_mode_index] +#ifndef MIR_SCALE_NOT_SUPPORTED + << "; " << scale << '=' << conf_output.scale +#endif + << "; " << orientation << '=' << as_string(conf_output.orientation); + } + + out << " # " << type; + + if (!conf_output.connected || conf_output.modes.size() <= 0) + out << " (disconnected)"; + + if (conf_output.modes.size() > 0) + { + out << " modes: "; + for (size_t i = 0; i < conf_output.modes.size(); ++i) + { + if (i) out << ", "; + out << conf_output.modes[i]; + } + } + }); + + out << "\n8>< ---------------------------------------------------"; + mir::log_info(out.str()); +} + diff --git a/src/miral/static_display_config.h b/src/miral/static_display_config.h new file mode 100644 index 00000000000..f3e07114495 --- /dev/null +++ b/src/miral/static_display_config.h @@ -0,0 +1,85 @@ +/* + * Copyright © 2018 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authored by: Alan Griffiths + */ + +#ifndef MIRAL_STATIC_DISPLAY_CONFIG_H_ +#define MIRAL_STATIC_DISPLAY_CONFIG_H_ + +#include +#include +#include + +#include + +// Scale is not supported when compositing. https://github.com/MirServer/mir/issues/552 +#define MIR_SCALE_NOT_SUPPORTED + +namespace miral +{ +class StaticDisplayConfig : public mir::graphics::DisplayConfigurationPolicy +{ +public: + StaticDisplayConfig(std::string const& filename); + virtual void apply_to(mir::graphics::DisplayConfiguration& conf); +private: + + using Id = std::tuple; + struct Config + { + mir::optional_value position; + mir::optional_value size; + mir::optional_value refresh; + mir::optional_value scale; + mir::optional_value orientation; + }; + + static constexpr char const* const output_id = "output_id"; + static constexpr char const* const position = "position"; + static constexpr char const* const mode = "mode"; +#ifndef MIR_SCALE_NOT_SUPPORTED + static constexpr char const* const scale = "scale"; +#endif + static constexpr char const* const orientation = "orientation"; + + + std::map config; + + static constexpr char const* const orientation_value[] = + { "normal", "left", "inverted", "right" }; + + static auto as_string(MirOrientation orientation) -> char const* + { + return orientation_value[orientation/90]; + } + + static auto as_orientation(std::string const& orientation) -> MirOrientation + { + if (orientation == orientation_value[3]) + return mir_orientation_right; + + if (orientation == orientation_value[2]) + return mir_orientation_inverted; + + if (orientation == orientation_value[1]) + return mir_orientation_left; + + return mir_orientation_normal; + } +}; +} + +#endif //MIRAL_STATIC_DISPLAY_CONFIG_H_ From 59a7de9fe0fc515145b44c4171d8707dc6f53920 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Tue, 21 Aug 2018 10:50:46 +0100 Subject: [PATCH 13/34] Move implementation out of header --- src/miral/display_configuration_option.cpp | 2 -- src/miral/static_display_config.cpp | 37 +++++++++++++++++++++- src/miral/static_display_config.h | 34 -------------------- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index 8aa995abb13..864b4e7122e 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -25,7 +25,6 @@ #include namespace mg = mir::graphics; -using namespace mir::geometry; namespace { @@ -70,7 +69,6 @@ PixelFormatSelector::PixelFormatSelector( void PixelFormatSelector::apply_to(mg::DisplayConfiguration& conf) { base_policy->apply_to(conf); - conf.for_each_output( [&](mg::UserDisplayConfigurationOutput& conf_output) { diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index d65e5a242da..9cfc3d4636a 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -26,10 +26,45 @@ #include #include +// Scale is not supported when compositing. https://github.com/MirServer/mir/issues/552 +#define MIR_SCALE_NOT_SUPPORTED + namespace mg = mir::graphics; using namespace mir::geometry; -constexpr char const* const miral::StaticDisplayConfig::orientation_value[]; +namespace +{ +static constexpr char const* const output_id = "output_id"; +static constexpr char const* const position = "position"; +static constexpr char const* const mode = "mode"; +#ifndef MIR_SCALE_NOT_SUPPORTED +static constexpr char const* const scale = "scale"; +#endif +static constexpr char const* const orientation = "orientation"; + + +static constexpr char const* const orientation_value[] = + { "normal", "left", "inverted", "right" }; + +static auto as_string(MirOrientation orientation) -> char const* +{ + return orientation_value[orientation/90]; +} + +static auto as_orientation(std::string const& orientation) -> MirOrientation +{ + if (orientation == orientation_value[3]) + return mir_orientation_right; + + if (orientation == orientation_value[2]) + return mir_orientation_inverted; + + if (orientation == orientation_value[1]) + return mir_orientation_left; + + return mir_orientation_normal; +} +} size_t select_mode_index(size_t mode_index, std::vector const & modes) { diff --git a/src/miral/static_display_config.h b/src/miral/static_display_config.h index f3e07114495..4c4cbe7486f 100644 --- a/src/miral/static_display_config.h +++ b/src/miral/static_display_config.h @@ -25,9 +25,6 @@ #include -// Scale is not supported when compositing. https://github.com/MirServer/mir/issues/552 -#define MIR_SCALE_NOT_SUPPORTED - namespace miral { class StaticDisplayConfig : public mir::graphics::DisplayConfigurationPolicy @@ -47,38 +44,7 @@ class StaticDisplayConfig : public mir::graphics::DisplayConfigurationPolicy mir::optional_value orientation; }; - static constexpr char const* const output_id = "output_id"; - static constexpr char const* const position = "position"; - static constexpr char const* const mode = "mode"; -#ifndef MIR_SCALE_NOT_SUPPORTED - static constexpr char const* const scale = "scale"; -#endif - static constexpr char const* const orientation = "orientation"; - - std::map config; - - static constexpr char const* const orientation_value[] = - { "normal", "left", "inverted", "right" }; - - static auto as_string(MirOrientation orientation) -> char const* - { - return orientation_value[orientation/90]; - } - - static auto as_orientation(std::string const& orientation) -> MirOrientation - { - if (orientation == orientation_value[3]) - return mir_orientation_right; - - if (orientation == orientation_value[2]) - return mir_orientation_inverted; - - if (orientation == orientation_value[1]) - return mir_orientation_left; - - return mir_orientation_normal; - } }; } From 077d61e674d5bd417c1a65d519b62236d1d82993 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Tue, 21 Aug 2018 16:50:48 +0100 Subject: [PATCH 14/34] First cut at parsing YAML --- src/miral/CMakeLists.txt | 3 + src/miral/static_display_config.cpp | 203 ++++++++++++++-------------- 2 files changed, 105 insertions(+), 101 deletions(-) diff --git a/src/miral/CMakeLists.txt b/src/miral/CMakeLists.txt index 96ae4665187..b667549c208 100644 --- a/src/miral/CMakeLists.txt +++ b/src/miral/CMakeLists.txt @@ -9,6 +9,8 @@ set(MIRAL_ABI 3) set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map) set(miral_include ${PROJECT_SOURCE_DIR}/include/miral) +pkg_check_modules(YAML REQUIRED yaml-cpp) + add_library(mirclientcpp INTERFACE) add_definitions(-DMIR_LOG_COMPONENT_FALLBACK="miral") @@ -98,6 +100,7 @@ target_link_libraries(miral miral-internal mirserver ${WAYLAND_CLIENT_LDFLAGS} ${WAYLAND_CLIENT_LIBRARIES} + ${YAML_LIBRARIES} ) set_target_properties(miral diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 9cfc3d4636a..eb5be85c92b 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -22,9 +22,13 @@ #include + +#include "yaml-cpp/yaml.h" + #include #include #include +#include // Scale is not supported when compositing. https://github.com/MirServer/mir/issues/552 #define MIR_SCALE_NOT_SUPPORTED @@ -78,144 +82,141 @@ size_t select_mode_index(size_t mode_index, std::vector> std::ws; - std::getline(in, property, '='); + auto const layout_name = name_node.Scalar(); - if (property != output_id) - goto error; + std::cout << "layout_name: " << layout_name << '\n'; - int card_no = -1; - int port_no = -1; - char delimiter = '\0'; + Node displays = config_node["displays"]; - if (!(in >> card_no)) - goto error; + for (Node const card : displays) + { + int card_no = 0; - if (!(in >> delimiter) || delimiter != '/') - goto error; + if (auto const id = card["card-id"]) + { + card_no = id.as(); + } - if (!(in >> port_no)) - goto error; + std::cout << "Card #" << card_no << '\n'; - Id const output_id{mg::DisplayConfigurationCardId{card_no}, mg::DisplayConfigurationOutputId{port_no}}; - Config output_config; + for (std::pair port : card) + { + auto const port_name = port.first.Scalar(); - if (in >> delimiter && delimiter != ':') - goto error; + if (port_name == "card-id") + continue; - while (in >> std::ws, std::getline(in, property, '=')) - { - if (property == position) - { - int x; - int y; + std::cout << "Port: " << port_name << '\n'; - if (!(in >> x)) - goto error; + auto const& port_config = port.second; - if (!(in >> delimiter) || delimiter != ',') - goto error; + if (port_config.IsDefined()) + { + // TODO remove requirement for port field + if (auto const p = port_config["port"]) + { + puts("port"); + int const port_no = p.as(); + std::cout << "Port #" << port_no << '\n'; - if (!(in >> y)) - goto error; + Id const output_id{mg::DisplayConfigurationCardId{card_no}, mg::DisplayConfigurationOutputId{port_no}}; + Config output_config; - output_config.position = Point{x, y}; - } - else if (property == mode) - { - int width; - int height; + if (auto const pos = port_config[position]) + { + puts(position); + output_config.size = Size{pos[0].as(), pos[1].as()}; + } - if (!(in >> width)) - goto error; + if (auto const m = port_config[mode]) + { + puts(mode); + puts(m.as().c_str()); + std::istringstream in{m.as()}; - if (!(in >> delimiter) || delimiter != 'x') - goto error; + char delimiter = '\0'; + int width; + int height; - if (!(in >> height)) - goto error; + if (!(in >> width)) + goto mode_error; - output_config.size = Size{width, height}; + if (!(in >> delimiter) || delimiter != 'x') + goto mode_error; - if (in.peek() == '@') - { - double refresh; - if (!(in >> delimiter) || delimiter != '@') - goto error; + if (!(in >> height)) + goto mode_error; - if (!(in >> refresh)) - goto error; + output_config.size = Size{width, height}; - output_config.refresh = refresh; - } - } -#ifndef MIR_SCALE_NOT_SUPPORTED - else if (property == scale) - { - double scale; + if (in.peek() == '@') + { + double refresh; + if (!(in >> delimiter) || delimiter != '@') + goto mode_error; - if (!(in >> scale)) - goto error; + if (!(in >> refresh)) + goto mode_error; - output_config.scale = scale; - } -#endif - else if (property == orientation) - { - std::string orientation; + output_config.refresh = refresh; + } + } + mode_error: // TODO better error handling - if (!(in >> std::ws, std::getline(in, orientation, ';'))) - goto error; + if (auto const o = port_config[orientation]) + { + puts(orientation); + std::string const orientation = o.as(); + puts(orientation.c_str()); + output_config.orientation = as_orientation(orientation); + } - puts(orientation.c_str()); - output_config.orientation = as_orientation(orientation); + this->config[output_id] = output_config; + } + } } - else goto error; - - if (in >> std::ws, in >> delimiter && delimiter != ';') - goto error; } - - config[output_id] = output_config; } + puts("*********************************************************"); return; - -error: - std::string error; - getline(in, error); - throw mir::AbnormalExit{"ERROR: Syntax error in display configuration file: '" + filename + - "' line: " + std::to_string(line_count) + - " before: '" + error + "'"}; +} +catch (YAML::Exception const& x) +{ + throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + "' : " + x.what()}; } void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) From 7fd0329c900f86913b4cf7b027509442fc96bad9 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 16:04:55 +0100 Subject: [PATCH 15/34] Fixup --- src/miral/static_display_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index eb5be85c92b..98defe49d40 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -158,7 +158,7 @@ try if (auto const pos = port_config[position]) { puts(position); - output_config.size = Size{pos[0].as(), pos[1].as()}; + output_config.position = Point{pos[0].as(), pos[1].as()}; } if (auto const m = port_config[mode]) From 3f38bb4714ddbdf9e79b6530490d702fc780fb4c Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 12:19:34 +0100 Subject: [PATCH 16/34] Dump layout as yaml --- src/miral/static_display_config.cpp | 78 +++++++++++++++++------------ 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 98defe49d40..df334960430 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -30,32 +30,26 @@ #include #include -// Scale is not supported when compositing. https://github.com/MirServer/mir/issues/552 -#define MIR_SCALE_NOT_SUPPORTED - namespace mg = mir::graphics; using namespace mir::geometry; namespace { -static constexpr char const* const output_id = "output_id"; -static constexpr char const* const position = "position"; -static constexpr char const* const mode = "mode"; -#ifndef MIR_SCALE_NOT_SUPPORTED -static constexpr char const* const scale = "scale"; -#endif -static constexpr char const* const orientation = "orientation"; +constexpr char const* const output_id = "output_id"; +constexpr char const* const position = "position"; +constexpr char const* const mode = "mode"; +constexpr char const* const orientation = "orientation"; -static constexpr char const* const orientation_value[] = +constexpr char const* const orientation_value[] = { "normal", "left", "inverted", "right" }; -static auto as_string(MirOrientation orientation) -> char const* +auto as_string(MirOrientation orientation) -> char const* { return orientation_value[orientation/90]; } -static auto as_orientation(std::string const& orientation) -> MirOrientation +auto as_orientation(std::string const& orientation) -> MirOrientation { if (orientation == orientation_value[3]) return mir_orientation_right; @@ -221,11 +215,12 @@ catch (YAML::Exception const& x) void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) { - std::ostringstream out; - out << "Display config:\n8>< ---------------------------------------------------"; + std::map cardout; conf.for_each_output([&](mg::UserDisplayConfigurationOutput& conf_output) { + auto& out = cardout[conf_output.card_id]; + if (conf_output.connected && conf_output.modes.size() > 0) { conf_output.used = true; @@ -285,35 +280,52 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) } auto const type = mir_output_type_name(static_cast(conf_output.type)); + - out << '\n' << output_id << '=' << conf_output.card_id << '/' << conf_output.id; - - if (conf_output.connected && conf_output.modes.size() > 0) - { - out << ": " << position << '=' << conf_output.top_left.x << ',' << conf_output.top_left.y - << "; " << mode << '=' << conf_output.modes[conf_output.current_mode_index] -#ifndef MIR_SCALE_NOT_SUPPORTED - << "; " << scale << '=' << conf_output.scale -#endif - << "; " << orientation << '=' << as_string(conf_output.orientation); - } - - out << " # " << type; + out << "\n " << type; + if (conf_output.card_id.as_value() > 0) + out << '-' << conf_output.card_id.as_value(); + out << '-' << conf_output.id.as_value(); // TODO calculate correctly - if (!conf_output.connected || conf_output.modes.size() <= 0) - out << " (disconnected)"; + out << "\n port: " << conf_output.id.as_value(); // TODO obsolete - if (conf_output.modes.size() > 0) + if (conf_output.connected && conf_output.modes.size() > 0) { - out << " modes: "; for (size_t i = 0; i < conf_output.modes.size(); ++i) { - if (i) out << ", "; + if (i) out << ','; + if (i % 5) out << ' '; + else out << "\n # "; out << conf_output.modes[i]; } + out << "\n #mode: " << conf_output.modes[conf_output.current_mode_index]; + out << "\n #position: [" << conf_output.top_left.x << ',' << conf_output.top_left.y << ']'; + out << "\n #orientation: " << as_string(conf_output.orientation); + } + else + { + out << "\n # (disconnected)"; } }); + std::ostringstream out; + out << "Display config:\n8>< ---------------------------------------------------"; + out << "\nlayouts:"; + out << "\n# keys here are layout labels (used for atomically switching between them)"; + out << "\n# when enabling displays, surfaces should be matched in reverse recency order"; + out << "\n"; + out << "\n my-layout: # the first layout is the default"; + out << "\n"; + out << "\n displays:"; + out << "\n # a list of displays matched by card-id and output label"; + + for (auto& co : cardout) + { + out << "\n"; + out << "\n - card-id: " << co.first.as_value(); + out << co.second.str(); + } + out << "\n8>< ---------------------------------------------------"; mir::log_info(out.str()); } From b550205898c9240ce3efdf876435c0061adb18d1 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 12:42:29 +0100 Subject: [PATCH 17/34] Dump layout as yaml --- src/miral/static_display_config.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index df334960430..88b1ea792b1 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -285,27 +285,37 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) out << "\n " << type; if (conf_output.card_id.as_value() > 0) out << '-' << conf_output.card_id.as_value(); - out << '-' << conf_output.id.as_value(); // TODO calculate correctly + out << '-' << conf_output.id.as_value() << ':'; // TODO calculate correctly out << "\n port: " << conf_output.id.as_value(); // TODO obsolete if (conf_output.connected && conf_output.modes.size() > 0) { + out << "\n # This output supports the following modes:"; for (size_t i = 0; i < conf_output.modes.size(); ++i) { if (i) out << ','; - if (i % 5) out << ' '; + if ((i % 5) != 2) out << ' '; else out << "\n # "; out << conf_output.modes[i]; } - out << "\n #mode: " << conf_output.modes[conf_output.current_mode_index]; - out << "\n #position: [" << conf_output.top_left.x << ',' << conf_output.top_left.y << ']'; - out << "\n #orientation: " << as_string(conf_output.orientation); + out << "\n #"; + out << "\n # Uncomment the following to enforce the selected configuration." + "\n # Or amend as desired."; + out << "\n #"; + out << "\n #mode: " << conf_output.modes[conf_output.current_mode_index] + << "\t# Defaults to preferred mode"; + out << "\n #position: [" << conf_output.top_left.x << ", " << conf_output.top_left.y << ']' + << "\t# Defaults to [0, 0]"; + out << "\n #orientation: " << as_string(conf_output.orientation) + << "\t# {normal, left, right, inverted}, Defaults to normal"; } else { out << "\n # (disconnected)"; } + + out << "\n"; }); std::ostringstream out; @@ -326,7 +336,7 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) out << co.second.str(); } - out << "\n8>< ---------------------------------------------------"; + out << "8>< ---------------------------------------------------"; mir::log_info(out.str()); } From 9837cdb657527f2feaa338541b7acb1b0cec15b8 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 14:21:46 +0100 Subject: [PATCH 18/34] Rudimentary error handling --- src/miral/static_display_config.cpp | 58 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 88b1ea792b1..405e0fad869 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -82,26 +82,24 @@ try using std::begin; using std::end; - auto const config = LoadFile(filename); - if (!config.IsDefined()) - puts("!config.IsDefined()"); + std::ifstream config_file{filename}; - Node layouts = config["layouts"]; - if (!layouts.IsDefined()) - puts("!layouts.IsDefined()"); - - switch (layouts.Type()) + if (!config_file) { - case NodeType::Null: puts("layouts:Null"); break; - case NodeType::Scalar: puts("layouts:Scalar"); break; - case NodeType::Sequence: puts("layouts:Sequence"); break; - case NodeType::Map: puts("layouts:Map"); break; - case NodeType::Undefined: puts("layouts:Undefined"); break; + mir::log_warning("Cannot read static display configuration file: '" + filename + "'"); + return; } + auto const config = Load(config_file); + if (!config.IsDefined() || !config.IsMap()) + throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + "' : unrecognized content"}; + + Node layouts = config["layouts"]; + if (!layouts.IsDefined() || !layouts.IsMap()) + throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + "' : no layouts"}; + auto const layout = begin(config["layouts"]); - puts("*********************************************************"); if (layout != end(config["layouts"])) { Node name_node; @@ -109,13 +107,17 @@ try std::tie(name_node, config_node) = *layout; - auto const layout_name = name_node.Scalar(); + if (!config_node.IsDefined() || !config_node.IsMap()) + throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + + "' : invalid layout: " + name_node.Scalar()}; - std::cout << "layout_name: " << layout_name << '\n'; + Node cards = config_node["displays"]; - Node displays = config_node["displays"]; + if (!cards.IsDefined() || !cards.IsSequence()) + throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + + "' : invalid 'displays' in " + name_node.Scalar()}; - for (Node const card : displays) + for (Node const card : cards) { int card_no = 0; @@ -124,7 +126,9 @@ try card_no = id.as(); } - std::cout << "Card #" << card_no << '\n'; + if (!card.IsDefined() || !(card.IsMap() || card.IsNull())) + throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + + "' : invalid card: " + std::to_string(card_no)}; for (std::pair port : card) { @@ -133,32 +137,29 @@ try if (port_name == "card-id") continue; - std::cout << "Port: " << port_name << '\n'; - auto const& port_config = port.second; if (port_config.IsDefined()) { + if (!port_config.IsDefined() || !port_config.IsMap()) + throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + + "' : invalid card: " + std::to_string(card_no)}; + // TODO remove requirement for port field if (auto const p = port_config["port"]) { - puts("port"); int const port_no = p.as(); - std::cout << "Port #" << port_no << '\n'; Id const output_id{mg::DisplayConfigurationCardId{card_no}, mg::DisplayConfigurationOutputId{port_no}}; Config output_config; if (auto const pos = port_config[position]) { - puts(position); output_config.position = Point{pos[0].as(), pos[1].as()}; } if (auto const m = port_config[mode]) { - puts(mode); - puts(m.as().c_str()); std::istringstream in{m.as()}; char delimiter = '\0'; @@ -192,9 +193,7 @@ try if (auto const o = port_config[orientation]) { - puts(orientation); std::string const orientation = o.as(); - puts(orientation.c_str()); output_config.orientation = as_orientation(orientation); } @@ -204,9 +203,6 @@ try } } } - puts("*********************************************************"); - - return; } catch (YAML::Exception const& x) { From 6e822536f401b00924ceb5999b1752113d00a5d9 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 14:36:24 +0100 Subject: [PATCH 19/34] Number ports within output type --- src/miral/static_display_config.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 405e0fad869..0325373cbbe 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -211,11 +211,17 @@ catch (YAML::Exception const& x) void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) { - std::map cardout; + struct card_data + { + std::ostringstream out; + std::map output_counts; + }; + std::map card_map; conf.for_each_output([&](mg::UserDisplayConfigurationOutput& conf_output) { - auto& out = cardout[conf_output.card_id]; + auto& card_data = card_map[conf_output.card_id]; + auto& out = card_data.out; if (conf_output.connected && conf_output.modes.size() > 0) { @@ -275,13 +281,12 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) conf_output.power_mode = mir_power_mode_off; } - auto const type = mir_output_type_name(static_cast(conf_output.type)); - + auto const type = static_cast(conf_output.type); - out << "\n " << type; + out << "\n " << mir_output_type_name(type); if (conf_output.card_id.as_value() > 0) out << '-' << conf_output.card_id.as_value(); - out << '-' << conf_output.id.as_value() << ':'; // TODO calculate correctly + out << '-' << ++card_data.output_counts[type] << ':'; out << "\n port: " << conf_output.id.as_value(); // TODO obsolete @@ -325,11 +330,11 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) out << "\n displays:"; out << "\n # a list of displays matched by card-id and output label"; - for (auto& co : cardout) + for (auto& co : card_map) { out << "\n"; out << "\n - card-id: " << co.first.as_value(); - out << co.second.str(); + out << co.second.out.str(); } out << "8>< ---------------------------------------------------"; From 1491daabcfb0834984d19449e6c0a8c6ee2c4be0 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 15:30:41 +0100 Subject: [PATCH 20/34] Eliminate port index within card --- src/miral/static_display_config.cpp | 139 +++++++++++++++++----------- src/miral/static_display_config.h | 2 +- 2 files changed, 87 insertions(+), 54 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 0325373cbbe..1a36ca406c5 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -40,7 +40,6 @@ constexpr char const* const position = "position"; constexpr char const* const mode = "mode"; constexpr char const* const orientation = "orientation"; - constexpr char const* const orientation_value[] = { "normal", "left", "inverted", "right" }; @@ -62,6 +61,48 @@ auto as_orientation(std::string const& orientation) -> MirOrientation return mir_orientation_normal; } + +auto output_type_from(std::string const& output) -> MirOutputType +{ + static const char * const names[] = + { + "unknown", + "VGA", + "DVI-I", + "DVI-D", + "DVI-A", + "Composite", + "S-video", + "LVDS", + "Component", + "9-pin", + "DisplayPort", + "HDMI-A", + "HDMI-B", + "TV", + "eDP", + "Virtual", + "DSI", + "DPI", + }; + + int index = 0; + for (auto const name : names) + { + if (output.find(name) == 0) + return static_cast(index); + ++index; + } + return mir_output_type_unknown; +} + +auto output_index_from(std::string const& output) -> int +{ + std::istringstream in{output.substr(output.rfind('-')+1)}; + int result = 0; + in >> result; + return result; +} } size_t select_mode_index(size_t mode_index, std::vector const & modes) @@ -119,16 +160,16 @@ try for (Node const card : cards) { - int card_no = 0; + mg::DisplayConfigurationCardId card_no; if (auto const id = card["card-id"]) { - card_no = id.as(); + card_no = mg::DisplayConfigurationCardId{id.as()}; } if (!card.IsDefined() || !(card.IsMap() || card.IsNull())) throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + - "' : invalid card: " + std::to_string(card_no)}; + "' : invalid card: " + std::to_string(card_no.as_value())}; for (std::pair port : card) { @@ -139,66 +180,60 @@ try auto const& port_config = port.second; - if (port_config.IsDefined()) + if (port_config.IsDefined() && !port_config.IsNull()) { - if (!port_config.IsDefined() || !port_config.IsMap()) + if (!port_config.IsMap()) throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + - "' : invalid card: " + std::to_string(card_no)}; + "' : invalid port: " + port_name}; + + Id const output_id{card_no, output_type_from(port_name), output_index_from(port_name)}; + Config output_config; - // TODO remove requirement for port field - if (auto const p = port_config["port"]) + if (auto const pos = port_config[position]) { - int const port_no = p.as(); + output_config.position = Point{pos[0].as(), pos[1].as()}; + } - Id const output_id{mg::DisplayConfigurationCardId{card_no}, mg::DisplayConfigurationOutputId{port_no}}; - Config output_config; + if (auto const m = port_config[mode]) + { + std::istringstream in{m.as()}; - if (auto const pos = port_config[position]) - { - output_config.position = Point{pos[0].as(), pos[1].as()}; - } + char delimiter = '\0'; + int width; + int height; - if (auto const m = port_config[mode]) - { - std::istringstream in{m.as()}; + if (!(in >> width)) + goto mode_error; - char delimiter = '\0'; - int width; - int height; + if (!(in >> delimiter) || delimiter != 'x') + goto mode_error; - if (!(in >> width)) - goto mode_error; + if (!(in >> height)) + goto mode_error; - if (!(in >> delimiter) || delimiter != 'x') - goto mode_error; + output_config.size = Size{width, height}; - if (!(in >> height)) + if (in.peek() == '@') + { + double refresh; + if (!(in >> delimiter) || delimiter != '@') goto mode_error; - output_config.size = Size{width, height}; - - if (in.peek() == '@') - { - double refresh; - if (!(in >> delimiter) || delimiter != '@') - goto mode_error; - - if (!(in >> refresh)) - goto mode_error; + if (!(in >> refresh)) + goto mode_error; - output_config.refresh = refresh; - } - } - mode_error: // TODO better error handling - - if (auto const o = port_config[orientation]) - { - std::string const orientation = o.as(); - output_config.orientation = as_orientation(orientation); + output_config.refresh = refresh; } + } + mode_error: // TODO better error handling - this->config[output_id] = output_config; + if (auto const o = port_config[orientation]) + { + std::string const orientation = o.as(); + output_config.orientation = as_orientation(orientation); } + + this->config[output_id] = output_config; } } } @@ -222,6 +257,8 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) { auto& card_data = card_map[conf_output.card_id]; auto& out = card_data.out; + auto const type = static_cast(conf_output.type); + auto const index_by_type = ++card_data.output_counts[type]; if (conf_output.connected && conf_output.modes.size() > 0) { @@ -229,7 +266,7 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) conf_output.power_mode = mir_power_mode_on; conf_output.orientation = mir_orientation_normal; - auto& conf = config[Id{conf_output.card_id, conf_output.id}]; + auto& conf = config[Id{conf_output.card_id, type, index_by_type}]; if (conf.position.is_set()) { @@ -281,14 +318,10 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) conf_output.power_mode = mir_power_mode_off; } - auto const type = static_cast(conf_output.type); - out << "\n " << mir_output_type_name(type); if (conf_output.card_id.as_value() > 0) out << '-' << conf_output.card_id.as_value(); - out << '-' << ++card_data.output_counts[type] << ':'; - - out << "\n port: " << conf_output.id.as_value(); // TODO obsolete + out << '-' << index_by_type << ':'; if (conf_output.connected && conf_output.modes.size() > 0) { diff --git a/src/miral/static_display_config.h b/src/miral/static_display_config.h index 4c4cbe7486f..5b11c691562 100644 --- a/src/miral/static_display_config.h +++ b/src/miral/static_display_config.h @@ -34,7 +34,7 @@ class StaticDisplayConfig : public mir::graphics::DisplayConfigurationPolicy virtual void apply_to(mir::graphics::DisplayConfiguration& conf); private: - using Id = std::tuple; + using Id = std::tuple; struct Config { mir::optional_value position; From 817d31c5dc403c1460eec62deff15b7c476084a5 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 16:05:45 +0100 Subject: [PATCH 21/34] Change "displays" tag to more intuitive "cards" --- src/miral/static_display_config.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 1a36ca406c5..efa0b265a2d 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -152,11 +152,11 @@ try throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + "' : invalid layout: " + name_node.Scalar()}; - Node cards = config_node["displays"]; + Node cards = config_node["cards"]; if (!cards.IsDefined() || !cards.IsSequence()) throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + - "' : invalid 'displays' in " + name_node.Scalar()}; + "' : invalid 'cards' in " + name_node.Scalar()}; for (Node const card : cards) { @@ -360,8 +360,8 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) out << "\n"; out << "\n my-layout: # the first layout is the default"; out << "\n"; - out << "\n displays:"; - out << "\n # a list of displays matched by card-id and output label"; + out << "\n cards:"; + out << "\n # a list of cards (currently matched by card-id)"; for (auto& co : card_map) { From aed3c7dbe7676dc1bf818a27771cbd63ab60d885 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 17:12:56 +0100 Subject: [PATCH 22/34] Fix Fedora dependencies --- spread/build/fedora/task.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spread/build/fedora/task.yaml b/spread/build/fedora/task.yaml index 139d7a5d27a..ddf143e73fa 100644 --- a/spread/build/fedora/task.yaml +++ b/spread/build/fedora/task.yaml @@ -50,7 +50,8 @@ execute: | python3-gobject-base \ python3-dbus \ mesa-libwayland-egl-devel\ - libXcursor-devel + libXcursor-devel \ + yaml-cpp-devel BUILD_DIR=$(mktemp --directory) cmake -H$SPREAD_PATH -B$BUILD_DIR -DCMAKE_BUILD_TYPE=Debug -DMIR_USE_LD_GOLD=ON From 1a1e8c22dcc10bfeaabf3d75eed74929bb1aaadf Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 17:17:16 +0100 Subject: [PATCH 23/34] Fix clang FTBFS --- src/miral/static_display_config.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index efa0b265a2d..52d1bf1f0c9 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -35,7 +35,6 @@ using namespace mir::geometry; namespace { -constexpr char const* const output_id = "output_id"; constexpr char const* const position = "position"; constexpr char const* const mode = "mode"; constexpr char const* const orientation = "orientation"; From dac7b34eb9a0cec25864d331ad887228634cad57 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Wed, 22 Aug 2018 17:25:26 +0100 Subject: [PATCH 24/34] Review comments --- src/miral/static_display_config.cpp | 40 +++++------------------------ 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 52d1bf1f0c9..2cb1cddc8fd 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -35,12 +35,10 @@ using namespace mir::geometry; namespace { -constexpr char const* const position = "position"; -constexpr char const* const mode = "mode"; -constexpr char const* const orientation = "orientation"; - -constexpr char const* const orientation_value[] = - { "normal", "left", "inverted", "right" }; +char const* const position = "position"; +char const* const mode = "mode"; +char const* const orientation = "orientation"; +char const* const orientation_value[] = { "normal", "left", "inverted", "right" }; auto as_string(MirOrientation orientation) -> char const* { @@ -63,34 +61,10 @@ auto as_orientation(std::string const& orientation) -> MirOrientation auto output_type_from(std::string const& output) -> MirOutputType { - static const char * const names[] = - { - "unknown", - "VGA", - "DVI-I", - "DVI-D", - "DVI-A", - "Composite", - "S-video", - "LVDS", - "Component", - "9-pin", - "DisplayPort", - "HDMI-A", - "HDMI-B", - "TV", - "eDP", - "Virtual", - "DSI", - "DPI", - }; - - int index = 0; - for (auto const name : names) + for (int i = 0; auto const name = mir_output_type_name(static_cast(i)); ++i) { if (output.find(name) == 0) - return static_cast(index); - ++index; + return static_cast(i); } return mir_output_type_unknown; } @@ -104,7 +78,7 @@ auto output_index_from(std::string const& output) -> int } } -size_t select_mode_index(size_t mode_index, std::vector const & modes) +auto select_mode_index(size_t mode_index, std::vector const & modes) -> size_t { if (modes.empty()) return std::numeric_limits::max(); From b70fcad35ded19801c35ce861f60a6601c091f18 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Thu, 23 Aug 2018 11:15:37 +0100 Subject: [PATCH 25/34] Add facility to disable outputs --- src/miral/static_display_config.cpp | 35 +++++++++++++++++++++-------- src/miral/static_display_config.h | 1 + 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 2cb1cddc8fd..9b17d470b24 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -35,6 +35,9 @@ using namespace mir::geometry; namespace { +char const* const state = "state"; +char const* const state_enabled = "enabled"; +char const* const state_disabled = "disabled"; char const* const position = "position"; char const* const mode = "mode"; char const* const orientation = "orientation"; @@ -162,6 +165,15 @@ try Id const output_id{card_no, output_type_from(port_name), output_index_from(port_name)}; Config output_config; + if (auto const s = port_config[state]) + { + auto const state = s.as(); + if (state != state_enabled && state != state_disabled) + throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + + "' : invalid 'state' (" + state + ") for port: " + port_name}; + output_config.disabled = (state == state_disabled); + } + if (auto const pos = port_config[position]) { output_config.position = Point{pos[0].as(), pos[1].as()}; @@ -232,15 +244,14 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) auto& out = card_data.out; auto const type = static_cast(conf_output.type); auto const index_by_type = ++card_data.output_counts[type]; + auto& conf = config[Id{conf_output.card_id, type, index_by_type}]; - if (conf_output.connected && conf_output.modes.size() > 0) + if (conf_output.connected && conf_output.modes.size() > 0 && !conf.disabled) { conf_output.used = true; conf_output.power_mode = mir_power_mode_on; conf_output.orientation = mir_orientation_normal; - auto& conf = config[Id{conf_output.card_id, type, index_by_type}]; - if (conf.position.is_set()) { conf_output.top_left = conf.position.value(); @@ -310,12 +321,18 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) out << "\n # Uncomment the following to enforce the selected configuration." "\n # Or amend as desired."; out << "\n #"; - out << "\n #mode: " << conf_output.modes[conf_output.current_mode_index] - << "\t# Defaults to preferred mode"; - out << "\n #position: [" << conf_output.top_left.x << ", " << conf_output.top_left.y << ']' - << "\t# Defaults to [0, 0]"; - out << "\n #orientation: " << as_string(conf_output.orientation) - << "\t# {normal, left, right, inverted}, Defaults to normal"; + out << "\n # state: " << (conf_output.used ? state_enabled : state_disabled) + << "\t# {enabled, disabled}, defaults to enabled"; + + if (conf_output.used) // The following are only set when used + { + out << "\n # mode: " << conf_output.modes[conf_output.current_mode_index] + << "\t# Defaults to preferred mode"; + out << "\n # position: [" << conf_output.top_left.x << ", " << conf_output.top_left.y << ']' + << "\t# Defaults to [0, 0]"; + out << "\n # orientation: " << as_string(conf_output.orientation) + << "\t# {normal, left, right, inverted}, defaults to normal"; + } } else { diff --git a/src/miral/static_display_config.h b/src/miral/static_display_config.h index 5b11c691562..25df932fbf3 100644 --- a/src/miral/static_display_config.h +++ b/src/miral/static_display_config.h @@ -37,6 +37,7 @@ class StaticDisplayConfig : public mir::graphics::DisplayConfigurationPolicy using Id = std::tuple; struct Config { + bool disabled = false; mir::optional_value position; mir::optional_value size; mir::optional_value refresh; From 884874f4cd5c632fb0d01a73a37f643963fb5c35 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Thu, 23 Aug 2018 15:20:15 +0100 Subject: [PATCH 26/34] Add a constructor that can be used to supply test input. --- src/miral/static_display_config.cpp | 49 +++++++++++++++-------------- src/miral/static_display_config.h | 2 ++ 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 9b17d470b24..2ef0535e330 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -28,7 +28,6 @@ #include #include #include -#include namespace mg = mir::graphics; using namespace mir::geometry; @@ -79,6 +78,18 @@ auto output_index_from(std::string const& output) -> int in >> result; return result; } + +auto open_file(std::string const& filename) -> std::ifstream +{ + std::ifstream config_file{filename}; + + if (!config_file) + { + mir::log_warning("Cannot read static display configuration file: '" + filename + "'"); + } + + return config_file; +} } auto select_mode_index(size_t mode_index, std::vector const & modes) -> size_t @@ -92,28 +103,25 @@ auto select_mode_index(size_t mode_index, std::vector port : card) { @@ -159,8 +164,7 @@ try if (port_config.IsDefined() && !port_config.IsNull()) { if (!port_config.IsMap()) - throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + - "' : invalid port: " + port_name}; + throw mir::AbnormalExit{error_prefix + "invalid port: " + port_name}; Id const output_id{card_no, output_type_from(port_name), output_index_from(port_name)}; Config output_config; @@ -169,8 +173,7 @@ try { auto const state = s.as(); if (state != state_enabled && state != state_disabled) - throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + - "' : invalid 'state' (" + state + ") for port: " + port_name}; + throw mir::AbnormalExit{error_prefix + "invalid 'state' (" + state + ") for port: " + port_name}; output_config.disabled = (state == state_disabled); } @@ -226,7 +229,7 @@ try } catch (YAML::Exception const& x) { - throw mir::AbnormalExit{"ERROR: in display configuration file: '" + filename + "' : " + x.what()}; + throw mir::AbnormalExit{error_prefix + x.what()}; } void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) diff --git a/src/miral/static_display_config.h b/src/miral/static_display_config.h index 25df932fbf3..eb64eda39b2 100644 --- a/src/miral/static_display_config.h +++ b/src/miral/static_display_config.h @@ -24,6 +24,7 @@ #include #include +#include namespace miral { @@ -31,6 +32,7 @@ class StaticDisplayConfig : public mir::graphics::DisplayConfigurationPolicy { public: StaticDisplayConfig(std::string const& filename); + StaticDisplayConfig(std::istream&& config_file, std::string const& error_prefix); virtual void apply_to(mir::graphics::DisplayConfiguration& conf); private: From bded7b0afb09ce746b0e82a00e2d63ed125ca3b1 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Thu, 23 Aug 2018 16:17:57 +0100 Subject: [PATCH 27/34] DRY --- src/miral/static_display_config.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 2ef0535e330..467b44fd6ed 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -34,6 +34,7 @@ using namespace mir::geometry; namespace { +char const* const card_id = "card-id"; char const* const state = "state"; char const* const state_enabled = "enabled"; char const* const state_disabled = "disabled"; @@ -144,7 +145,7 @@ try { mg::DisplayConfigurationCardId card_no; - if (auto const id = card["card-id"]) + if (auto const id = card[card_id]) { card_no = mg::DisplayConfigurationCardId{id.as()}; } @@ -156,7 +157,7 @@ try { auto const port_name = port.first.Scalar(); - if (port_name == "card-id") + if (port_name == card_id) continue; auto const& port_config = port.second; From a20397bf4088aa3b4f187dfa5025be25fef70a54 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Thu, 23 Aug 2018 16:49:07 +0100 Subject: [PATCH 28/34] Use the 'default' layout --- src/miral/static_display_config.cpp | 149 +++++++++++++++------------- 1 file changed, 78 insertions(+), 71 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 467b44fd6ed..9525c2467a9 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -124,106 +124,113 @@ try if (!layouts.IsDefined() || !layouts.IsMap()) throw mir::AbnormalExit{error_prefix + "no layouts"}; - auto const layout = begin(config["layouts"]); + auto layout = layouts["default"]; - if (layout != end(config["layouts"])) + if (!layout.IsDefined() || !layout.IsMap()) { - Node name_node; - Node config_node; + // No 'default' but there is only one - use it + if (layouts.size() == 1) + { + layout = layouts.begin()->second; - std::tie(name_node, config_node) = *layout; + if (!layout.IsDefined() || !layout.IsMap()) + throw mir::AbnormalExit{error_prefix + "invalid '"+ layouts.begin()->first.Scalar() + "' layout"}; - if (!config_node.IsDefined() || !config_node.IsMap()) - throw mir::AbnormalExit{error_prefix + "invalid layout: " + name_node.Scalar()}; + mir::log_debug("Loading display layout '%s'", layouts.begin()->first.Scalar().c_str()); + } + else + { + throw mir::AbnormalExit{error_prefix + "invalid 'default' layout"}; + } + } - Node cards = config_node["cards"]; + Node cards = layout["cards"]; - if (!cards.IsDefined() || !cards.IsSequence()) - throw mir::AbnormalExit{error_prefix + "invalid 'cards' in " + name_node.Scalar()}; + if (!cards.IsDefined() || !cards.IsSequence()) + throw mir::AbnormalExit{error_prefix + "invalid 'cards' in 'default' layout"}; - for (Node const card : cards) + for (Node const card : cards) + { + mg::DisplayConfigurationCardId card_no; + + if (auto const id = card[card_id]) { - mg::DisplayConfigurationCardId card_no; + card_no = mg::DisplayConfigurationCardId{id.as()}; + } - if (auto const id = card[card_id]) - { - card_no = mg::DisplayConfigurationCardId{id.as()}; - } + if (!card.IsDefined() || !(card.IsMap() || card.IsNull())) + throw mir::AbnormalExit{error_prefix + "invalid card: " + std::to_string(card_no.as_value())}; + + for (std::pair port : card) + { + auto const port_name = port.first.Scalar(); - if (!card.IsDefined() || !(card.IsMap() || card.IsNull())) - throw mir::AbnormalExit{error_prefix + "invalid card: " + std::to_string(card_no.as_value())}; + if (port_name == card_id) + continue; - for (std::pair port : card) + auto const& port_config = port.second; + + if (port_config.IsDefined() && !port_config.IsNull()) { - auto const port_name = port.first.Scalar(); + if (!port_config.IsMap()) + throw mir::AbnormalExit{error_prefix + "invalid port: " + port_name}; - if (port_name == card_id) - continue; + Id const output_id{card_no, output_type_from(port_name), output_index_from(port_name)}; + Config output_config; - auto const& port_config = port.second; + if (auto const s = port_config[state]) + { + auto const state = s.as(); + if (state != state_enabled && state != state_disabled) + throw mir::AbnormalExit{error_prefix + "invalid 'state' (" + state + ") for port: " + port_name}; + output_config.disabled = (state == state_disabled); + } - if (port_config.IsDefined() && !port_config.IsNull()) + if (auto const pos = port_config[position]) { - if (!port_config.IsMap()) - throw mir::AbnormalExit{error_prefix + "invalid port: " + port_name}; + output_config.position = Point{pos[0].as(), pos[1].as()}; + } - Id const output_id{card_no, output_type_from(port_name), output_index_from(port_name)}; - Config output_config; + if (auto const m = port_config[mode]) + { + std::istringstream in{m.as()}; - if (auto const s = port_config[state]) - { - auto const state = s.as(); - if (state != state_enabled && state != state_disabled) - throw mir::AbnormalExit{error_prefix + "invalid 'state' (" + state + ") for port: " + port_name}; - output_config.disabled = (state == state_disabled); - } + char delimiter = '\0'; + int width; + int height; - if (auto const pos = port_config[position]) - { - output_config.position = Point{pos[0].as(), pos[1].as()}; - } + if (!(in >> width)) + goto mode_error; - if (auto const m = port_config[mode]) - { - std::istringstream in{m.as()}; + if (!(in >> delimiter) || delimiter != 'x') + goto mode_error; - char delimiter = '\0'; - int width; - int height; + if (!(in >> height)) + goto mode_error; - if (!(in >> width)) - goto mode_error; + output_config.size = Size{width, height}; - if (!(in >> delimiter) || delimiter != 'x') + if (in.peek() == '@') + { + double refresh; + if (!(in >> delimiter) || delimiter != '@') goto mode_error; - if (!(in >> height)) + if (!(in >> refresh)) goto mode_error; - output_config.size = Size{width, height}; - - if (in.peek() == '@') - { - double refresh; - if (!(in >> delimiter) || delimiter != '@') - goto mode_error; - - if (!(in >> refresh)) - goto mode_error; - - output_config.refresh = refresh; - } - } - mode_error: // TODO better error handling - - if (auto const o = port_config[orientation]) - { - std::string const orientation = o.as(); - output_config.orientation = as_orientation(orientation); + output_config.refresh = refresh; } + } + mode_error: // TODO better error handling - this->config[output_id] = output_config; + if (auto const o = port_config[orientation]) + { + std::string const orientation = o.as(); + output_config.orientation = as_orientation(orientation); } + + this->config[output_id] = output_config; } } } @@ -352,7 +359,7 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) out << "\n# keys here are layout labels (used for atomically switching between them)"; out << "\n# when enabling displays, surfaces should be matched in reverse recency order"; out << "\n"; - out << "\n my-layout: # the first layout is the default"; + out << "\n default: # the default layout"; out << "\n"; out << "\n cards:"; out << "\n # a list of cards (currently matched by card-id)"; From f7e169fc95ed0f6374692c1319e5d81eb2137f5c Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Thu, 23 Aug 2018 17:19:38 +0100 Subject: [PATCH 29/34] Local functions should be in anon namespace --- src/miral/static_display_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 9525c2467a9..996443d552e 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -91,7 +91,6 @@ auto open_file(std::string const& filename) -> std::ifstream return config_file; } -} auto select_mode_index(size_t mode_index, std::vector const & modes) -> size_t { @@ -103,6 +102,7 @@ auto select_mode_index(size_t mode_index, std::vector Date: Thu, 23 Aug 2018 17:31:46 +0100 Subject: [PATCH 30/34] Tidy code --- src/miral/static_display_config.cpp | 46 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 996443d552e..d8dbf56b469 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -328,20 +328,20 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) else out << "\n # "; out << conf_output.modes[i]; } - out << "\n #"; - out << "\n # Uncomment the following to enforce the selected configuration." - "\n # Or amend as desired."; - out << "\n #"; - out << "\n # state: " << (conf_output.used ? state_enabled : state_disabled) + out << "\n #" + "\n # Uncomment the following to enforce the selected configuration." + "\n # Or amend as desired." + "\n #" + "\n # state: " << (conf_output.used ? state_enabled : state_disabled) << "\t# {enabled, disabled}, defaults to enabled"; if (conf_output.used) // The following are only set when used { out << "\n # mode: " << conf_output.modes[conf_output.current_mode_index] - << "\t# Defaults to preferred mode"; - out << "\n # position: [" << conf_output.top_left.x << ", " << conf_output.top_left.y << ']' - << "\t# Defaults to [0, 0]"; - out << "\n # orientation: " << as_string(conf_output.orientation) + << "\t# Defaults to preferred mode" + "\n # position: [" << conf_output.top_left.x << ", " << conf_output.top_left.y << ']' + << "\t# Defaults to [0, 0]" + "\n # orientation: " << as_string(conf_output.orientation) << "\t# {normal, left, right, inverted}, defaults to normal"; } } @@ -354,21 +354,21 @@ void miral::StaticDisplayConfig::apply_to(mg::DisplayConfiguration& conf) }); std::ostringstream out; - out << "Display config:\n8>< ---------------------------------------------------"; - out << "\nlayouts:"; - out << "\n# keys here are layout labels (used for atomically switching between them)"; - out << "\n# when enabling displays, surfaces should be matched in reverse recency order"; - out << "\n"; - out << "\n default: # the default layout"; - out << "\n"; - out << "\n cards:"; - out << "\n # a list of cards (currently matched by card-id)"; - - for (auto& co : card_map) + out << "Display config:\n8>< ---------------------------------------------------" + "\nlayouts:" + "\n# keys here are layout labels (used for atomically switching between them)" + "\n# when enabling displays, surfaces should be matched in reverse recency order" + "\n" + "\n default: # the default layout" + "\n" + "\n cards:" + "\n # a list of cards (currently matched by card-id)"; + + for (auto const& co : card_map) { - out << "\n"; - out << "\n - card-id: " << co.first.as_value(); - out << co.second.out.str(); + out << "\n" + "\n - card-id: " << co.first.as_value() + << co.second.out.str(); } out << "8>< ---------------------------------------------------"; From f25c5b9d74fef1a670ee05c0862270eb47402f98 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 24 Aug 2018 10:20:28 +0100 Subject: [PATCH 31/34] StaticDisplayConfig test fixture. (And fix some linker options.) --- .../test/doubles/mock_display_configuration.h | 2 + src/miral/CMakeLists.txt | 9 +++- src/miral/static_display_config.cpp | 40 ++++++++-------- src/miral/static_display_config.h | 6 ++- tests/miral/CMakeLists.txt | 2 +- tests/miral/static_display_config.cpp | 48 +++++++++++++++++++ 6 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 tests/miral/static_display_config.cpp diff --git a/include/test/mir/test/doubles/mock_display_configuration.h b/include/test/mir/test/doubles/mock_display_configuration.h index 119a34ef662..19f0da4baeb 100644 --- a/include/test/mir/test/doubles/mock_display_configuration.h +++ b/include/test/mir/test/doubles/mock_display_configuration.h @@ -21,6 +21,8 @@ #include "mir/graphics/display_configuration.h" +#include + namespace mir { namespace test diff --git a/src/miral/CMakeLists.txt b/src/miral/CMakeLists.txt index b667549c208..976ea709a7e 100644 --- a/src/miral/CMakeLists.txt +++ b/src/miral/CMakeLists.txt @@ -87,6 +87,13 @@ target_include_directories(miral-internal PRIVATE ${MIRSERVER_INCLUDE_DIRS} ) +target_link_libraries(miral-internal + PRIVATE + mirserver + ${WAYLAND_CLIENT_LDFLAGS} ${WAYLAND_CLIENT_LIBRARIES} + ${YAML_LIBRARIES} +) + target_include_directories(miral PUBLIC "${miral_include}" ${MIRCLIENT_INCLUDE_DIRS} PRIVATE ${MIRSERVER_INCLUDE_DIRS} @@ -99,8 +106,6 @@ target_link_libraries(miral PRIVATE miral-internal mirserver - ${WAYLAND_CLIENT_LDFLAGS} ${WAYLAND_CLIENT_LIBRARIES} - ${YAML_LIBRARIES} ) set_target_properties(miral diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index d8dbf56b469..1f97715677b 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -80,18 +80,6 @@ auto output_index_from(std::string const& output) -> int return result; } -auto open_file(std::string const& filename) -> std::ifstream -{ - std::ifstream config_file{filename}; - - if (!config_file) - { - mir::log_warning("Cannot read static display configuration file: '" + filename + "'"); - } - - return config_file; -} - auto select_mode_index(size_t mode_index, std::vector const & modes) -> size_t { if (modes.empty()) @@ -104,23 +92,35 @@ auto select_mode_index(size_t mode_index, std::vectorconfig[output_id] = output_config; + new_config[output_id] = output_config; } } } + + config = new_config; } catch (YAML::Exception const& x) { diff --git a/src/miral/static_display_config.h b/src/miral/static_display_config.h index eb64eda39b2..2bebc84c965 100644 --- a/src/miral/static_display_config.h +++ b/src/miral/static_display_config.h @@ -31,9 +31,13 @@ namespace miral class StaticDisplayConfig : public mir::graphics::DisplayConfigurationPolicy { public: + StaticDisplayConfig(); StaticDisplayConfig(std::string const& filename); - StaticDisplayConfig(std::istream&& config_file, std::string const& error_prefix); + virtual void apply_to(mir::graphics::DisplayConfiguration& conf); + + void load_config(std::istream& config_file, std::string const& error_prefix); + private: using Id = std::tuple; diff --git a/tests/miral/CMakeLists.txt b/tests/miral/CMakeLists.txt index ca7e1e1fc10..cc7803ccde8 100644 --- a/tests/miral/CMakeLists.txt +++ b/tests/miral/CMakeLists.txt @@ -47,6 +47,7 @@ mir_add_wrapped_executable(miral-test-internal NOINSTALL modify_window_specification.cpp display_reconfiguration.cpp raise_tree.cpp + static_display_config.cpp client_mediated_gestures.cpp window_info.cpp test_window_manager_tools.h @@ -55,7 +56,6 @@ mir_add_wrapped_executable(miral-test-internal NOINSTALL target_link_libraries(miral-test-internal ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARIES} - miral miral-internal mir-test-assist ) diff --git a/tests/miral/static_display_config.cpp b/tests/miral/static_display_config.cpp new file mode 100644 index 00000000000..335b0079428 --- /dev/null +++ b/tests/miral/static_display_config.cpp @@ -0,0 +1,48 @@ +/* + * Copyright © 2018 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authored by: Alan Griffiths + */ + +#include "static_display_config.h" + +#include + +#include +#include + +using namespace testing; +namespace mg = mir::graphics; +namespace mtd = mir::test::doubles; + +namespace +{ +struct StaticDisplayConfig : Test +{ + mtd::MockDisplayConfiguration dc; + mg::DisplayConfigurationOutput dco; + mg::UserDisplayConfigurationOutput udco{dco}; + + miral::StaticDisplayConfig sdc; +}; +} + +TEST_F(StaticDisplayConfig, empty_config_file_is_invalid) +{ + std::istringstream empty; + + EXPECT_THROW((sdc.load_config(empty, "")), mir::AbnormalExit); + +} \ No newline at end of file From 8627b49d1e2db91360526ffaa7bfd38cbcf9e149 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 24 Aug 2018 15:11:22 +0100 Subject: [PATCH 32/34] Reasonable set of tests --- src/miral/static_display_config.cpp | 8 +- tests/miral/CMakeLists.txt | 4 + tests/miral/static_display_config.cpp | 197 +++++++++++++++++++++++++- 3 files changed, 203 insertions(+), 6 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 1f97715677b..f2b2fe3a566 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -99,12 +99,14 @@ miral::StaticDisplayConfig::StaticDisplayConfig(std::string const& filename) { std::ifstream config_file{filename}; - if (!config_file) + if (config_file) + { + load_config(config_file, "ERROR: in display configuration file: '" + filename + "' : "); + } + else { mir::log_warning("Cannot read static display configuration file: '" + filename + "'"); } - - load_config(config_file, "ERROR: in display configuration file: '" + filename + "' : "); } void miral::StaticDisplayConfig::load_config(std::istream& config_file, std::string const& error_prefix) diff --git a/tests/miral/CMakeLists.txt b/tests/miral/CMakeLists.txt index cc7803ccde8..5cd7accbde3 100644 --- a/tests/miral/CMakeLists.txt +++ b/tests/miral/CMakeLists.txt @@ -53,6 +53,10 @@ mir_add_wrapped_executable(miral-test-internal NOINSTALL test_window_manager_tools.h ) +set_source_files_properties(static_display_config.cpp PROPERTIES COMPILE_FLAGS + "${CMAKE_CXXFLAGS} -I ${PROJECT_SOURCE_DIR}/src/include/common") + + target_link_libraries(miral-test-internal ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARIES} diff --git a/tests/miral/static_display_config.cpp b/tests/miral/static_display_config.cpp index 335b0079428..4a2ed6bef19 100644 --- a/tests/miral/static_display_config.cpp +++ b/tests/miral/static_display_config.cpp @@ -17,32 +17,223 @@ */ #include "static_display_config.h" +#include "mir/logging/dumb_console_logger.h" #include +#include #include #include using namespace testing; +using namespace mir::geometry; namespace mg = mir::graphics; namespace mtd = mir::test::doubles; namespace { +static constexpr Point default_top_left{0, 0}; +static constexpr mg::DisplayConfigurationMode default_mode{{648, 480}, 60.0}; +static constexpr mg::DisplayConfigurationMode another_mode{{1280, 1024}, 75.0}; + struct StaticDisplayConfig : Test { mtd::MockDisplayConfiguration dc; - mg::DisplayConfigurationOutput dco; - mg::UserDisplayConfigurationOutput udco{dco}; + mg::DisplayConfigurationOutput vga1; + mg::DisplayConfigurationOutput hdmi1; miral::StaticDisplayConfig sdc; + + + + void SetUp() override + { + mir::logging::set_logger(std::make_shared()); + vga1.id = mg::DisplayConfigurationOutputId{0}; + vga1.card_id = mg::DisplayConfigurationCardId{0}; + vga1.connected = true; + vga1.type = mg::DisplayConfigurationOutputType::vga; + vga1.used = true; + vga1.top_left = default_top_left; + vga1.preferred_mode_index = 0; + vga1.current_mode_index = 0; + vga1.modes.push_back(default_mode); + vga1.modes.push_back(another_mode); + vga1.power_mode = mir_power_mode_on; + vga1.orientation = mir_orientation_normal; + + hdmi1.id = mg::DisplayConfigurationOutputId{1}; + hdmi1.card_id = mg::DisplayConfigurationCardId{0}; + hdmi1.connected = true; + hdmi1.type = mg::DisplayConfigurationOutputType::hdmia; + hdmi1.used = true; + hdmi1.top_left = default_top_left; + hdmi1.preferred_mode_index = 0; + hdmi1.current_mode_index = 0; + hdmi1.modes.push_back(default_mode); + hdmi1.modes.push_back(another_mode); + hdmi1.power_mode = mir_power_mode_on; + hdmi1.orientation = mir_orientation_normal; + + EXPECT_CALL(dc, for_each_output(_)).WillRepeatedly(DoAll( + InvokeArgument<0>(mg::UserDisplayConfigurationOutput{vga1}), + InvokeArgument<0>(mg::UserDisplayConfigurationOutput{hdmi1}))); + + Test::SetUp(); + } + +protected: + void TearDown() override + { + Test::TearDown(); + mir::logging::set_logger(std::make_shared()); + } + +public: + static auto constexpr valid_input = + "layouts:\n" + "# keys here are layout labels (used for atomically switching between them)\n" + "# when enabling displays, surfaces should be matched in reverse recency order\n" + "\n" + " default: # the first layout is the default\n" + "\n" + " cards:\n" + " # a list of cards (currently matched by card-id)\n" + "\n" + " - card-id: 0\n" + " VGA-1:\n" + " # This output supports the following modes: 1920x1080@60.0, 1680x1050@60.0,\n" + " # 1280x1024@75.0, 1280x1024@60.0, 1440x900@59.9, 1280x960@60.0, 1280x800@59.8,\n" + " # 1152x864@75.0, 1280x720@60.0, 1024x768@75.0, 1024x768@70.1, 1024x768@60.0,\n" + " # 832x624@74.5, 800x600@75.0, 800x600@72.2, 800x600@60.3, 800x600@56.2,\n" + " # 640x480@75.0, 640x480@66.7, 640x480@59.9, 720x400@70.1\n" + " #\n" + " # Uncomment the following to enforce the selected configuration.\n" + " # Or amend as desired.\n" + " #\n" + " state: disabled # Defaults to preferred enabled\n" + " mode: 1280x1024@75.0 # Defaults to preferred mode\n" + " # position: [0, 0] # Defaults to [0, 0]\n" + " # orientation: normal # {normal, left, right, inverted}, Defaults to normal\n" + "\n" + " HDMI-A-1:\n" + " # This output supports the following modes: 1920x1080@60.0, 1680x1050@59.9,\n" + " # 1280x1024@75.0, 1280x1024@60.0, 1440x900@59.9, 1280x960@60.0, 1280x800@59.9,\n" + " # 1152x864@75.0, 1280x720@60.0, 1024x768@75.0, 1024x768@70.1, 1024x768@60.0,\n" + " # 832x624@74.5, 800x600@75.0, 800x600@72.2, 800x600@60.3, 800x600@56.2,\n" + " # 640x480@75.0, 640x480@66.7, 640x480@59.9, 720x400@70.1\n" + " #\n" + " # Uncomment the following to enforce the selected configuration.\n" + " # Or amend as desired.\n" + " #\n" + " # state: enabled # Defaults to preferred enabled\n" + " mode: 1280x1024@75.0 # Defaults to preferred mode\n" + " # position: [1280, 0] # Defaults to [0, 0]\n" + " orientation: inverted # {normal, left, right, inverted}, Defaults to normal\n" + "\n" + " DisplayPort-1:\n" + " # (disconnected)\n" + "\n" + " HDMI-A-2:\n" + " # (disconnected)\n" + "\n" + " DisplayPort-2:\n" + " # (disconnected)"; }; } -TEST_F(StaticDisplayConfig, empty_config_file_is_invalid) +TEST_F(StaticDisplayConfig, nonexistent_config_file_is_no_error) +{ + miral::StaticDisplayConfig{tmpnam(nullptr)}; +} + +TEST_F(StaticDisplayConfig, empty_config_input_causes_AbnormalExit) { std::istringstream empty; EXPECT_THROW((sdc.load_config(empty, "")), mir::AbnormalExit); +} + +TEST_F(StaticDisplayConfig, ill_formed_config_input_causes_AbnormalExit) +{ + std::istringstream ill_formed{"not YAML = error"}; + + EXPECT_THROW((sdc.load_config(ill_formed, "")), mir::AbnormalExit); +} + +TEST_F(StaticDisplayConfig, well_formed_non_config_input_causes_AbnormalExit) +{ + std::istringstream well_formed{"well-formed: error"}; + + EXPECT_THROW((sdc.load_config(well_formed, "")), mir::AbnormalExit); +} + +TEST_F(StaticDisplayConfig, valid_config_input_is_no_error) +{ + std::istringstream valid_config_stream{valid_input}; + + sdc.load_config(valid_config_stream, ""); +} + +TEST_F(StaticDisplayConfig, disabling_vga1_disables_vga1) +{ + std::istringstream stream{ + "layouts:\n" + " default:\n" + " cards:\n" + " - VGA-1:\n" + " state: disabled\n"}; + + sdc.load_config(stream, ""); + + sdc.apply_to(dc); + + EXPECT_THAT(vga1.used, Eq(false)); + EXPECT_THAT(vga1.power_mode, Eq(mir_power_mode_off)); +} + +TEST_F(StaticDisplayConfig, sizing_hdmi1_sizes_hdmi1) +{ + std::istringstream stream{ + "layouts:\n" + " default:\n" + " cards:\n" + " - HDMI-A-1:\n" + " mode: 1280x1024\n"}; + + sdc.load_config(stream, ""); + + sdc.apply_to(dc); + + EXPECT_THAT(hdmi1.used, Eq(true)); + EXPECT_THAT(hdmi1.power_mode, Eq(mir_power_mode_on)); + EXPECT_THAT(hdmi1.modes[hdmi1.current_mode_index].size, Eq(Size{1280, 1024})); +} + +TEST_F(StaticDisplayConfig, positioning_hdmi1_and_inverting_vga1_works) +{ + std::istringstream stream{ + "layouts:\n" + " default:\n" + " cards:\n" + " - VGA-1:\n" + " orientation: inverted\n" + " - HDMI-A-1:\n" + " position: [1280, 0]\n"}; + + sdc.load_config(stream, ""); + + sdc.apply_to(dc); + + EXPECT_THAT(vga1.used, Eq(true)); + EXPECT_THAT(vga1.power_mode, Eq(mir_power_mode_on)); + EXPECT_THAT(vga1.modes[vga1.current_mode_index], Eq(default_mode)); + EXPECT_THAT(vga1.top_left, Eq(Point{0, 0})); + EXPECT_THAT(vga1.orientation, Eq(mir_orientation_inverted)); + EXPECT_THAT(hdmi1.used, Eq(true)); + EXPECT_THAT(hdmi1.power_mode, Eq(mir_power_mode_on)); + EXPECT_THAT(hdmi1.modes[hdmi1.current_mode_index], Eq(default_mode)); + EXPECT_THAT(hdmi1.top_left, Eq(Point{1280, 0})); + EXPECT_THAT(hdmi1.orientation, Eq(mir_orientation_normal)); } \ No newline at end of file From b50bdfed84a38242f343edd5793888321500e543 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 24 Aug 2018 15:31:31 +0100 Subject: [PATCH 33/34] Drop the logic for using layout not called "default" --- src/miral/static_display_config.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index f2b2fe3a566..61aa14570ac 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -130,20 +130,7 @@ try if (!layout.IsDefined() || !layout.IsMap()) { - // No 'default' but there is only one - use it - if (layouts.size() == 1) - { - layout = layouts.begin()->second; - - if (!layout.IsDefined() || !layout.IsMap()) - throw mir::AbnormalExit{error_prefix + "invalid '"+ layouts.begin()->first.Scalar() + "' layout"}; - - mir::log_debug("Loading display layout '%s'", layouts.begin()->first.Scalar().c_str()); - } - else - { - throw mir::AbnormalExit{error_prefix + "invalid 'default' layout"}; - } + throw mir::AbnormalExit{error_prefix + "invalid 'default' layout"}; } Node cards = layout["cards"]; From 8f0e7e540452b615d060a44432f667a23fb44166 Mon Sep 17 00:00:00 2001 From: Alan Griffiths Date: Fri, 24 Aug 2018 16:41:53 +0100 Subject: [PATCH 34/34] Test demonstrating using an alias --- tests/miral/static_display_config.cpp | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/miral/static_display_config.cpp b/tests/miral/static_display_config.cpp index 4a2ed6bef19..784d6416cb3 100644 --- a/tests/miral/static_display_config.cpp +++ b/tests/miral/static_display_config.cpp @@ -231,6 +231,41 @@ TEST_F(StaticDisplayConfig, positioning_hdmi1_and_inverting_vga1_works) EXPECT_THAT(vga1.top_left, Eq(Point{0, 0})); EXPECT_THAT(vga1.orientation, Eq(mir_orientation_inverted)); + EXPECT_THAT(hdmi1.used, Eq(true)); + EXPECT_THAT(hdmi1.power_mode, Eq(mir_power_mode_on)); + EXPECT_THAT(hdmi1.modes[hdmi1.current_mode_index], Eq(default_mode)); + EXPECT_THAT(hdmi1.top_left, Eq(Point{1280, 0})); + EXPECT_THAT(hdmi1.orientation, Eq(mir_orientation_normal)); +} + +TEST_F(StaticDisplayConfig, selecting_layout_by_alias_works) +{ + std::istringstream stream{ + "layouts:\n" + " another:\n" + " cards:\n" + " - VGA-1:\n" + " state: disabled\n" + " - HDMI-A-1:\n" + " state: disabled\n" + " expected: &my_default\n" + " cards:\n" + " - VGA-1:\n" + " orientation: inverted\n" + " - HDMI-A-1:\n" + " position: [1280, 0]\n" + " default: *my_default\n"}; + + sdc.load_config(stream, ""); + + sdc.apply_to(dc); + + EXPECT_THAT(vga1.used, Eq(true)); + EXPECT_THAT(vga1.power_mode, Eq(mir_power_mode_on)); + EXPECT_THAT(vga1.modes[vga1.current_mode_index], Eq(default_mode)); + EXPECT_THAT(vga1.top_left, Eq(Point{0, 0})); + EXPECT_THAT(vga1.orientation, Eq(mir_orientation_inverted)); + EXPECT_THAT(hdmi1.used, Eq(true)); EXPECT_THAT(hdmi1.power_mode, Eq(mir_power_mode_on)); EXPECT_THAT(hdmi1.modes[hdmi1.current_mode_index], Eq(default_mode));