Changeset View
Changeset View
Standalone View
Standalone View
plugins/platforms/x11/standalone/screens_xrandr.cpp
Show All 12 Lines | |||||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | 15 | GNU General Public License for more details. | ||
16 | 16 | | |||
17 | You should have received a copy of the GNU General Public License | 17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | *********************************************************************/ | 19 | *********************************************************************/ | ||
20 | #include "screens_xrandr.h" | 20 | #include "screens_xrandr.h" | ||
21 | #include "x11_platform.h" | ||||
22 | | ||||
21 | #ifndef KWIN_UNIT_TEST | 23 | #ifndef KWIN_UNIT_TEST | ||
22 | #include "composite.h" | 24 | #include "composite.h" | ||
23 | #include "options.h" | 25 | #include "options.h" | ||
24 | #include "workspace.h" | 26 | #include "workspace.h" | ||
25 | #endif | 27 | #endif | ||
26 | #include "xcbutils.h" | 28 | #include "xcbutils.h" | ||
27 | 29 | | |||
28 | 30 | | |||
29 | namespace KWin | 31 | namespace KWin | ||
30 | { | 32 | { | ||
31 | 33 | | |||
32 | XRandRScreens::XRandRScreens(QObject *parent) | 34 | XRandRScreens::XRandRScreens(X11StandalonePlatform *backend, QObject *parent) | ||
33 | : Screens(parent) | 35 | : OutputScreens(backend, parent) | ||
34 | , X11EventFilter(Xcb::Extensions::self()->randrNotifyEvent()) | 36 | , X11EventFilter(Xcb::Extensions::self()->randrNotifyEvent()) | ||
37 | , m_backend(backend) | ||||
35 | { | 38 | { | ||
36 | } | 39 | } | ||
37 | 40 | | |||
38 | XRandRScreens::~XRandRScreens() = default; | 41 | XRandRScreens::~XRandRScreens() = default; | ||
39 | 42 | | |||
40 | template <typename T> | | |||
41 | void XRandRScreens::update() | | |||
42 | { | | |||
43 | auto fallback = [this]() { | | |||
44 | m_geometries << QRect(); | | |||
45 | m_refreshRates << -1.0f; | | |||
46 | m_names << "Xinerama"; | | |||
47 | setCount(1); | | |||
48 | }; | | |||
49 | m_geometries.clear(); | | |||
50 | m_names.clear(); | | |||
51 | if (!Xcb::Extensions::self()->isRandrAvailable()) { | | |||
52 | fallback(); | | |||
53 | return; | | |||
54 | } | | |||
55 | T resources(rootWindow()); | | |||
56 | if (resources.isNull()) { | | |||
57 | fallback(); | | |||
58 | return; | | |||
59 | } | | |||
60 | xcb_randr_crtc_t *crtcs = resources.crtcs(); | | |||
61 | xcb_randr_mode_info_t *modes = resources.modes(); | | |||
62 | | ||||
63 | QVector<Xcb::RandR::CrtcInfo> infos(resources->num_crtcs); | | |||
64 | for (int i = 0; i < resources->num_crtcs; ++i) { | | |||
65 | infos[i] = Xcb::RandR::CrtcInfo(crtcs[i], resources->config_timestamp); | | |||
66 | } | | |||
67 | | ||||
68 | for (int i = 0; i < resources->num_crtcs; ++i) { | | |||
69 | Xcb::RandR::CrtcInfo info(infos.at(i)); | | |||
70 | | ||||
71 | xcb_randr_output_t *outputs = info.outputs(); | | |||
72 | QVector<Xcb::RandR::OutputInfo> outputInfos(outputs ? resources->num_outputs : 0); | | |||
73 | if (outputs) { | | |||
74 | for (int i = 0; i < resources->num_outputs; ++i) { | | |||
75 | outputInfos[i] = Xcb::RandR::OutputInfo(outputs[i], resources->config_timestamp); | | |||
76 | } | | |||
77 | } | | |||
78 | | ||||
79 | float refreshRate = -1.0f; | | |||
80 | for (int j = 0; j < resources->num_modes; ++j) { | | |||
81 | if (info->mode == modes[j].id) { | | |||
82 | if (modes[j].htotal != 0 && modes[j].vtotal != 0) { // BUG 313996 | | |||
83 | // refresh rate calculation - WTF was wikipedia 1998 when I needed it? | | |||
84 | int dotclock = modes[j].dot_clock, | | |||
85 | vtotal = modes[j].vtotal; | | |||
86 | if (modes[j].mode_flags & XCB_RANDR_MODE_FLAG_INTERLACE) | | |||
87 | dotclock *= 2; | | |||
88 | if (modes[j].mode_flags & XCB_RANDR_MODE_FLAG_DOUBLE_SCAN) | | |||
89 | vtotal *= 2; | | |||
90 | refreshRate = dotclock/float(modes[j].htotal*vtotal); | | |||
91 | } | | |||
92 | break; // found mode | | |||
93 | } | | |||
94 | } | | |||
95 | | ||||
96 | const QRect geo = info.rect(); | | |||
97 | if (geo.isValid()) { | | |||
98 | m_geometries << geo; | | |||
99 | m_refreshRates << refreshRate; | | |||
100 | QString name; | | |||
101 | for (int j = 0; j < info->num_outputs; ++j) { | | |||
102 | Xcb::RandR::OutputInfo outputInfo(outputInfos.at(j)); | | |||
103 | if (crtcs[i] == outputInfo->crtc) { | | |||
104 | name = outputInfo.name(); | | |||
105 | break; | | |||
106 | } | | |||
107 | } | | |||
108 | m_names << name; | | |||
109 | } | | |||
110 | } | | |||
111 | if (m_geometries.isEmpty()) { | | |||
112 | fallback(); | | |||
113 | return; | | |||
114 | } | | |||
115 | | ||||
116 | setCount(m_geometries.count()); | | |||
117 | } | | |||
118 | | ||||
119 | | ||||
120 | void XRandRScreens::init() | 43 | void XRandRScreens::init() | ||
121 | { | 44 | { | ||
122 | KWin::Screens::init(); | 45 | KWin::Screens::init(); | ||
123 | // we need to call ScreenResources at least once to be able to use current | 46 | // we need to call ScreenResources at least once to be able to use current | ||
124 | update<Xcb::RandR::ScreenResources>(); | 47 | m_backend->initOutputs(); | ||
48 | setCount(m_backend->outputs().count()); | ||||
125 | emit changed(); | 49 | emit changed(); | ||
126 | } | 50 | } | ||
127 | 51 | | |||
128 | QRect XRandRScreens::geometry(int screen) const | | |||
129 | { | | |||
130 | if (screen >= m_geometries.size() || screen < 0) { | | |||
131 | return QRect(); | | |||
132 | } | | |||
133 | return m_geometries.at(screen).isValid() ? m_geometries.at(screen) : | | |||
134 | QRect(QPoint(0, 0), displaySize()); // xinerama, lacks RandR | | |||
135 | } | | |||
136 | | ||||
137 | QString XRandRScreens::name(int screen) const | | |||
138 | { | | |||
139 | if (screen >= m_names.size() || screen < 0) { | | |||
140 | return QString(); | | |||
141 | } | | |||
142 | return m_names.at(screen); | | |||
143 | } | | |||
144 | | ||||
145 | int XRandRScreens::number(const QPoint &pos) const | | |||
146 | { | | |||
147 | int bestScreen = 0; | | |||
148 | int minDistance = INT_MAX; | | |||
149 | for (int i = 0; i < m_geometries.size(); ++i) { | | |||
150 | const QRect &geo = m_geometries.at(i); | | |||
151 | if (geo.contains(pos)) { | | |||
152 | return i; | | |||
153 | } | | |||
154 | int distance = QPoint(geo.topLeft() - pos).manhattanLength(); | | |||
155 | distance = qMin(distance, QPoint(geo.topRight() - pos).manhattanLength()); | | |||
156 | distance = qMin(distance, QPoint(geo.bottomRight() - pos).manhattanLength()); | | |||
157 | distance = qMin(distance, QPoint(geo.bottomLeft() - pos).manhattanLength()); | | |||
158 | if (distance < minDistance) { | | |||
159 | minDistance = distance; | | |||
160 | bestScreen = i; | | |||
161 | } | | |||
162 | } | | |||
163 | return bestScreen; | | |||
164 | } | | |||
165 | | ||||
166 | float XRandRScreens::refreshRate(int screen) const | | |||
167 | { | | |||
168 | if (screen >= m_refreshRates.size() || screen < 0) { | | |||
169 | return -1.0f; | | |||
170 | } | | |||
171 | return m_refreshRates.at(screen); | | |||
172 | } | | |||
173 | | ||||
174 | QSize XRandRScreens::size(int screen) const | | |||
175 | { | | |||
176 | const QRect geo = geometry(screen); | | |||
177 | if (!geo.isValid()) { | | |||
178 | return QSize(); | | |||
179 | } | | |||
180 | return geo.size(); | | |||
181 | } | | |||
182 | | ||||
183 | void XRandRScreens::updateCount() | 52 | void XRandRScreens::updateCount() | ||
184 | { | 53 | { | ||
185 | update<Xcb::RandR::CurrentResources>(); | 54 | m_backend->updateOutputs(); | ||
55 | setCount(m_backend->outputs().count()); | ||||
186 | } | 56 | } | ||
187 | 57 | | |||
188 | bool XRandRScreens::event(xcb_generic_event_t *event) | 58 | bool XRandRScreens::event(xcb_generic_event_t *event) | ||
189 | { | 59 | { | ||
190 | Q_ASSERT((event->response_type & ~0x80) == Xcb::Extensions::self()->randrNotifyEvent()); | 60 | Q_ASSERT((event->response_type & ~0x80) == Xcb::Extensions::self()->randrNotifyEvent()); | ||
191 | // let's try to gather a few XRandR events, unlikely that there is just one | 61 | // let's try to gather a few XRandR events, unlikely that there is just one | ||
192 | startChangedTimer(); | 62 | startChangedTimer(); | ||
193 | 63 | | |||
Show All 37 Lines |