summaryrefslogtreecommitdiffstats
path: root/xbmc/windowing/wayland/Output.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/windowing/wayland/Output.cpp')
-rw-r--r--xbmc/windowing/wayland/Output.cpp145
1 files changed, 145 insertions, 0 deletions
diff --git a/xbmc/windowing/wayland/Output.cpp b/xbmc/windowing/wayland/Output.cpp
new file mode 100644
index 0000000..5dd840a
--- /dev/null
+++ b/xbmc/windowing/wayland/Output.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "Output.h"
+
+#include <cassert>
+#include <cmath>
+#include <mutex>
+#include <set>
+#include <stdexcept>
+#include <utility>
+
+using namespace KODI::WINDOWING::WAYLAND;
+
+COutput::COutput(std::uint32_t globalName,
+ wayland::output_t const& output,
+ std::function<void()> doneHandler)
+ : m_globalName{globalName}, m_output{output}, m_doneHandler{std::move(doneHandler)}
+{
+ assert(m_output);
+
+ m_output.on_geometry() = [this](std::int32_t x, std::int32_t y, std::int32_t physWidth,
+ std::int32_t physHeight, wayland::output_subpixel,
+ std::string const& make, std::string const& model,
+ const wayland::output_transform&)
+ {
+ std::unique_lock<CCriticalSection> lock(m_geometryCriticalSection);
+ m_position = {x, y};
+ // Some monitors report invalid (negative) values that would cause an exception
+ // with CSizeInt
+ if (physWidth < 0 || physHeight < 0)
+ m_physicalSize = {};
+ else
+ m_physicalSize = {physWidth, physHeight};
+ m_make = make;
+ m_model = model;
+ };
+ m_output.on_mode() = [this](const wayland::output_mode& flags, std::int32_t width,
+ std::int32_t height, std::int32_t refresh) {
+ // std::set.emplace returns pair of iterator to the (possibly) inserted
+ // element and boolean information whether the element was actually added
+ // which we do not need
+ auto modeIterator = m_modes.emplace(CSizeInt{width, height}, refresh).first;
+ std::unique_lock<CCriticalSection> lock(m_iteratorCriticalSection);
+ // Remember current and preferred mode
+ // Current mode is the last one that was sent with current flag set
+ if (flags & wayland::output_mode::current)
+ {
+ m_currentMode = modeIterator;
+ }
+ if (flags & wayland::output_mode::preferred)
+ {
+ m_preferredMode = modeIterator;
+ }
+ };
+ m_output.on_scale() = [this](std::int32_t scale)
+ {
+ m_scale = scale;
+ };
+
+ m_output.on_done() = [this]()
+ {
+ m_doneHandler();
+ };
+}
+
+COutput::~COutput() noexcept
+{
+ // Reset event handlers - someone might still hold a reference to the output_t,
+ // causing events to be dispatched. They should not go to a deleted class.
+ m_output.on_geometry() = nullptr;
+ m_output.on_mode() = nullptr;
+ m_output.on_done() = nullptr;
+ m_output.on_scale() = nullptr;
+}
+
+const COutput::Mode& COutput::GetCurrentMode() const
+{
+ std::unique_lock<CCriticalSection> lock(m_iteratorCriticalSection);
+ if (m_currentMode == m_modes.end())
+ {
+ throw std::runtime_error("Current mode not set");
+ }
+ return *m_currentMode;
+}
+
+const COutput::Mode& COutput::GetPreferredMode() const
+{
+ std::unique_lock<CCriticalSection> lock(m_iteratorCriticalSection);
+ if (m_preferredMode == m_modes.end())
+ {
+ throw std::runtime_error("Preferred mode not set");
+ }
+ return *m_preferredMode;
+}
+
+float COutput::GetPixelRatioForMode(const Mode& mode) const
+{
+ std::unique_lock<CCriticalSection> lock(m_geometryCriticalSection);
+ if (m_physicalSize.IsZero() || mode.size.IsZero())
+ {
+ return 1.0f;
+ }
+ else
+ {
+ return (
+ (static_cast<float> (m_physicalSize.Width()) / static_cast<float> (mode.size.Width()))
+ /
+ (static_cast<float> (m_physicalSize.Height()) / static_cast<float> (mode.size.Height()))
+ );
+ }
+}
+
+float COutput::GetDpiForMode(const Mode& mode) const
+{
+ std::unique_lock<CCriticalSection> lock(m_geometryCriticalSection);
+ if (m_physicalSize.IsZero())
+ {
+ // We really have no idea, so use a "sane" default
+ return 96.0;
+ }
+ else
+ {
+ constexpr float INCH_MM_RATIO{25.4f};
+
+ float diagonalPixels = std::sqrt(mode.size.Width() * mode.size.Width() + mode.size.Height() * mode.size.Height());
+ // physicalWidth/physicalHeight is in millimeters
+ float diagonalInches =
+ std::sqrt(static_cast<float>(m_physicalSize.Width() * m_physicalSize.Width() +
+ m_physicalSize.Height() * m_physicalSize.Height())) /
+ INCH_MM_RATIO;
+
+ return diagonalPixels / diagonalInches;
+ }
+}
+
+float COutput::GetCurrentDpi() const
+{
+ return GetDpiForMode(GetCurrentMode());
+}