diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | .vscode/settings.json | 13 | ||||
| -rw-r--r-- | CMakeLists.txt | 32 | ||||
| -rw-r--r-- | cmake/Modules/ConanDependencies.cmake | 9 | ||||
| -rw-r--r-- | cmake/Modules/SystemDependencies.cmake | 7 | ||||
| -rw-r--r-- | conanfile.py | 25 | ||||
| -rw-r--r-- | src/main.cpp | 16 | ||||
| -rw-r--r-- | src/optional.hpp | 36 | ||||
| -rw-r--r-- | src/setting.cpp | 29 | ||||
| -rw-r--r-- | src/setting.hpp | 48 | ||||
| -rw-r--r-- | src/type_wrapper.hpp | 23 | ||||
| -rw-r--r-- | src/variant.cpp | 17 | ||||
| -rw-r--r-- | src/variant.hpp | 47 |
13 files changed, 303 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build
\ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1231968 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "C_Cpp.default.configurationProvider": "vector-of-bool.cmake-tools", + "C_Cpp.default.cppStandard": "c++17", + "C_Cpp.configurationWarnings": "Disabled", + "files.associations": { + "optional": "cpp", + "exception": "cpp", + "initializer_list": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "string": "cpp" + } +}
\ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1257c68 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.10) +project("wanda" LANGUAGES CXX) + +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_STANDARD "17") + +# if(NOT CMAKE_BUILD_TYPE) +# set(CMAKE_BUILD_TYPE "Release") +# endif() + +if(NOT CMAKE_EXPORT_COMPILE_COMMANDS) + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +endif() + +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules") + +include("ConanDependencies") +include("SystemDependencies") + +add_executable("wanda" + "src/main.cpp" + "src/setting.cpp" + "src/setting.hpp" + "src/variant.cpp" + "src/variant.hpp" + ) +target_link_libraries("wanda" + "CONAN_PKG::boost_config" + "SYSTEM::GIO" + )
\ No newline at end of file diff --git a/cmake/Modules/ConanDependencies.cmake b/cmake/Modules/ConanDependencies.cmake new file mode 100644 index 0000000..1aa589d --- /dev/null +++ b/cmake/Modules/ConanDependencies.cmake @@ -0,0 +1,9 @@ +if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake") + message(STATUS "Downloading 'conan' integration") + file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/master/conan.cmake" "${CMAKE_BINARY_DIR}/conan.cmake") +endif() + +include("${CMAKE_BINARY_DIR}/conan.cmake") + +conan_add_remote(NAME "bincrafters" URL "https://api.bintray.com/conan/bincrafters/public-conan") +conan_cmake_run(CONANFILE "conanfile.py" BASIC_SETUP CMAKE_TARGETS BUILD "missing" OUTPUT_QUIET) diff --git a/cmake/Modules/SystemDependencies.cmake b/cmake/Modules/SystemDependencies.cmake new file mode 100644 index 0000000..0b1321f --- /dev/null +++ b/cmake/Modules/SystemDependencies.cmake @@ -0,0 +1,7 @@ +find_package("PkgConfig" REQUIRED) + +pkg_check_modules("GIO" "gio-2.0" REQUIRED) +add_library("SYSTEM::GIO" INTERFACE IMPORTED) +set_property(TARGET "SYSTEM::GIO" PROPERTY INTERFACE_LINK_LIBRARIES ${GIO_LIBRARIES}) +set_property(TARGET "SYSTEM::GIO" PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${GIO_INCLUDE_DIRS}) +set_property(TARGET "SYSTEM::GIO" PROPERTY INTERFACE_COMPILE_OPTIONS ${GIO_CFLAGS} ${GIO_CFLAGS_OTHER}) diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 0000000..ddb17e8 --- /dev/null +++ b/conanfile.py @@ -0,0 +1,25 @@ +# pylint: disable=missing-docstring + +from conans import ConanFile, CMake + +class Wanda(ConanFile): + name = "wanda" + version = "0.1" + license = "BSD 3-clause" + description = "A wallpaper changer for the GNOME" + generators = "cmake" + export_sources = ( + "CMakeLists.txt", + "src/*", + ) + requires = ( + "boost_program_options/1.67.0@bincrafters/stable", + ) + + def build(self): + cmake = CMake(self) + cmake.configure(source_folder="src") + cmake.build() + + def package(self): + pass diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..fb2e0bf --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,16 @@ +#include "setting.hpp" +#include "optional.hpp" + +#include <iostream> +#include <string> + +int main() { + using namespace wanda::literals; + using namespace wanda::std_ext; + + with("org.gnome.desktop.background"_setting, [](auto & setting){ + with(setting.template get<std::string>("picture-uri"_key), [](auto & value){ + std::cout << value << '\n'; + }) || []{ std::cerr << "No such key!\n"; }; + }) || []{ std::cerr << "No such setting!\n"; }; +} diff --git a/src/optional.hpp b/src/optional.hpp new file mode 100644 index 0000000..c178d59 --- /dev/null +++ b/src/optional.hpp @@ -0,0 +1,36 @@ +#ifndef WANDA_OPTIONAL_HPP +#define WANDA_OPTIONAL_HPP + +#include <optional> + +namespace wanda::std_ext { + +struct failable { + + constexpr static auto success() { return failable{false}; } + constexpr static auto failure() { return failable{true}; } + + template<typename Handler> + constexpr auto operator ||(Handler handler) const { + if(m_failed) { + handler(); + } + } + +private: + constexpr explicit failable(bool failed) : m_failed{failed} { }; + bool const m_failed; +}; + +template<typename ObjectType, typename HandlerType> +auto with(std::optional<ObjectType> && object, HandlerType handler) { + if(object) { + handler(object.value()); + return failable::success(); + } + return failable::failure(); +} + +} + +#endif
\ No newline at end of file diff --git a/src/setting.cpp b/src/setting.cpp new file mode 100644 index 0000000..9ddbfe8 --- /dev/null +++ b/src/setting.cpp @@ -0,0 +1,29 @@ +#include "setting.hpp" + +namespace wanda { + +namespace literals { + key operator""_key(char const * str, std::size_t len) { + return key{{str, len}}; + } + + std::optional<setting> operator""_setting(char const * str, std::size_t len) { + auto source = g_settings_schema_source_get_default(); + auto schema = g_settings_schema_source_lookup(source, str, true); + if(schema) { + g_settings_schema_unref(schema); + return setting{::wanda::schema{{str, len}}}; + } + return std::nullopt; + } +} + +setting::setting(schema schema) : m_value{g_settings_new(schema.get().c_str())} { } + +setting::setting(setting const & other) : m_value{reinterpret_cast<GSettings *>(g_object_ref(other.m_value))} { } + +setting::~setting() { + g_clear_object(&m_value); +} + +}
\ No newline at end of file diff --git a/src/setting.hpp b/src/setting.hpp new file mode 100644 index 0000000..6293dd3 --- /dev/null +++ b/src/setting.hpp @@ -0,0 +1,48 @@ +#ifndef WANDA_setting_HPP +#define WANDA_setting_HPP + +#include <gio/gio.h> + +#include <cstddef> +#include <optional> +#include <string> +#include <type_traits> + +#include "type_wrapper.hpp" +#include "variant.hpp" +#include <iostream> + +namespace wanda { + +struct setting; +using schema = type_wrapper<std::string, struct SchemaTag>; +using key = type_wrapper<std::string, struct KeyTag>; + +namespace literals { +key operator""_key(char const * str, std::size_t len); +std::optional<setting> operator""_setting(char const * str, std::size_t len); +} + +struct setting { + ~setting(); + + setting(setting const & other); + + template<typename TargetType> std::optional<TargetType> get(key key) const { + auto value = variant{g_settings_get_value(m_value, key.get().c_str())}; + return value.get<TargetType>(); + } + +private: + explicit setting(schema schema); + + GSettings * m_value; + + friend std::optional<setting> literals::operator""_setting(char const *, std::size_t); +}; + + +} + + +#endif
\ No newline at end of file diff --git a/src/type_wrapper.hpp b/src/type_wrapper.hpp new file mode 100644 index 0000000..d3bf694 --- /dev/null +++ b/src/type_wrapper.hpp @@ -0,0 +1,23 @@ +#ifndef WANDA_TYPE_WRAPPER_HPP +#define WANDA_TYPE_WRAPPER_HPP + +#include <utility> + +namespace wanda { + +template<typename InnerType, typename TagType> +struct type_wrapper { + + explicit type_wrapper(InnerType value) : m_value{std::move(value)} { } + + constexpr explicit operator InnerType const & () const { return get(); } + + constexpr InnerType const & get() const { return m_value; } + +private: + InnerType const m_value; +}; + +} + +#endif
\ No newline at end of file diff --git a/src/variant.cpp b/src/variant.cpp new file mode 100644 index 0000000..54e484e --- /dev/null +++ b/src/variant.cpp @@ -0,0 +1,17 @@ +#include "variant.hpp" + +namespace wanda { + +variant::variant(GVariant * value) : m_value{value} { } + +variant::~variant() { + if(m_value) { + g_variant_unref(m_value); + } +} + +bool variant::is_of_type(GVariantType const * const type) const { + return g_variant_is_of_type(m_value, type); +} + +}
\ No newline at end of file diff --git a/src/variant.hpp b/src/variant.hpp new file mode 100644 index 0000000..8a5fb03 --- /dev/null +++ b/src/variant.hpp @@ -0,0 +1,47 @@ +#ifndef WANDA_VARIANT_HPP +#define WANDA_VARIANT_HPP + +#include <gio/gio.h> + +#include <optional> +#include <string> +#include <type_traits> + +namespace wanda { + +struct variant { + + explicit variant(GVariant * variant); + + ~variant(); + + template<typename Type> std::optional<Type> get() const { + if(!m_value) { + return std::nullopt; + } + + if constexpr(std::is_same_v<Type, bool>) { + if(is_of_type(G_VARIANT_TYPE_BOOLEAN)) { + return static_cast<bool>(g_variant_get_boolean(m_value)); + } + } else if constexpr(std::is_same_v<Type, std::string>) { + if(is_of_type(G_VARIANT_TYPE_STRING)) { + auto length = gsize{}; + auto value = g_variant_get_string(m_value, &length); + return std::string(value, static_cast<std::size_t>(length)); + } + } + + return std::nullopt; + } + + +private: + bool is_of_type(GVariantType const * const type) const; + + GVariant * const m_value; +}; + +} + +#endif
\ No newline at end of file |
