Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions debian/libmiral7.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,32 @@ libmiral.so.7 libmiral7 #MINVER#
MIRAL_5.8@MIRAL_5.8 5.8.0
(c++)"miral::WindowSpecification::parent_size() const@MIRAL_5.8" 5.8.0
(c++)"miral::WindowSpecification::parent_size()@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::OverridesList::OverridesList(std::unique_ptr<miral::live_config::OverridesList::Context, std::default_delete<miral::live_config::OverridesList::Context> >)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::OverridesList::for_each(std::move_only_function<void (std::filesystem::__cxx11::path const&, std::basic_istream<char, std::char_traits<char> >&)>, std::move_only_function<void (std::filesystem::__cxx11::path const&, std::basic_istream<char, std::char_traits<char> >&)>, std::move_only_function<void (std::filesystem::__cxx11::path const&, std::basic_istream<char, std::char_traits<char> >&)>, std::move_only_function<void (std::filesystem::__cxx11::path const&)>) const@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::OverridesList::~OverridesList()@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::IniFileWithOverrides()@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::add_bool_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, bool, std::function<void (miral::live_config::Key const&, std::optional<bool>)>)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::add_bool_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<bool>)>)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::add_float_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, float, std::function<void (miral::live_config::Key const&, std::optional<float>)>)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::add_float_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<float>)>)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::add_int_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, int, std::function<void (miral::live_config::Key const&, std::optional<int>)>)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::add_int_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<int>)>)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::add_string_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<std::basic_string_view<char, std::char_traits<char> > >)>)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::add_string_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<std::basic_string_view<char, std::char_traits<char> > >)>)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::load(miral::live_config::OverridesList const&)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::on_done(std::function<void ()>)@MIRAL_5.8" 5.8.0
(c++)"miral::live_config::IniFileWithOverrides::~IniFileWithOverrides()@MIRAL_5.8" 5.8.0
(c++)"typeinfo for miral::live_config::IniFileWithOverrides@MIRAL_5.8" 5.8.0
(c++)"vtable for miral::live_config::IniFileWithOverrides@MIRAL_5.8" 5.8.0
(c++|arch-bits=32)"miral::live_config::IniFileWithOverrides::add_floats_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<std::span<float const, 4294967295u> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=32)"miral::live_config::IniFileWithOverrides::add_floats_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::span<float const, 4294967295u>, std::function<void (miral::live_config::Key const&, std::optional<std::span<float const, 4294967295u> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=32)"miral::live_config::IniFileWithOverrides::add_ints_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<std::span<int const, 4294967295u> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=32)"miral::live_config::IniFileWithOverrides::add_ints_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::span<int const, 4294967295u>, std::function<void (miral::live_config::Key const&, std::optional<std::span<int const, 4294967295u> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=32)"miral::live_config::IniFileWithOverrides::add_strings_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 4294967295u> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=32)"miral::live_config::IniFileWithOverrides::add_strings_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 4294967295u>, std::function<void (miral::live_config::Key const&, std::optional<std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 4294967295u> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=64)"miral::live_config::IniFileWithOverrides::add_floats_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<std::span<float const, 18446744073709551615ul> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=64)"miral::live_config::IniFileWithOverrides::add_floats_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::span<float const, 18446744073709551615ul>, std::function<void (miral::live_config::Key const&, std::optional<std::span<float const, 18446744073709551615ul> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=64)"miral::live_config::IniFileWithOverrides::add_ints_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<std::span<int const, 18446744073709551615ul> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=64)"miral::live_config::IniFileWithOverrides::add_ints_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::span<int const, 18446744073709551615ul>, std::function<void (miral::live_config::Key const&, std::optional<std::span<int const, 18446744073709551615ul> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=64)"miral::live_config::IniFileWithOverrides::add_strings_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::function<void (miral::live_config::Key const&, std::optional<std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 18446744073709551615ul> >)>)@MIRAL_5.8" 5.8.0
(c++|arch-bits=64)"miral::live_config::IniFileWithOverrides::add_strings_attribute(miral::live_config::Key const&, std::basic_string_view<char, std::char_traits<char> >, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 18446744073709551615ul>, std::function<void (miral::live_config::Key const&, std::optional<std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 18446744073709551615ul> >)>)@MIRAL_5.8" 5.8.0
90 changes: 90 additions & 0 deletions include/miral/miral/live_config_ini_file_with_overrides.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright © 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 <http://www.gnu.org/licenses/>.
*/

