[platforms/x11/windowed] Port to AbstractOutput
Summary: To homogenize our backends and as another step to remove the Screens class use the AbstractOutput class in the windowed X11 backend. Test Plan: Manually in X session. Reviewers: #kwin, zzag Reviewed By: #kwin, zzag Subscribers: davidedmundson, zzag, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D19207
This commit is contained in:
parent
29e4ca26a6
commit
8040c559cb
5 changed files with 347 additions and 162 deletions
|
@ -3,6 +3,7 @@ set(X11BACKEND_SOURCES
|
|||
egl_x11_backend.cpp
|
||||
scene_qpainter_x11_backend.cpp
|
||||
x11windowed_backend.cpp
|
||||
x11windowed_output.cpp
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl)
|
||||
|
|
|
@ -18,25 +18,22 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "x11windowed_backend.h"
|
||||
#include "x11windowed_output.h"
|
||||
#include "scene_qpainter_x11_backend.h"
|
||||
#include "logging.h"
|
||||
#include "wayland_server.h"
|
||||
#include "xcbutils.h"
|
||||
#include "egl_x11_backend.h"
|
||||
#include "screens.h"
|
||||
#include "outputscreens.h"
|
||||
#include <kwinxrenderutils.h>
|
||||
// KDE
|
||||
#include <KLocalizedString>
|
||||
#include <NETWM>
|
||||
#include <QAbstractEventDispatcher>
|
||||
#include <QCoreApplication>
|
||||
#include <QIcon>
|
||||
#include <QSocketNotifier>
|
||||
// kwayland
|
||||
#include <KWayland/Server/buffer_interface.h>
|
||||
#include <KWayland/Server/display.h>
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/surface_interface.h>
|
||||
// xcb
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
// X11
|
||||
|
@ -65,11 +62,6 @@ X11WindowedBackend::~X11WindowedBackend()
|
|||
if (m_keySymbols) {
|
||||
xcb_key_symbols_free(m_keySymbols);
|
||||
}
|
||||
for (auto it = m_windows.begin(); it != m_windows.end(); ++it) {
|
||||
xcb_unmap_window(m_connection, (*it).window);
|
||||
xcb_destroy_window(m_connection, (*it).window);
|
||||
delete (*it).winInfo;
|
||||
}
|
||||
if (m_cursor) {
|
||||
xcb_free_cursor(m_connection, m_cursor);
|
||||
}
|
||||
|
@ -100,7 +92,7 @@ void X11WindowedBackend::init()
|
|||
}
|
||||
initXInput();
|
||||
XRenderUtils::init(m_connection, m_screen->root);
|
||||
createWindow();
|
||||
createOutputs();
|
||||
connect(kwinApp(), &Application::workspaceCreated, this, &X11WindowedBackend::startEventReading);
|
||||
connect(this, &X11WindowedBackend::cursorChanged, this,
|
||||
[this] {
|
||||
|
@ -147,64 +139,37 @@ void X11WindowedBackend::initXInput()
|
|||
#endif
|
||||
}
|
||||
|
||||
void X11WindowedBackend::createWindow()
|
||||
void X11WindowedBackend::createOutputs()
|
||||
{
|
||||
Xcb::Atom protocolsAtom(QByteArrayLiteral("WM_PROTOCOLS"), false, m_connection);
|
||||
Xcb::Atom deleteWindowAtom(QByteArrayLiteral("WM_DELETE_WINDOW"), false, m_connection);
|
||||
|
||||
// we need to multiply the initial window size with the scale in order to
|
||||
// create an output window of this size in the end
|
||||
const int pixelWidth = initialWindowSize().width() * initialOutputScale() + 0.5;
|
||||
const int pixelHeight = initialWindowSize().height() * initialOutputScale() + 0.5;
|
||||
const int logicalWidth = initialWindowSize().width();
|
||||
|
||||
int logicalWidthSum = 0;
|
||||
for (int i = 0; i < initialOutputCount(); ++i) {
|
||||
Output o;
|
||||
o.window = xcb_generate_id(m_connection);
|
||||
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
||||
const uint32_t values[] = {
|
||||
m_screen->black_pixel,
|
||||
XCB_EVENT_MASK_KEY_PRESS |
|
||||
XCB_EVENT_MASK_KEY_RELEASE |
|
||||
XCB_EVENT_MASK_BUTTON_PRESS |
|
||||
XCB_EVENT_MASK_BUTTON_RELEASE |
|
||||
XCB_EVENT_MASK_POINTER_MOTION |
|
||||
XCB_EVENT_MASK_ENTER_WINDOW |
|
||||
XCB_EVENT_MASK_LEAVE_WINDOW |
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_EXPOSURE
|
||||
};
|
||||
o.scale = initialOutputScale();
|
||||
o.size = initialWindowSize() * o.scale;
|
||||
if (!m_windows.isEmpty()) {
|
||||
const auto &p = m_windows.last();
|
||||
o.internalPosition = QPoint(p.internalPosition.x() + p.size.width() / p.scale, 0);
|
||||
}
|
||||
xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, o.window, m_screen->root,
|
||||
0, 0, o.size.width(), o.size.height(),
|
||||
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, mask, values);
|
||||
|
||||
// select xinput 2 events
|
||||
initXInputForWindow(o.window);
|
||||
|
||||
o.winInfo = new NETWinInfo(m_connection, o.window, m_screen->root, NET::WMWindowType, NET::Properties2());
|
||||
o.winInfo->setWindowType(NET::Normal);
|
||||
o.winInfo->setPid(QCoreApplication::applicationPid());
|
||||
QIcon windowIcon = QIcon::fromTheme(QStringLiteral("kwin"));
|
||||
auto addIcon = [&o, &windowIcon] (const QSize &size) {
|
||||
if (windowIcon.actualSize(size) != size) {
|
||||
return;
|
||||
}
|
||||
NETIcon icon;
|
||||
icon.data = windowIcon.pixmap(size).toImage().bits();
|
||||
icon.size.width = size.width();
|
||||
icon.size.height = size.height();
|
||||
o.winInfo->setIcon(icon, false);
|
||||
};
|
||||
addIcon(QSize(16, 16));
|
||||
addIcon(QSize(32, 32));
|
||||
addIcon(QSize(48, 48));
|
||||
|
||||
xcb_map_window(m_connection, o.window);
|
||||
auto *output = new X11WindowedOutput(this);
|
||||
output->setScale(initialOutputScale());
|
||||
output->setGeometry(QPoint(logicalWidthSum, 0), QSize(pixelWidth, pixelHeight));
|
||||
output->init();
|
||||
|
||||
m_protocols = protocolsAtom;
|
||||
m_deleteWindowProtocol = deleteWindowAtom;
|
||||
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, o.window, m_protocols, XCB_ATOM_ATOM, 32, 1, &m_deleteWindowProtocol);
|
||||
|
||||
m_windows << o;
|
||||
xcb_change_property(m_connection,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
output->window(),
|
||||
m_protocols,
|
||||
XCB_ATOM_ATOM,
|
||||
32, 1,
|
||||
&m_deleteWindowProtocol);
|
||||
|
||||
logicalWidthSum += logicalWidth;
|
||||
m_outputs << output;
|
||||
}
|
||||
|
||||
updateWindowTitle();
|
||||
|
@ -212,29 +177,6 @@ void X11WindowedBackend::createWindow()
|
|||
xcb_flush(m_connection);
|
||||
}
|
||||
|
||||
void X11WindowedBackend::initXInputForWindow(xcb_window_t window)
|
||||
{
|
||||
if (!m_hasXInput) {
|
||||
return;
|
||||
}
|
||||
#if HAVE_X11_XINPUT
|
||||
XIEventMask evmasks[1];
|
||||
unsigned char mask1[XIMaskLen(XI_LASTEVENT)];
|
||||
|
||||
memset(mask1, 0, sizeof(mask1));
|
||||
XISetMask(mask1, XI_TouchBegin);
|
||||
XISetMask(mask1, XI_TouchUpdate);
|
||||
XISetMask(mask1, XI_TouchOwnership);
|
||||
XISetMask(mask1, XI_TouchEnd);
|
||||
evmasks[0].deviceid = XIAllMasterDevices;
|
||||
evmasks[0].mask_len = sizeof(mask1);
|
||||
evmasks[0].mask = mask1;
|
||||
XISelectEvents(m_display, window, evmasks, 1);
|
||||
#else
|
||||
Q_UNUSED(window)
|
||||
#endif
|
||||
}
|
||||
|
||||
void X11WindowedBackend::startEventReading()
|
||||
{
|
||||
QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read, this);
|
||||
|
@ -268,15 +210,17 @@ void X11WindowedBackend::handleEvent(xcb_generic_event_t *e)
|
|||
break;
|
||||
case XCB_MOTION_NOTIFY: {
|
||||
auto event = reinterpret_cast<xcb_motion_notify_event_t*>(e);
|
||||
auto it = std::find_if(m_windows.constBegin(), m_windows.constEnd(), [event] (const Output &o) { return o.window == event->event; });
|
||||
if (it == m_windows.constEnd()) {
|
||||
auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(),
|
||||
[event] (X11WindowedOutput *output) { return output->window() == event->event; }
|
||||
);
|
||||
if (it == m_outputs.constEnd()) {
|
||||
break;
|
||||
}
|
||||
//generally we don't need to normalise input to the output scale; however because we're getting input
|
||||
//from a host window that doesn't understand scaling, we need to apply it ourselves so the cursor matches
|
||||
pointerMotion(QPointF(event->root_x - (*it).xPosition.x() + (*it).internalPosition.x(),
|
||||
event->root_y - (*it).xPosition.y() + (*it).internalPosition.y()) / it->scale,
|
||||
event->time);
|
||||
pointerMotion(QPointF(event->root_x - (*it)->hostPosition().x() + (*it)->internalPosition().x(),
|
||||
event->root_y - (*it)->hostPosition().y() + (*it)->internalPosition().y()) / (*it)->scale(),
|
||||
event->time);
|
||||
}
|
||||
break;
|
||||
case XCB_KEY_PRESS:
|
||||
|
@ -301,13 +245,15 @@ void X11WindowedBackend::handleEvent(xcb_generic_event_t *e)
|
|||
break;
|
||||
case XCB_ENTER_NOTIFY: {
|
||||
auto event = reinterpret_cast<xcb_enter_notify_event_t*>(e);
|
||||
auto it = std::find_if(m_windows.constBegin(), m_windows.constEnd(), [event] (const Output &o) { return o.window == event->event; });
|
||||
if (it == m_windows.constEnd()) {
|
||||
auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(),
|
||||
[event] (X11WindowedOutput *output) { return output->window() == event->event; }
|
||||
);
|
||||
if (it == m_outputs.constEnd()) {
|
||||
break;
|
||||
}
|
||||
pointerMotion(QPointF(event->root_x - (*it).xPosition.x() + (*it).internalPosition.x(),
|
||||
event->root_y - (*it).xPosition.y() + (*it).internalPosition.y()) / it->scale,
|
||||
event->time);
|
||||
pointerMotion(QPointF(event->root_x - (*it)->hostPosition().x() + (*it)->internalPosition().x(),
|
||||
event->root_y - (*it)->hostPosition().y() + (*it)->internalPosition().y()) / (*it)->scale(),
|
||||
event->time);
|
||||
}
|
||||
break;
|
||||
case XCB_CLIENT_MESSAGE:
|
||||
|
@ -325,15 +271,17 @@ void X11WindowedBackend::handleEvent(xcb_generic_event_t *e)
|
|||
case XCB_GE_GENERIC: {
|
||||
GeEventMemMover ge(e);
|
||||
auto te = reinterpret_cast<xXIDeviceEvent*>(e);
|
||||
auto it = std::find_if(m_windows.constBegin(), m_windows.constEnd(), [te] (const Output &o) { return o.window == te->event; });
|
||||
if (it == m_windows.constEnd()) {
|
||||
auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(),
|
||||
[te] (X11WindowedOutput *output) { return output->window() == te->event; }
|
||||
);
|
||||
if (it == m_outputs.constEnd()) {
|
||||
break;
|
||||
}
|
||||
QPointF position{
|
||||
fixed1616ToReal(te->root_x) - (*it).xPosition.x() + (*it).internalPosition.x(),
|
||||
fixed1616ToReal(te->root_y) - (*it).xPosition.y() + (*it).internalPosition.y()
|
||||
fixed1616ToReal(te->root_x) - (*it)->hostPosition().x() + (*it)->internalPosition().x(),
|
||||
fixed1616ToReal(te->root_y) - (*it)->hostPosition().y() + (*it)->internalPosition().y()
|
||||
};
|
||||
position /= it->scale;
|
||||
position /= (*it)->scale();
|
||||
|
||||
switch (ge->event_type) {
|
||||
|
||||
|
@ -407,37 +355,39 @@ void X11WindowedBackend::updateWindowTitle()
|
|||
const QString title = QStringLiteral("%1 (%2) - %3").arg(i18n("KDE Wayland Compositor"))
|
||||
.arg(waylandServer()->display()->socketName())
|
||||
.arg(grab);
|
||||
for (auto it = m_windows.constBegin(); it != m_windows.constEnd(); ++it) {
|
||||
(*it).winInfo->setName(title.toUtf8().constData());
|
||||
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
|
||||
(*it)->setWindowTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
void X11WindowedBackend::handleClientMessage(xcb_client_message_event_t *event)
|
||||
{
|
||||
auto it = std::find_if(m_windows.begin(), m_windows.end(), [event] (const Output &o) { return o.window == event->window; });
|
||||
if (it == m_windows.end()) {
|
||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
|
||||
[event] (X11WindowedOutput *output) { return output->window() == event->window; }
|
||||
);
|
||||
if (it == m_outputs.end()) {
|
||||
return;
|
||||
}
|
||||
if (event->type == m_protocols && m_protocols != XCB_ATOM_NONE) {
|
||||
if (event->data.data32[0] == m_deleteWindowProtocol && m_deleteWindowProtocol != XCB_ATOM_NONE) {
|
||||
if (m_windows.count() == 1) {
|
||||
if (m_outputs.count() == 1) {
|
||||
qCDebug(KWIN_X11WINDOWED) << "Backend window is going to be closed, shutting down.";
|
||||
QCoreApplication::quit();
|
||||
} else {
|
||||
// remove the window
|
||||
qCDebug(KWIN_X11WINDOWED) << "Removing one output window.";
|
||||
auto o = *it;
|
||||
it = m_windows.erase(it);
|
||||
xcb_unmap_window(m_connection, o.window);
|
||||
xcb_destroy_window(m_connection, o.window);
|
||||
delete o.winInfo;
|
||||
|
||||
auto removedOutput = *it;
|
||||
it = m_outputs.erase(it);
|
||||
|
||||
// update the sizes
|
||||
int x = o.internalPosition.x();
|
||||
for (; it != m_windows.end(); ++it) {
|
||||
(*it).internalPosition.setX(x);
|
||||
x += (*it).size.width();
|
||||
int x = removedOutput->internalPosition().x();
|
||||
for (; it != m_outputs.end(); ++it) {
|
||||
(*it)->setGeometry(QPoint(x, 0), (*it)->pixelSize());
|
||||
x += (*it)->geometry().width();
|
||||
}
|
||||
|
||||
delete removedOutput;
|
||||
QMetaObject::invokeMethod(screens(), "updateCount");
|
||||
}
|
||||
}
|
||||
|
@ -446,8 +396,10 @@ void X11WindowedBackend::handleClientMessage(xcb_client_message_event_t *event)
|
|||
|
||||
void X11WindowedBackend::handleButtonPress(xcb_button_press_event_t *event)
|
||||
{
|
||||
auto it = std::find_if(m_windows.constBegin(), m_windows.constEnd(), [event] (const Output &o) { return o.window == event->event; });
|
||||
if (it == m_windows.constEnd()) {
|
||||
auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(),
|
||||
[event] (X11WindowedOutput *output) { return output->window() == event->event; }
|
||||
);
|
||||
if (it == m_outputs.constEnd()) {
|
||||
return;
|
||||
}
|
||||
bool const pressed = (event->response_type & ~0x80) == XCB_BUTTON_PRESS;
|
||||
|
@ -481,9 +433,9 @@ void X11WindowedBackend::handleButtonPress(xcb_button_press_event_t *event)
|
|||
return;
|
||||
}
|
||||
|
||||
pointerMotion(QPointF(event->root_x - (*it).xPosition.x() + (*it).internalPosition.x(),
|
||||
event->root_y - (*it).xPosition.y() + (*it).internalPosition.y()) / it->scale,
|
||||
event->time);
|
||||
pointerMotion(QPointF(event->root_x - (*it)->hostPosition().x() + (*it)->internalPosition().x(),
|
||||
event->root_y - (*it)->hostPosition().y() + (*it)->internalPosition().y()) / (*it)->scale(),
|
||||
event->time);
|
||||
if (pressed) {
|
||||
pointerButtonPressed(button, event->time);
|
||||
} else {
|
||||
|
@ -498,22 +450,20 @@ void X11WindowedBackend::handleExpose(xcb_expose_event_t *event)
|
|||
|
||||
void X11WindowedBackend::updateSize(xcb_configure_notify_event_t *event)
|
||||
{
|
||||
auto it = std::find_if(m_windows.begin(), m_windows.end(), [event] (const Output &o) { return o.window == event->window; });
|
||||
if (it == m_windows.end()) {
|
||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
|
||||
[event] (X11WindowedOutput *output) { return output->window() == event->window; }
|
||||
);
|
||||
if (it == m_outputs.end()) {
|
||||
return;
|
||||
}
|
||||
(*it).xPosition = QPoint(event->x, event->y);
|
||||
QSize s = QSize(event->width, event->height);
|
||||
if (s != (*it).size) {
|
||||
(*it).size = s;
|
||||
int x = (*it).internalPosition.x() + (*it).size.width() / (*it).scale;
|
||||
it++;
|
||||
for (; it != m_windows.end(); ++it) {
|
||||
(*it).internalPosition.setX(x);
|
||||
x += (*it).size.width() / (*it).scale;
|
||||
}
|
||||
emit sizeChanged();
|
||||
|
||||
(*it)->setHostPosition(QPoint(event->x, event->y));
|
||||
|
||||
const QSize s = QSize(event->width, event->height);
|
||||
if (s != (*it)->pixelSize()) {
|
||||
(*it)->setGeometry((*it)->internalPosition(), s);
|
||||
}
|
||||
emit sizeChanged();
|
||||
}
|
||||
|
||||
void X11WindowedBackend::createCursor(const QImage &srcImage, const QPoint &hotspot)
|
||||
|
@ -534,8 +484,8 @@ void X11WindowedBackend::createCursor(const QImage &srcImage, const QPoint &hots
|
|||
|
||||
XRenderPicture pic(pix, 32);
|
||||
xcb_render_create_cursor(m_connection, cid, pic, qRound(hotspot.x() * outputScale), qRound(hotspot.y() * outputScale));
|
||||
for (auto it = m_windows.constBegin(); it != m_windows.constEnd(); ++it) {
|
||||
xcb_change_window_attributes(m_connection, (*it).window, XCB_CW_CURSOR, &cid);
|
||||
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
|
||||
xcb_change_window_attributes(m_connection, (*it)->window(), XCB_CW_CURSOR, &cid);
|
||||
}
|
||||
|
||||
xcb_free_pixmap(m_connection, pix);
|
||||
|
@ -558,7 +508,7 @@ xcb_window_t X11WindowedBackend::rootWindow() const
|
|||
|
||||
Screens *X11WindowedBackend::createScreens(QObject *parent)
|
||||
{
|
||||
return new BasicScreens(this, parent);
|
||||
return new OutputScreens(this, parent);
|
||||
}
|
||||
|
||||
OpenGLBackend *X11WindowedBackend::createOpenGLBackend()
|
||||
|
@ -573,35 +523,27 @@ QPainterBackend *X11WindowedBackend::createQPainterBackend()
|
|||
|
||||
void X11WindowedBackend::warpPointer(const QPointF &globalPos)
|
||||
{
|
||||
const xcb_window_t w = m_windows.at(0).window;
|
||||
const xcb_window_t w = m_outputs.at(0)->window();
|
||||
xcb_warp_pointer(m_connection, w, w, 0, 0, 0, 0, globalPos.x(), globalPos.y());
|
||||
xcb_flush(m_connection);
|
||||
}
|
||||
|
||||
xcb_window_t X11WindowedBackend::windowForScreen(int screen) const
|
||||
{
|
||||
if (screen > m_windows.count()) {
|
||||
if (screen > m_outputs.count()) {
|
||||
return XCB_WINDOW_NONE;
|
||||
}
|
||||
return m_windows.at(screen).window;
|
||||
return m_outputs.at(screen)->window();
|
||||
}
|
||||
|
||||
QVector<QRect> X11WindowedBackend::screenGeometries() const
|
||||
Outputs X11WindowedBackend::outputs() const
|
||||
{
|
||||
QVector<QRect> ret;
|
||||
for (auto it = m_windows.constBegin(); it != m_windows.constEnd(); ++it) {
|
||||
ret << QRect((*it).internalPosition, (*it).size / (*it).scale);
|
||||
}
|
||||
return ret;
|
||||
return m_outputs;
|
||||
}
|
||||
|
||||
QVector<qreal> X11WindowedBackend::screenScales() const
|
||||
Outputs X11WindowedBackend::enabledOutputs() const
|
||||
{
|
||||
QVector<qreal> ret;
|
||||
for (auto it = m_windows.constBegin(); it != m_windows.constEnd(); ++it) {
|
||||
ret << (*it).scale;
|
||||
}
|
||||
return ret;
|
||||
return m_outputs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ class NETWinInfo;
|
|||
|
||||
namespace KWin
|
||||
{
|
||||
class X11WindowedOutput;
|
||||
|
||||
class KWIN_EXPORT X11WindowedBackend : public Platform
|
||||
{
|
||||
|
@ -46,12 +47,13 @@ public:
|
|||
X11WindowedBackend(QObject *parent = nullptr);
|
||||
virtual ~X11WindowedBackend();
|
||||
void init() override;
|
||||
QVector<QRect> screenGeometries() const override;
|
||||
QVector<qreal> screenScales() const override;
|
||||
|
||||
xcb_connection_t *connection() const {
|
||||
return m_connection;
|
||||
}
|
||||
xcb_screen_t *screen() const {
|
||||
return m_screen;
|
||||
}
|
||||
int screenNumer() const {
|
||||
return m_screenNumber;
|
||||
}
|
||||
|
@ -63,6 +65,9 @@ public:
|
|||
return m_display;
|
||||
}
|
||||
xcb_window_t rootWindow() const;
|
||||
bool hasXInput() const {
|
||||
return m_hasXInput;
|
||||
}
|
||||
|
||||
Screens *createScreens(QObject *parent = nullptr) override;
|
||||
OpenGLBackend *createOpenGLBackend() override;
|
||||
|
@ -76,11 +81,14 @@ public:
|
|||
return QVector<CompositingType>{OpenGLCompositing, QPainterCompositing};
|
||||
}
|
||||
|
||||
Outputs outputs() const override;
|
||||
Outputs enabledOutputs() const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void sizeChanged();
|
||||
|
||||
private:
|
||||
void createWindow();
|
||||
void createOutputs();
|
||||
void startEventReading();
|
||||
void grabKeyboard(xcb_timestamp_t time);
|
||||
void updateWindowTitle();
|
||||
|
@ -90,22 +98,13 @@ private:
|
|||
void handleExpose(xcb_expose_event_t *event);
|
||||
void updateSize(xcb_configure_notify_event_t *event);
|
||||
void createCursor(const QImage &img, const QPoint &hotspot);
|
||||
void initXInputForWindow(xcb_window_t window);
|
||||
void initXInput();
|
||||
|
||||
xcb_connection_t *m_connection = nullptr;
|
||||
xcb_screen_t *m_screen = nullptr;
|
||||
xcb_key_symbols_t *m_keySymbols = nullptr;
|
||||
int m_screenNumber = 0;
|
||||
struct Output {
|
||||
xcb_window_t window = XCB_WINDOW_NONE;
|
||||
QSize size;
|
||||
qreal scale = 1;
|
||||
QPoint xPosition;
|
||||
QPoint internalPosition;
|
||||
NETWinInfo *winInfo = nullptr;
|
||||
};
|
||||
QVector<Output> m_windows;
|
||||
|
||||
xcb_atom_t m_protocols = XCB_ATOM_NONE;
|
||||
xcb_atom_t m_deleteWindowProtocol = XCB_ATOM_NONE;
|
||||
xcb_cursor_t m_cursor = XCB_CURSOR_NONE;
|
||||
|
@ -116,6 +115,8 @@ private:
|
|||
int m_xiOpcode = 0;
|
||||
int m_majorVersion = 0;
|
||||
int m_minorVersion = 0;
|
||||
|
||||
QVector<X11WindowedOutput*> m_outputs;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
156
plugins/platforms/x11/windowed/x11windowed_output.cpp
Normal file
156
plugins/platforms/x11/windowed/x11windowed_output.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright 2019 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "x11windowed_output.h"
|
||||
|
||||
#include "x11windowed_backend.h"
|
||||
|
||||
#include <NETWM>
|
||||
|
||||
#if HAVE_X11_XINPUT
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
X11WindowedOutput::X11WindowedOutput(X11WindowedBackend *backend)
|
||||
: AbstractOutput(backend)
|
||||
, m_backend(backend)
|
||||
{
|
||||
m_window = xcb_generate_id(m_backend->connection());
|
||||
}
|
||||
|
||||
X11WindowedOutput::~X11WindowedOutput()
|
||||
{
|
||||
xcb_unmap_window(m_backend->connection(), m_window);
|
||||
xcb_destroy_window(m_backend->connection(), m_window);
|
||||
delete m_winInfo;
|
||||
xcb_flush(m_backend->connection());
|
||||
}
|
||||
|
||||
void X11WindowedOutput::init()
|
||||
{
|
||||
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
||||
const uint32_t values[] = {
|
||||
m_backend->screen()->black_pixel,
|
||||
XCB_EVENT_MASK_KEY_PRESS |
|
||||
XCB_EVENT_MASK_KEY_RELEASE |
|
||||
XCB_EVENT_MASK_BUTTON_PRESS |
|
||||
XCB_EVENT_MASK_BUTTON_RELEASE |
|
||||
XCB_EVENT_MASK_POINTER_MOTION |
|
||||
XCB_EVENT_MASK_ENTER_WINDOW |
|
||||
XCB_EVENT_MASK_LEAVE_WINDOW |
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_EXPOSURE
|
||||
};
|
||||
xcb_create_window(m_backend->connection(),
|
||||
XCB_COPY_FROM_PARENT,
|
||||
m_window,
|
||||
m_backend->screen()->root,
|
||||
0, 0,
|
||||
pixelSize().width(), pixelSize().height(),
|
||||
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT,
|
||||
mask, values);
|
||||
|
||||
// select xinput 2 events
|
||||
initXInputForWindow();
|
||||
|
||||
m_winInfo = new NETWinInfo(m_backend->connection(),
|
||||
m_window,
|
||||
m_backend->screen()->root,
|
||||
NET::WMWindowType, NET::Properties2());
|
||||
|
||||
m_winInfo->setWindowType(NET::Normal);
|
||||
m_winInfo->setPid(QCoreApplication::applicationPid());
|
||||
QIcon windowIcon = QIcon::fromTheme(QStringLiteral("kwin"));
|
||||
auto addIcon = [&windowIcon, this] (const QSize &size) {
|
||||
if (windowIcon.actualSize(size) != size) {
|
||||
return;
|
||||
}
|
||||
NETIcon icon;
|
||||
icon.data = windowIcon.pixmap(size).toImage().bits();
|
||||
icon.size.width = size.width();
|
||||
icon.size.height = size.height();
|
||||
m_winInfo->setIcon(icon, false);
|
||||
};
|
||||
addIcon(QSize(16, 16));
|
||||
addIcon(QSize(32, 32));
|
||||
addIcon(QSize(48, 48));
|
||||
|
||||
xcb_map_window(m_backend->connection(), m_window);
|
||||
}
|
||||
|
||||
void X11WindowedOutput::initXInputForWindow()
|
||||
{
|
||||
if (!m_backend->hasXInput()) {
|
||||
return;
|
||||
}
|
||||
#if HAVE_X11_XINPUT
|
||||
XIEventMask evmasks[1];
|
||||
unsigned char mask1[XIMaskLen(XI_LASTEVENT)];
|
||||
|
||||
memset(mask1, 0, sizeof(mask1));
|
||||
XISetMask(mask1, XI_TouchBegin);
|
||||
XISetMask(mask1, XI_TouchUpdate);
|
||||
XISetMask(mask1, XI_TouchOwnership);
|
||||
XISetMask(mask1, XI_TouchEnd);
|
||||
evmasks[0].deviceid = XIAllMasterDevices;
|
||||
evmasks[0].mask_len = sizeof(mask1);
|
||||
evmasks[0].mask = mask1;
|
||||
XISelectEvents(m_backend->display(), m_window, evmasks, 1);
|
||||
#else
|
||||
Q_UNUSED(window)
|
||||
#endif
|
||||
}
|
||||
|
||||
QSize X11WindowedOutput::pixelSize() const
|
||||
{
|
||||
return m_pixelSize;
|
||||
}
|
||||
|
||||
void X11WindowedOutput::setGeometry(const QPoint &logicalPosition, const QSize &pixelSize)
|
||||
{
|
||||
m_pixelSize = pixelSize;
|
||||
|
||||
// Physicial size must be adjusted, such that QPA calculates correct sizes of
|
||||
// internal elements.
|
||||
setRawPhysicalSize(pixelSize / 96.0 * 25.4 / scale());
|
||||
|
||||
setGlobalPos(logicalPosition);
|
||||
}
|
||||
|
||||
void X11WindowedOutput::setWindowTitle(const QString &title)
|
||||
{
|
||||
m_winInfo->setName(title.toUtf8().constData());
|
||||
}
|
||||
|
||||
QPoint X11WindowedOutput::internalPosition() const
|
||||
{
|
||||
return geometry().topLeft();
|
||||
}
|
||||
|
||||
void X11WindowedOutput::setHostPosition(const QPoint &pos)
|
||||
{
|
||||
m_hostPosition = pos;
|
||||
}
|
||||
|
||||
}
|
85
plugins/platforms/x11/windowed/x11windowed_output.h
Normal file
85
plugins/platforms/x11/windowed/x11windowed_output.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright 2019 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#ifndef KWIN_X11WINDOWED_OUTPUT_H
|
||||
#define KWIN_X11WINDOWED_OUTPUT_H
|
||||
|
||||
#include "abstract_output.h"
|
||||
#include <kwin_export.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
class NETWinInfo;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class X11WindowedBackend;
|
||||
|
||||
/**
|
||||
* Wayland outputs in a nested X11 setup
|
||||
**/
|
||||
class KWIN_EXPORT X11WindowedOutput : public AbstractOutput
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit X11WindowedOutput(X11WindowedBackend *backend);
|
||||
~X11WindowedOutput() override;
|
||||
|
||||
void init();
|
||||
|
||||
xcb_window_t window() const {
|
||||
return m_window;
|
||||
}
|
||||
|
||||
QPoint internalPosition() const;
|
||||
QPoint hostPosition() const {
|
||||
return m_hostPosition;
|
||||
}
|
||||
void setHostPosition(const QPoint &pos);
|
||||
|
||||
void setWindowTitle(const QString &title);
|
||||
|
||||
QSize pixelSize() const override;
|
||||
|
||||
/**
|
||||
* @brief defines the geometry of the output
|
||||
* @param logicalPosition top left position of the output in compositor space
|
||||
* @param pixelSize output size as seen from the outside
|
||||
*/
|
||||
void setGeometry(const QPoint &logicalPosition, const QSize &pixelSize);
|
||||
|
||||
private:
|
||||
void initXInputForWindow();
|
||||
|
||||
xcb_window_t m_window = XCB_WINDOW_NONE;
|
||||
NETWinInfo *m_winInfo = nullptr;
|
||||
|
||||
QPoint m_hostPosition;
|
||||
QSize m_pixelSize;
|
||||
|
||||
X11WindowedBackend *m_backend;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue