summaryrefslogtreecommitdiffstats
path: root/xbmc/windowing/wayland/Output.h
blob: 2408a6f21bbf9fdd645831292a12d1ec201b567d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
 *  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.
 */

#pragma once

#include "threads/CriticalSection.h"
#include "utils/Geometry.h"

#include <atomic>
#include <cstdint>
#include <mutex>
#include <set>
#include <tuple>

#include <wayland-client-protocol.hpp>

namespace KODI
{
namespace WINDOWING
{
namespace WAYLAND
{

/**
 * wl_output handler that collects information from the compositor and then
 * passes it on when everything is available
 */
class COutput
{
public:
  COutput(std::uint32_t globalName, wayland::output_t const & output, std::function<void()> doneHandler);
  ~COutput() noexcept;

  wayland::output_t const& GetWaylandOutput() const
  {
    return m_output;
  }
  std::uint32_t GetGlobalName() const
  {
    return m_globalName;
  }
  /**
   * Get output position in compositor coordinate space
   * \return (x, y) tuple of output position
   */
  CPointInt GetPosition() const
  {
    std::unique_lock<CCriticalSection> lock(m_geometryCriticalSection);
    return m_position;
  }
  /**
   * Get output physical size in millimeters
   * \return (width, height) tuple of output physical size in millimeters
   */
  CSizeInt GetPhysicalSize() const
  {
    std::unique_lock<CCriticalSection> lock(m_geometryCriticalSection);
    return m_physicalSize;
  }
  std::string const& GetMake() const
  {
    std::unique_lock<CCriticalSection> lock(m_geometryCriticalSection);
    return m_make;
  }
  std::string const& GetModel() const
  {
    std::unique_lock<CCriticalSection> lock(m_geometryCriticalSection);
    return m_model;
  }
  std::int32_t GetScale() const
  {
    return m_scale;
  }

  struct Mode
  {
    CSizeInt size;
    std::int32_t refreshMilliHz;
    Mode(CSizeInt size, std::int32_t refreshMilliHz)
    : size{size}, refreshMilliHz(refreshMilliHz)
    {}

    float GetRefreshInHz() const
    {
      return refreshMilliHz / 1000.0f;
    }

    std::tuple<std::int32_t, std::int32_t, std::int32_t> AsTuple() const
    {
      return std::make_tuple(size.Width(), size.Height(), refreshMilliHz);
    }

    // Comparison operator needed for std::set
    bool operator<(const Mode& right) const
    {
      return AsTuple() < right.AsTuple();
    }

    bool operator==(const Mode& right) const
    {
      return AsTuple() == right.AsTuple();
    }

    bool operator!=(const Mode& right) const
    {
      return !(*this == right);
    }
  };

  std::set<Mode> const& GetModes() const
  {
    return m_modes;
  }
  Mode const& GetCurrentMode() const;
  Mode const& GetPreferredMode() const;

  float GetPixelRatioForMode(Mode const& mode) const;
  float GetDpiForMode(Mode const& mode) const;
  float GetCurrentDpi() const;

private:
  COutput(COutput const& other) = delete;
  COutput& operator=(COutput const& other) = delete;

  std::uint32_t m_globalName;
  wayland::output_t m_output;
  std::function<void()> m_doneHandler;

  mutable CCriticalSection m_geometryCriticalSection;
  mutable CCriticalSection m_iteratorCriticalSection;

  CPointInt m_position;
  CSizeInt m_physicalSize;
  std::string m_make, m_model;
  std::atomic<std::int32_t> m_scale{1}; // default scale of 1 if no wl_output::scale is sent

  std::set<Mode> m_modes;
  // For std::set, insertion never invalidates existing iterators, and modes are
  // never removed, so the usage of iterators is safe
  std::set<Mode>::iterator m_currentMode{m_modes.end()};
  std::set<Mode>::iterator m_preferredMode{m_modes.end()};
};


}
}
}