#ifndef MIRAL_INI_FILE_WITH_OVERRIDES_H
#define MIRAL_INI_FILE_WITH_OVERRIDES_H

#include <miral/live_config.h>

#include <memory>
#include <span>

namespace miral::live_config
{
class OverridesList;

/// An ini-file-based live configuration store that aggregates values from
/// multiple files (a base config plus zero or more override files).
///
/// Non-array keys follow last-writer-wins semantics: if the same key appears
/// in a later (higher-priority) file, it replaces the earlier value.
///
/// Array keys accumulate across files; an empty assignment (\c key=) in a
/// later file clears all previously accumulated values from earlier files.
///
/// A single call to load() wraps the entire set of files in one transaction,
/// so all attribute handlers and \c on_done fire exactly once per call.
///
/// \remark Since MirAL 5.8
class IniFileWithOverrides : public Store
{
public:
IniFileWithOverrides();
~IniFileWithOverrides() override;

IniFileWithOverrides(IniFileWithOverrides const&) = delete;
IniFileWithOverrides& operator=(IniFileWithOverrides const&) = delete;

void add_int_attribute(Key const& key, std::string_view description, HandleInt handler) override;
void add_ints_attribute(Key const& key, std::string_view description, HandleInts handler) override;
void add_bool_attribute(Key const& key, std::string_view description, HandleBool handler) override;
void add_float_attribute(Key const& key, std::string_view description, HandleFloat handler) override;
void add_floats_attribute(Key const& key, std::string_view description, HandleFloats handler) override;
void add_string_attribute(Key const& key, std::string_view description, HandleString handler) override;
void add_strings_attribute(Key const& key, std::string_view description, HandleStrings handler) override;

void add_int_attribute(Key const& key, std::string_view description, int preset, HandleInt handler) override;
void add_ints_attribute(
Key const& key, std::string_view description, std::span<int const> preset, HandleInts handler) override;
void add_bool_attribute(Key const& key, std::string_view description, bool preset, HandleBool handler) override;
void add_float_attribute(
Key const& key, std::string_view description, float preset, HandleFloat handler) override;
void add_floats_attribute(
Key const& key, std::string_view description, std::span<float const> preset, HandleFloats handler) override;
void add_string_attribute(
Key const& key, std::string_view description, std::string_view preset, HandleString handler) override;
void add_strings_attribute(
Key const& key,
std::string_view description,
std::span<std::string const> preset,
HandleStrings handler) override;

void on_done(HandleDone handler) override;

/// Parse a batch of file-system events and dispatch all handlers once.
///
/// \c on_done fires exactly once per call.
///
/// \remark Since MirAL 5.8
void load(OverridesList const& changes);

private:
class Self;
std::shared_ptr<Self> self;
};
}

#endif // MIRAL_INI_FILE_WITH_OVERRIDES_H
59 changes: 59 additions & 0 deletions include/miral/miral/live_config_overrides_list.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright © 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 <http://www.gnu.org/licenses/>.
*/

#ifndef MIRAL_LIVE_CONFIG_OVERRIDES_LIST_H
#define MIRAL_LIVE_CONFIG_OVERRIDES_LIST_H

#include <filesystem>
#include <functional>
#include <iosfwd>
#include <memory>

namespace miral::live_config
{
class OverridesListBuilder;

/// An ordered list of configuration file overrides to be applied. Each
/// callback represents a file that should be loaded into the configuration in
/// the given order (unchanged, fresh, modified, or dropped).
///
/// \remark Since MirAL 5.8
class OverridesList
{
struct Context;
friend OverridesListBuilder;

public:
/// \pre The context must not be null
explicit OverridesList(std::unique_ptr<Context> ctx);

/// Callback type for file-content events (unchanged, moved/new, or modified).
using Loader = std::move_only_function<void(std::filesystem::path const&, std::istream&)>;

Comment thread
tarek-y-ismail marked this conversation as resolved.
/// Callback type for file-removal events.
using Dropped = std::move_only_function<void(std::filesystem::path const&)>;

/// Iterate all events in push order, invoking the matching callback for each.
void for_each(Loader unchanged, Loader fresh, Loader modified, Dropped dropped) const;

~OverridesList();

private:
std::unique_ptr<Context> ctx;
};
}

