aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.vscode/settings.json13
-rw-r--r--CMakeLists.txt32
-rw-r--r--cmake/Modules/ConanDependencies.cmake9
-rw-r--r--cmake/Modules/SystemDependencies.cmake7
-rw-r--r--conanfile.py25
-rw-r--r--src/main.cpp16
-rw-r--r--src/optional.hpp36
-rw-r--r--src/setting.cpp29
-rw-r--r--src/setting.hpp48
-rw-r--r--src/type_wrapper.hpp23
-rw-r--r--src/variant.cpp17
-rw-r--r--src/variant.hpp47
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