18
18
along with this program. If not, see <http://www.gnu.org/licenses/>.
19
19
*********************************************************************/
20
20
#include "wayland_server.h"
22
#include "abstract_backend.h"
23
#include "composite.h"
21
24
#include "screens.h"
25
#include "shell_client.h"
23
26
#include "workspace.h"
26
29
#include <KWayland/Client/connection_thread.h>
27
30
#include <KWayland/Client/registry.h>
31
#include <KWayland/Client/surface.h>
29
33
#include <KWayland/Server/compositor_interface.h>
34
#include <KWayland/Server/datadevicemanager_interface.h>
30
35
#include <KWayland/Server/display.h>
36
#include <KWayland/Server/idle_interface.h>
31
37
#include <KWayland/Server/output_interface.h>
38
#include <KWayland/Server/plasmashell_interface.h>
39
#include <KWayland/Server/plasmawindowmanagement_interface.h>
40
#include <KWayland/Server/qtsurfaceextension_interface.h>
32
41
#include <KWayland/Server/seat_interface.h>
42
#include <KWayland/Server/shadow_interface.h>
33
43
#include <KWayland/Server/shell_interface.h>
36
49
#include <sys/types.h>
37
50
#include <sys/socket.h>
78
95
m_shell = m_display->createShell(m_display);
97
connect(m_shell, &ShellInterface::surfaceCreated, this,
98
[this] (ShellSurfaceInterface *surface) {
99
if (!Workspace::self()) {
100
// it's possible that a Surface gets created before Workspace is created
103
if (surface->client() == m_xwaylandConnection) {
104
// skip Xwayland clients, those are created using standard X11 way
107
if (surface->client() == m_qtConnection) {
108
// one of Qt's windows
109
if (m_dummyWindowSurface && (m_dummyWindowSurface->id() == surface->surface()->id())) {
110
fakeDummyQtWindowInput();
113
// HACK: in order to get Qt to not block for frame rendered, we immediatelly emit the
114
// frameRendered once we get a new damage event.
115
auto s = surface->surface();
116
connect(s, &SurfaceInterface::damaged, this, [this, s] {
118
m_qtConnection->flush();
121
auto client = new ShellClient(surface);
122
if (auto c = Compositor::self()) {
123
connect(client, &Toplevel::needsRepaint, c, &Compositor::scheduleRepaint);
125
if (client->isInternal()) {
126
m_internalClients << client;
130
if (client->readyForPainting()) {
131
emit shellClientAdded(client);
133
connect(client, &ShellClient::windowShown, this,
135
emit shellClientAdded(client);
80
141
m_display->createShm();
81
142
m_seat = m_display->createSeat(m_display);
144
m_display->createDataDeviceManager(m_display)->create();
145
m_display->createIdle(m_display)->create();
146
m_plasmaShell = m_display->createPlasmaShell(m_display);
147
m_plasmaShell->create();
148
connect(m_plasmaShell, &PlasmaShellInterface::surfaceCreated,
149
[this] (PlasmaShellSurfaceInterface *surface) {
150
if (ShellClient *client = findClient(surface->surface())) {
151
client->installPlasmaShellSurface(surface);
155
m_qtExtendedSurface = m_display->createQtSurfaceExtension(m_display);
156
m_qtExtendedSurface->create();
157
connect(m_qtExtendedSurface, &QtSurfaceExtensionInterface::surfaceCreated,
158
[this] (QtExtendedSurfaceInterface *surface) {
159
if (ShellClient *client = findClient(surface->surface())) {
160
client->installQtExtendedSurface(surface);
164
m_windowManagement = m_display->createPlasmaWindowManagement(m_display);
165
m_windowManagement->create();
166
m_windowManagement->setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState::Disabled);
167
connect(m_windowManagement, &PlasmaWindowManagementInterface::requestChangeShowingDesktop, this,
168
[] (PlasmaWindowManagementInterface::ShowingDesktopState state) {
174
case PlasmaWindowManagementInterface::ShowingDesktopState::Disabled:
177
case PlasmaWindowManagementInterface::ShowingDesktopState::Enabled:
184
if (set == workspace()->showingDesktop()) {
187
workspace()->setShowingDesktop(set);
190
auto shadowManager = m_display->createShadowManager(m_display);
191
shadowManager->create();
194
void WaylandServer::initWorkspace()
196
if (m_windowManagement) {
197
connect(workspace(), &Workspace::showingDesktopChanged, this,
199
using namespace KWayland::Server;
200
m_windowManagement->setShowingDesktopState(set ?
201
PlasmaWindowManagementInterface::ShowingDesktopState::Enabled :
202
PlasmaWindowManagementInterface::ShowingDesktopState::Disabled
85
209
void WaylandServer::initOutputs()
211
if (m_backend && m_backend->handlesOutputs()) {
87
214
Screens *s = screens();
89
216
for (int i = 0; i < s->count(); ++i) {
154
297
m_backend = nullptr;
300
void WaylandServer::removeClient(ShellClient *c)
302
m_clients.removeAll(c);
303
m_internalClients.removeAll(c);
304
emit shellClientRemoved(c);
307
void WaylandServer::createDummyQtWindow()
312
m_dummyWindow.reset(new QWindow());
313
m_dummyWindow->setSurfaceType(QSurface::RasterSurface);
314
m_dummyWindow->show();
315
m_dummyWindowSurface = KWayland::Client::Surface::fromWindow(m_dummyWindow.data());
318
void WaylandServer::fakeDummyQtWindowInput()
320
// we need to fake Qt into believing it has got any seat events
321
// this is done only when receiving either a key press or button.
322
// we simulate by sending a button press and release
323
auto surface = KWayland::Server::SurfaceInterface::get(m_dummyWindowSurface->id(), m_qtConnection);
327
const auto oldSeatSurface = m_seat->focusedPointerSurface();
328
const auto oldPos = m_seat->focusedPointerSurfacePosition();
329
m_seat->setFocusedPointerSurface(surface, QPoint(0, 0));
330
m_seat->setPointerPos(QPointF(0, 0));
331
m_seat->pointerButtonPressed(Qt::LeftButton);
332
m_seat->pointerButtonReleased(Qt::LeftButton);
333
m_qtConnection->flush();
334
m_dummyWindow->hide();
335
m_seat->setFocusedPointerSurface(oldSeatSurface, oldPos);
338
void WaylandServer::dispatch()
343
if (!m_qtClientConnection) {
344
if (m_qtConnection && QGuiApplication::instance()) {
345
m_qtClientConnection = KWayland::Client::ConnectionThread::fromApplication(this);
348
if (m_qtClientConnection) {
349
m_qtClientConnection->flush();
351
m_display->dispatchEvents(0);
354
static ShellClient *findClientInList(const QList<ShellClient*> &clients, quint32 id)
356
auto it = std::find_if(clients.begin(), clients.end(),
357
[id] (ShellClient *c) {
358
return c->windowId() == id;
361
if (it == clients.end()) {
367
static ShellClient *findClientInList(const QList<ShellClient*> &clients, KWayland::Server::SurfaceInterface *surface)
369
auto it = std::find_if(clients.begin(), clients.end(),
370
[surface] (ShellClient *c) {
371
return c->surface() == surface;
374
if (it == clients.end()) {
380
ShellClient *WaylandServer::findClient(quint32 id) const
385
if (ShellClient *c = findClientInList(m_clients, id)) {
388
if (ShellClient *c = findClientInList(m_internalClients, id)) {
394
ShellClient *WaylandServer::findClient(SurfaceInterface *surface) const
399
if (ShellClient *c = findClientInList(m_clients, surface)) {
402
if (ShellClient *c = findClientInList(m_internalClients, surface)) {
408
quint32 WaylandServer::createWindowId(SurfaceInterface *surface)
410
auto it = m_clientIds.constFind(surface->client());
411
quint16 clientId = 0;
412
if (it != m_clientIds.constEnd()) {
413
clientId = it.value();
415
clientId = createClientId(surface->client());
417
Q_ASSERT(clientId != 0);
418
quint32 id = clientId;
419
// TODO: this does not prevent that two surfaces of same client get same id
420
id = (id << 16) | (surface->id() & 0xFFFF);
421
if (findClient(id)) {
422
qCWarning(KWIN_CORE) << "Invalid client windowId generated:" << id;
428
quint16 WaylandServer::createClientId(ClientConnection *c)
430
auto ids = m_clientIds.values().toSet();
432
if (!ids.isEmpty()) {
433
for (quint16 i = ids.count() + 1; i >= 1 ; i--) {
434
if (!ids.contains(i)) {
440
Q_ASSERT(!ids.contains(id));
441
m_clientIds.insert(c, id);
442
connect(c, &ClientConnection::disconnected, this,
443
[this] (ClientConnection *c) {
444
m_clientIds.remove(c);