#endif //MIRAL_LIVE_CONFIG_OVERRIDES_LIST_H
4 changes: 4 additions & 0 deletions src/miral/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ add_library(miral-internal STATIC
fd_manager.cpp fd_manager.h
input_device_config.cpp input_device_configuration_options.h input_device_config.h
launch_app.cpp launch_app.h
live_config_overrides_list_builder.cpp live_config_overrides_list_builder.h
render_scene_into_surface.cpp render_scene_into_surface.h
mru_window_list.cpp mru_window_list.h
open_desktop_entry.cpp open_desktop_entry.h
Expand All @@ -36,6 +37,7 @@ add_library(miral-internal STATIC
window_info_defaults.h
window_specification_internal.cpp window_specification_internal.h
basic_store.cpp basic_store.h
live_config_ini_file_common.cpp live_config_ini_file_common.h
)

# Already implied by the linker's symbol version script, but can avoid accidents
Expand Down Expand Up @@ -149,7 +151,9 @@ add_library(miral-external OBJECT
output_filter.cpp ${miral_include}/miral/output_filter.h
simulated_secondary_click.cpp ${miral_include}/miral/simulated_secondary_click.h
live_config.cpp ${miral_include}/miral/live_config.h
live_config_overrides_list.cpp ${miral_include}/miral/live_config_overrides_list.h
live_config_ini_file.cpp ${miral_include}/miral/live_config_ini_file.h
live_config_ini_file_with_overrides.cpp ${miral_include}/miral/live_config_ini_file_with_overrides.h
hover_click.cpp ${miral_include}/miral/hover_click.h
magnifier.cpp ${miral_include}/miral/magnifier.h
bounce_keys.cpp ${miral_include}/miral/bounce_keys.h
Expand Down
37 changes: 2 additions & 35 deletions src/miral/live_config_ini_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include "basic_store.h"
#include "live_config_ini_file_common.h"

#include <miral/live_config_ini_file.h>

Expand All @@ -29,46 +30,12 @@ class mlc::IniFile::Self: public mlc::BasicStore
void load_file(std::istream& istream, std::filesystem::path const& path);
};

namespace
{
auto trim_start_and_end(std::string_view string) -> std::string_view
{
constexpr auto whitespace = " \t\n\r\f\v";

auto const first_non_space = string.find_first_not_of(whitespace);
if (first_non_space == std::string::npos)
{
return string.substr(0, 0);
}

auto const last_non_space = string.find_last_not_of(whitespace);
return string.substr(first_non_space, last_non_space - first_non_space + 1);
}
}

void mlc::IniFile::Self::load_file(std::istream& istream, std::filesystem::path const& path)
{
do_transaction(
[&]
{
for (std::string line; std::getline(istream, line);)
{
auto const line_view = std::string_view{line};
if (!line_view.starts_with('#') && line_view.contains("="))
try
{
auto const eq = line_view.find_first_of("=");
auto const key = Key{trim_start_and_end(line_view.substr(0, eq))};
auto const value = trim_start_and_end(line_view.substr(eq + 1));

update_key(key, value, path);
}
catch (std::exception const& e)
{
mir::log_warning("Error processing '%s': %s", path.c_str(), e.what());
}
}

parse_ini(istream, path, [this](auto const& key, auto value, auto const& path) { update_key(key, value, path); });
});
}

Expand Down
62 changes: 62 additions & 0 deletions src/miral/live_config_ini_file_common.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright © 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 <http://www.gnu.org/licenses/>.
*/

#include "live_config_ini_file_common.h"

#include <mir/log.h>
#include <miral/live_config.h>

#include <string>

namespace mlc = miral::live_config;

namespace
{
auto trim_start_and_end(std::string_view string) -> std::string_view
{
constexpr auto whitespace = " \t\n\r\f\v";

auto const first_non_space = string.find_first_not_of(whitespace);
if (first_non_space == std::string::npos)
{
return string.substr(0, 0);
}

auto const last_non_space = string.find_last_not_of(whitespace);
return string.substr(first_non_space, last_non_space - first_non_space + 1);
}
}

auto mlc::parse_ini(std::istream& istream, std::filesystem::path path, std::function<void(Key const&, std::string_view, std::filesystem::path const&)> const &update_key) -> void
{
for (std::string line; std::getline(istream, line);)
{
auto const line_view = std::string_view{line};
if (!line_view.starts_with('#') && line_view.contains("="))
try
{
auto const eq = line_view.find_first_of("=");
auto const key = Key{trim_start_and_end(line_view.substr(0, eq))};
auto const value = trim_start_and_end(line_view.substr(eq + 1));

update_key(key, value, path);
}
catch (std::exception const& e)
{
mir::log_warning("Error processing '%s': %s", path.c_str(), e.what());
}
}
}
Loading
Loading