diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f0df8b26c..956a99cb49 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -426,6 +426,7 @@ endif()
if(Wayland_Client_FOUND AND XKB_FOUND)
set(kwin_KDEINIT_SRCS
${kwin_KDEINIT_SRCS}
+ screens_wayland.cpp
wayland_backend.cpp
wayland_client/buffer.cpp
wayland_client/compositor.cpp
diff --git a/screens.cpp b/screens.cpp
index 01dbbc20c5..ee76051faa 100644
--- a/screens.cpp
+++ b/screens.cpp
@@ -22,10 +22,9 @@ along with this program. If not, see .
#include "cursor.h"
#include "settings.h"
#include "workspace.h"
+#include
#if HAVE_WAYLAND
-#include "wayland_backend.h"
-#include "wayland_client/output.h"
-#include
+#include "screens_wayland.h"
#endif
#include
@@ -209,228 +208,4 @@ void DesktopWidgetScreens::updateCount()
setCount(m_desktop->screenCount());
}
-#if HAVE_WAYLAND
-WaylandScreens::WaylandScreens(QObject* parent)
- : Screens(parent)
-{
-}
-
-WaylandScreens::~WaylandScreens()
-{
-}
-
-void WaylandScreens::init()
-{
- Screens::init();
- connect(Wayland::WaylandBackend::self(), &Wayland::WaylandBackend::outputsChanged,
- this, &WaylandScreens::startChangedTimer);
- updateCount();
-}
-
-QRect WaylandScreens::geometry(int screen) const
-{
- if (screen >= m_geometries.size()) {
- return QRect();
- }
- return m_geometries.at(screen);
-}
-
-QSize WaylandScreens::size(int screen) const
-{
- return geometry(screen).size();
-}
-
-int WaylandScreens::number(const QPoint &pos) const
-{
- int bestScreen = 0;
- int minDistance = INT_MAX;
- for (int i = 0; i < m_geometries.size(); ++i) {
- const QRect &geo = m_geometries.at(i);
- if (geo.contains(pos)) {
- return i;
- }
- int distance = QPoint(geo.topLeft() - pos).manhattanLength();
- distance = qMin(distance, QPoint(geo.topRight() - pos).manhattanLength());
- distance = qMin(distance, QPoint(geo.bottomRight() - pos).manhattanLength());
- distance = qMin(distance, QPoint(geo.bottomLeft() - pos).manhattanLength());
- if (distance < minDistance) {
- minDistance = distance;
- bestScreen = i;
- }
- }
- return bestScreen;
-}
-
-void WaylandScreens::updateCount()
-{
- m_geometries.clear();
- int count = 0;
- const QList &outputs = Wayland::WaylandBackend::self()->outputs();
- for (auto it = outputs.begin(); it != outputs.end(); ++it) {
- if ((*it)->pixelSize().isEmpty()) {
- continue;
- }
- count++;
- m_geometries.append(QRect((*it)->globalPosition(), (*it)->pixelSize()));
- }
- if (m_geometries.isEmpty()) {
- // we need a fake screen
- m_geometries.append(QRect(0, 0, displayWidth(), displayHeight()));
- setCount(1);
- return;
- }
- setCount(m_geometries.count());
- updateXRandr();
- emit changed();
-}
-
-namespace RandR
-{
-using namespace Xcb;
-XCB_WRAPPER(CurrentResources, xcb_randr_get_screen_resources_current, xcb_window_t)
-}
-
-static bool setNewScreenSize(const QSize &size)
-{
- auto c = xcb_randr_set_screen_size_checked(connection(), rootWindow(), size.width(), size.height(), 1, 1);
- ScopedCPointer error(xcb_request_check(connection(), c));
- if (!error.isNull()) {
- qDebug() << "Error setting screen size: " << error->error_code;
- return false;
- }
- return true;
-}
-
-static xcb_randr_crtc_t getCrtc(const xcb_randr_get_screen_resources_current_reply_t* r)
-{
- if (xcb_randr_get_screen_resources_current_crtcs_length(r) == 0) {
- qDebug() << "No CRTCs";
- return XCB_NONE;
- }
- return xcb_randr_get_screen_resources_current_crtcs(r)[0];
-}
-
-static xcb_randr_output_t getOutputForCrtc(xcb_randr_crtc_t crtc)
-{
- ScopedCPointer info(xcb_randr_get_crtc_info_reply(
- connection(), xcb_randr_get_crtc_info(connection(), crtc, XCB_TIME_CURRENT_TIME), nullptr));
- if (info->num_outputs == 0) {
- return XCB_NONE;
- }
- return xcb_randr_get_crtc_info_outputs(info.data())[0];
-}
-
-static xcb_randr_mode_t createNewMode(const QSize &size)
-{
- // need to create the new mode
- qDebug() << "Creating a new mode";
- QString name(QString::number(size.width()));
- name.append('x');
- name.append(QString::number(size.height()));
- xcb_randr_mode_info_t newInfo;
- newInfo.dot_clock = 0;
- newInfo.height = size.height();
- newInfo.hskew = 0;
- newInfo.hsync_end = 0;
- newInfo.hsync_start = 0;
- newInfo.htotal = size.width();
- newInfo.id = 0;
- newInfo.mode_flags = 0;
- newInfo.vsync_end = 0;
- newInfo.vsync_start = 0;
- newInfo.vtotal = size.height();
- newInfo.width = size.width();
- newInfo.name_len = name.length();
- auto cookie = xcb_randr_create_mode_unchecked(connection(), rootWindow(), newInfo, name.length(), name.toUtf8().constData());
- ScopedCPointer reply(xcb_randr_create_mode_reply(connection(), cookie, nullptr));
- if (!reply.isNull()) {
- return reply->mode;
- }
- return XCB_NONE;
-}
-
-static xcb_randr_mode_t getModeForSize(const QSize &size, const xcb_randr_get_screen_resources_current_reply_t* r)
-{
- xcb_randr_mode_info_t *infos = xcb_randr_get_screen_resources_current_modes(r);
- const int modeInfoLength = xcb_randr_get_screen_resources_current_modes_length(r);
- // check available modes
- for (int i = 0; i < modeInfoLength; ++i) {
- xcb_randr_mode_info_t modeInfo = infos[i];
- if (modeInfo.width == size.width() && modeInfo.height == size.height()) {
- qDebug() << "Found our required mode";
- return modeInfo.id;
- }
- }
- // did not find our mode, so create it
- return createNewMode(size);
-}
-
-static bool addModeToOutput(xcb_randr_output_t output, xcb_randr_mode_t mode)
-{
- ScopedCPointer info(xcb_randr_get_output_info_reply(connection(),
- xcb_randr_get_output_info(connection(), output, XCB_TIME_CURRENT_TIME), nullptr));
- xcb_randr_mode_t *modes = xcb_randr_get_output_info_modes(info.data());
- for (int i = 0; i < info->num_modes; ++i) {
- if (modes[i] == mode) {
- return true;
- }
- }
- qDebug() << "Need to add the mode to output";
- auto c = xcb_randr_add_output_mode_checked(connection(), output, mode);
- ScopedCPointer error(xcb_request_check(connection(), c));
- if (!error.isNull()) {
- qDebug() << "Error while adding mode to output: " << error->error_code;
- return false;
- }
- return true;
-}
-
-void WaylandScreens::updateXRandr()
-{
- if (!Xcb::Extensions::self()->isRandrAvailable()) {
- qDebug() << "No RandR extension available, cannot sync with X";
- return;
- }
- QRegion screens;
- foreach (const QRect &rect, m_geometries) {
- screens = screens.united(rect);
- }
- const QSize &size = screens.boundingRect().size();
- if (size.isEmpty()) {
- return;
- }
-
- RandR::CurrentResources currentResources(rootWindow());
- xcb_randr_crtc_t crtc = getCrtc(currentResources.data());
- if (crtc == XCB_NONE) {
- return;
- }
- xcb_randr_output_t output = getOutputForCrtc(crtc);
- if (output == XCB_NONE) {
- return;
- }
- // first disable the first CRTC
- xcb_randr_set_crtc_config(connection(), crtc, XCB_TIME_CURRENT_TIME, XCB_TIME_CURRENT_TIME,
- 0, 0, XCB_NONE, XCB_RANDR_ROTATION_ROTATE_0, 0, nullptr);
-
- // then set new screen size
- if (!setNewScreenSize(size)) {
- return;
- }
-
- xcb_randr_mode_t mode = getModeForSize(size, currentResources.data());
- if (mode == XCB_NONE) {
- return;
- }
-
- if (!addModeToOutput(output, mode)) {
- return;
- }
- // enable CRTC again
- xcb_randr_set_crtc_config(connection(), crtc, XCB_TIME_CURRENT_TIME, XCB_TIME_CURRENT_TIME,
- 0, 0, mode, XCB_RANDR_ROTATION_ROTATE_0, 1, &output);
-}
-
-#endif
-
} // namespace
diff --git a/screens.h b/screens.h
index 0d7e56476e..25fed8052f 100644
--- a/screens.h
+++ b/screens.h
@@ -22,7 +22,6 @@ along with this program. If not, see .
// KWin includes
#include
-#include
// KDE includes
#include
#include
@@ -161,26 +160,6 @@ private:
QDesktopWidget *m_desktop;
};
-#if HAVE_WAYLAND
-class WaylandScreens : public Screens
-{
- Q_OBJECT
-public:
- explicit WaylandScreens(QObject *parent);
- virtual ~WaylandScreens();
- void init() override;
- QRect geometry(int screen) const override;
- QSize size(int screen) const override;
- int number(const QPoint& pos) const override;
-
-protected Q_SLOTS:
- void updateCount() override;
-private:
- void updateXRandr();
- QList m_geometries;
-};
-#endif
-
inline
void Screens::setConfig(KSharedConfig::Ptr config)
{
diff --git a/screens_wayland.cpp b/screens_wayland.cpp
new file mode 100644
index 0000000000..398d92bdd8
--- /dev/null
+++ b/screens_wayland.cpp
@@ -0,0 +1,254 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2013 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+#include "screens_wayland.h"
+
+#include "wayland_backend.h"
+#include "wayland_client/output.h"
+#include "xcbutils.h"
+
+#include
+
+#include
+
+namespace KWin
+{
+
+WaylandScreens::WaylandScreens(QObject* parent)
+ : Screens(parent)
+{
+}
+
+WaylandScreens::~WaylandScreens()
+{
+}
+
+void WaylandScreens::init()
+{
+ Screens::init();
+ connect(Wayland::WaylandBackend::self(), &Wayland::WaylandBackend::outputsChanged,
+ this, &WaylandScreens::startChangedTimer);
+ updateCount();
+}
+
+QRect WaylandScreens::geometry(int screen) const
+{
+ if (screen >= m_geometries.size()) {
+ return QRect();
+ }
+ return m_geometries.at(screen);
+}
+
+QSize WaylandScreens::size(int screen) const
+{
+ return geometry(screen).size();
+}
+
+int WaylandScreens::number(const QPoint &pos) const
+{
+ int bestScreen = 0;
+ int minDistance = INT_MAX;
+ for (int i = 0; i < m_geometries.size(); ++i) {
+ const QRect &geo = m_geometries.at(i);
+ if (geo.contains(pos)) {
+ return i;
+ }
+ int distance = QPoint(geo.topLeft() - pos).manhattanLength();
+ distance = qMin(distance, QPoint(geo.topRight() - pos).manhattanLength());
+ distance = qMin(distance, QPoint(geo.bottomRight() - pos).manhattanLength());
+ distance = qMin(distance, QPoint(geo.bottomLeft() - pos).manhattanLength());
+ if (distance < minDistance) {
+ minDistance = distance;
+ bestScreen = i;
+ }
+ }
+ return bestScreen;
+}
+
+void WaylandScreens::updateCount()
+{
+ m_geometries.clear();
+ int count = 0;
+ const QList &outputs = Wayland::WaylandBackend::self()->outputs();
+ for (auto it = outputs.begin(); it != outputs.end(); ++it) {
+ if ((*it)->pixelSize().isEmpty()) {
+ continue;
+ }
+ count++;
+ m_geometries.append(QRect((*it)->globalPosition(), (*it)->pixelSize()));
+ }
+ if (m_geometries.isEmpty()) {
+ // we need a fake screen
+ m_geometries.append(QRect(0, 0, displayWidth(), displayHeight()));
+ setCount(1);
+ return;
+ }
+ setCount(m_geometries.count());
+ updateXRandr();
+ emit changed();
+}
+
+namespace RandR
+{
+using namespace Xcb;
+XCB_WRAPPER(CurrentResources, xcb_randr_get_screen_resources_current, xcb_window_t)
+}
+
+static bool setNewScreenSize(const QSize &size)
+{
+ auto c = xcb_randr_set_screen_size_checked(connection(), rootWindow(), size.width(), size.height(), 1, 1);
+ ScopedCPointer error(xcb_request_check(connection(), c));
+ if (!error.isNull()) {
+ qDebug() << "Error setting screen size: " << error->error_code;
+ return false;
+ }
+ return true;
+}
+
+static xcb_randr_crtc_t getCrtc(const xcb_randr_get_screen_resources_current_reply_t* r)
+{
+ if (xcb_randr_get_screen_resources_current_crtcs_length(r) == 0) {
+ qDebug() << "No CRTCs";
+ return XCB_NONE;
+ }
+ return xcb_randr_get_screen_resources_current_crtcs(r)[0];
+}
+
+static xcb_randr_output_t getOutputForCrtc(xcb_randr_crtc_t crtc)
+{
+ ScopedCPointer info(xcb_randr_get_crtc_info_reply(
+ connection(), xcb_randr_get_crtc_info(connection(), crtc, XCB_TIME_CURRENT_TIME), nullptr));
+ if (info->num_outputs == 0) {
+ return XCB_NONE;
+ }
+ return xcb_randr_get_crtc_info_outputs(info.data())[0];
+}
+
+static xcb_randr_mode_t createNewMode(const QSize &size)
+{
+ // need to create the new mode
+ qDebug() << "Creating a new mode";
+ QString name(QString::number(size.width()));
+ name.append('x');
+ name.append(QString::number(size.height()));
+ xcb_randr_mode_info_t newInfo;
+ newInfo.dot_clock = 0;
+ newInfo.height = size.height();
+ newInfo.hskew = 0;
+ newInfo.hsync_end = 0;
+ newInfo.hsync_start = 0;
+ newInfo.htotal = size.width();
+ newInfo.id = 0;
+ newInfo.mode_flags = 0;
+ newInfo.vsync_end = 0;
+ newInfo.vsync_start = 0;
+ newInfo.vtotal = size.height();
+ newInfo.width = size.width();
+ newInfo.name_len = name.length();
+ auto cookie = xcb_randr_create_mode_unchecked(connection(), rootWindow(), newInfo, name.length(), name.toUtf8().constData());
+ ScopedCPointer reply(xcb_randr_create_mode_reply(connection(), cookie, nullptr));
+ if (!reply.isNull()) {
+ return reply->mode;
+ }
+ return XCB_NONE;
+}
+
+static xcb_randr_mode_t getModeForSize(const QSize &size, const xcb_randr_get_screen_resources_current_reply_t* r)
+{
+ xcb_randr_mode_info_t *infos = xcb_randr_get_screen_resources_current_modes(r);
+ const int modeInfoLength = xcb_randr_get_screen_resources_current_modes_length(r);
+ // check available modes
+ for (int i = 0; i < modeInfoLength; ++i) {
+ xcb_randr_mode_info_t modeInfo = infos[i];
+ if (modeInfo.width == size.width() && modeInfo.height == size.height()) {
+ qDebug() << "Found our required mode";
+ return modeInfo.id;
+ }
+ }
+ // did not find our mode, so create it
+ return createNewMode(size);
+}
+
+static bool addModeToOutput(xcb_randr_output_t output, xcb_randr_mode_t mode)
+{
+ ScopedCPointer info(xcb_randr_get_output_info_reply(connection(),
+ xcb_randr_get_output_info(connection(), output, XCB_TIME_CURRENT_TIME), nullptr));
+ xcb_randr_mode_t *modes = xcb_randr_get_output_info_modes(info.data());
+ for (int i = 0; i < info->num_modes; ++i) {
+ if (modes[i] == mode) {
+ return true;
+ }
+ }
+ qDebug() << "Need to add the mode to output";
+ auto c = xcb_randr_add_output_mode_checked(connection(), output, mode);
+ ScopedCPointer error(xcb_request_check(connection(), c));
+ if (!error.isNull()) {
+ qDebug() << "Error while adding mode to output: " << error->error_code;
+ return false;
+ }
+ return true;
+}
+
+void WaylandScreens::updateXRandr()
+{
+ if (!Xcb::Extensions::self()->isRandrAvailable()) {
+ qDebug() << "No RandR extension available, cannot sync with X";
+ return;
+ }
+ QRegion screens;
+ foreach (const QRect &rect, m_geometries) {
+ screens = screens.united(rect);
+ }
+ const QSize &size = screens.boundingRect().size();
+ if (size.isEmpty()) {
+ return;
+ }
+
+ RandR::CurrentResources currentResources(rootWindow());
+ xcb_randr_crtc_t crtc = getCrtc(currentResources.data());
+ if (crtc == XCB_NONE) {
+ return;
+ }
+ xcb_randr_output_t output = getOutputForCrtc(crtc);
+ if (output == XCB_NONE) {
+ return;
+ }
+ // first disable the first CRTC
+ xcb_randr_set_crtc_config(connection(), crtc, XCB_TIME_CURRENT_TIME, XCB_TIME_CURRENT_TIME,
+ 0, 0, XCB_NONE, XCB_RANDR_ROTATION_ROTATE_0, 0, nullptr);
+
+ // then set new screen size
+ if (!setNewScreenSize(size)) {
+ return;
+ }
+
+ xcb_randr_mode_t mode = getModeForSize(size, currentResources.data());
+ if (mode == XCB_NONE) {
+ return;
+ }
+
+ if (!addModeToOutput(output, mode)) {
+ return;
+ }
+ // enable CRTC again
+ xcb_randr_set_crtc_config(connection(), crtc, XCB_TIME_CURRENT_TIME, XCB_TIME_CURRENT_TIME,
+ 0, 0, mode, XCB_RANDR_ROTATION_ROTATE_0, 1, &output);
+}
+
+}
diff --git a/screens_wayland.h b/screens_wayland.h
new file mode 100644
index 0000000000..0063df1b0b
--- /dev/null
+++ b/screens_wayland.h
@@ -0,0 +1,48 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2013 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+#ifndef KWIN_SCREENS_WAYLAND_H
+#define KWIN_SCREENS_WAYLAND_H
+
+#include "screens.h"
+
+namespace KWin
+{
+
+class WaylandScreens : public Screens
+{
+ Q_OBJECT
+public:
+ explicit WaylandScreens(QObject *parent);
+ virtual ~WaylandScreens();
+ void init() override;
+ QRect geometry(int screen) const override;
+ QSize size(int screen) const override;
+ int number(const QPoint& pos) const override;
+
+protected Q_SLOTS:
+ void updateCount() override;
+private:
+ void updateXRandr();
+ QList m_geometries;
+};
+
+}
+
+#endif