~ubuntu-branches/ubuntu/wily/kwin/wily-proposed

« back to all changes in this revision

Viewing changes to wayland_server.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-08-10 23:16:37 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20150810231637-5zb2tstjkez93hml
Tags: 4:5.3.95-0ubuntu1
new upstream beta release

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
19
*********************************************************************/
20
20
#include "wayland_server.h"
 
21
#include "client.h"
 
22
#include "abstract_backend.h"
 
23
#include "composite.h"
21
24
#include "screens.h"
22
 
#include "toplevel.h"
 
25
#include "shell_client.h"
23
26
#include "workspace.h"
24
27
 
25
28
// Client
26
29
#include <KWayland/Client/connection_thread.h>
27
30
#include <KWayland/Client/registry.h>
 
31
#include <KWayland/Client/surface.h>
28
32
// Server
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>
34
44
 
 
45
// Qt
 
46
#include <QWindow>
 
47
 
35
48
// system
36
49
#include <sys/types.h>
37
50
#include <sys/socket.h>
67
80
                // it's possible that a Surface gets created before Workspace is created
68
81
                return;
69
82
            }
 
83
            if (surface->client() != xWaylandConnection()) {
 
84
                // setting surface is only relevat for Xwayland clients
 
85
                return;
 
86
            }
70
87
            auto check = [surface] (const Toplevel *t) {
71
88
                return t->surfaceId() == surface->id();
72
89
            };
77
94
    );
78
95
    m_shell = m_display->createShell(m_display);
79
96
    m_shell->create();
 
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
 
101
                return;
 
102
            }
 
103
            if (surface->client() == m_xwaylandConnection) {
 
104
                // skip Xwayland clients, those are created using standard X11 way
 
105
                return;
 
106
            }
 
107
            if (surface->client() == m_qtConnection) {
 
108
                // one of Qt's windows
 
109
                if (m_dummyWindowSurface && (m_dummyWindowSurface->id() == surface->surface()->id())) {
 
110
                    fakeDummyQtWindowInput();
 
111
                    return;
 
112
                }
 
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] {
 
117
                    s->frameRendered(0);
 
118
                    m_qtConnection->flush();
 
119
                });
 
120
            }
 
121
            auto client = new ShellClient(surface);
 
122
            if (auto c = Compositor::self()) {
 
123
                connect(client, &Toplevel::needsRepaint, c, &Compositor::scheduleRepaint);
 
124
            }
 
125
            if (client->isInternal()) {
 
126
                m_internalClients << client;
 
127
            } else {
 
128
                m_clients << client;
 
129
            }
 
130
            if (client->readyForPainting()) {
 
131
                emit shellClientAdded(client);
 
132
            } else {
 
133
                connect(client, &ShellClient::windowShown, this,
 
134
                    [this, client] {
 
135
                        emit shellClientAdded(client);
 
136
                    }
 
137
                );
 
138
            }
 
139
        }
 
140
    );
80
141
    m_display->createShm();
81
142
    m_seat = m_display->createSeat(m_display);
82
143
    m_seat->create();
 
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);
 
152
            }
 
153
        }
 
154
    );
 
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);
 
161
            }
 
162
        }
 
163
    );
 
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) {
 
169
            if (!workspace()) {
 
170
                return;
 
171
            }
 
172
            bool set = false;
 
173
            switch (state) {
 
174
            case PlasmaWindowManagementInterface::ShowingDesktopState::Disabled:
 
175
                set = false;
 
176
                break;
 
177
            case PlasmaWindowManagementInterface::ShowingDesktopState::Enabled:
 
178
                set = true;
 
179
                break;
 
180
            default:
 
181
                Q_UNREACHABLE();
 
182
                break;
 
183
            }
 
184
            if (set == workspace()->showingDesktop()) {
 
185
                return;
 
186
            }
 
187
            workspace()->setShowingDesktop(set);
 
188
        }
 
189
    );
 
190
    auto shadowManager = m_display->createShadowManager(m_display);
 
191
    shadowManager->create();
 
192
}
 
193
 
 
194
void WaylandServer::initWorkspace()
 
195
{
 
196
    if (m_windowManagement) {
 
197
        connect(workspace(), &Workspace::showingDesktopChanged, this,
 
198
            [this] (bool set) {
 
199
                using namespace KWayland::Server;
 
200
                m_windowManagement->setShowingDesktopState(set ?
 
201
                    PlasmaWindowManagementInterface::ShowingDesktopState::Enabled :
 
202
                    PlasmaWindowManagementInterface::ShowingDesktopState::Disabled
 
203
                );
 
204
            }
 
205
        );
 
206
    }
83
207
}
84
208
 
85
209
void WaylandServer::initOutputs()
86
210
{
 
211
    if (m_backend && m_backend->handlesOutputs()) {
 
212
        return;
 
213
    }
87
214
    Screens *s = screens();
88
215
    Q_ASSERT(s);
89
216
    for (int i = 0; i < s->count(); ++i) {
102
229
        return -1;
103
230
    }
104
231
    m_xwaylandConnection = m_display->createClient(sx[0]);
 
232
    connect(m_xwaylandConnection, &KWayland::Server::ClientConnection::disconnected, this,
 
233
        [] {
 
234
            qFatal("Xwayland Connection died");
 
235
        }
 
236
    );
 
237
    return sx[1];
 
238
}
 
239
 
 
240
int WaylandServer::createInputMethodConnection()
 
241
{
 
242
    int sx[2];
 
243
    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) {
 
244
        qCWarning(KWIN_CORE) << "Could not create socket";
 
245
        return -1;
 
246
    }
 
247
    m_inputMethodServerConnection = m_display->createClient(sx[0]);
105
248
    return sx[1];
106
249
}
107
250
 
154
297
    m_backend = nullptr;
155
298
}
156
299
 
 
300
void WaylandServer::removeClient(ShellClient *c)
 
301
{
 
302
    m_clients.removeAll(c);
 
303
    m_internalClients.removeAll(c);
 
304
    emit shellClientRemoved(c);
 
305
}
 
306
 
 
307
void WaylandServer::createDummyQtWindow()
 
308
{
 
309
    if (m_dummyWindow) {
 
310
        return;
 
311
    }
 
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());
 
316
}
 
317
 
 
318
void WaylandServer::fakeDummyQtWindowInput()
 
319
{
 
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);
 
324
    if (!surface) {
 
325
        return;
 
326
    }
 
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);
 
336
}
 
337
 
 
338
void WaylandServer::dispatch()
 
339
{
 
340
    if (!m_display) {
 
341
        return;
 
342
    }
 
343
    if (!m_qtClientConnection) {
 
344
        if (m_qtConnection && QGuiApplication::instance()) {
 
345
            m_qtClientConnection = KWayland::Client::ConnectionThread::fromApplication(this);
 
346
        }
 
347
    }
 
348
    if (m_qtClientConnection) {
 
349
        m_qtClientConnection->flush();
 
350
    }
 
351
    m_display->dispatchEvents(0);
 
352
}
 
353
 
 
354
static ShellClient *findClientInList(const QList<ShellClient*> &clients, quint32 id)
 
355
{
 
356
    auto it = std::find_if(clients.begin(), clients.end(),
 
357
        [id] (ShellClient *c) {
 
358
            return c->windowId() == id;
 
359
        }
 
360
    );
 
361
    if (it == clients.end()) {
 
362
        return nullptr;
 
363
    }
 
364
    return *it;
 
365
}
 
366
 
 
367
static ShellClient *findClientInList(const QList<ShellClient*> &clients, KWayland::Server::SurfaceInterface *surface)
 
368
{
 
369
    auto it = std::find_if(clients.begin(), clients.end(),
 
370
        [surface] (ShellClient *c) {
 
371
            return c->surface() == surface;
 
372
        }
 
373
    );
 
374
    if (it == clients.end()) {
 
375
        return nullptr;
 
376
    }
 
377
    return *it;
 
378
}
 
379
 
 
380
ShellClient *WaylandServer::findClient(quint32 id) const
 
381
{
 
382
    if (id == 0) {
 
383
        return nullptr;
 
384
    }
 
385
    if (ShellClient *c = findClientInList(m_clients, id)) {
 
386
        return c;
 
387
    }
 
388
    if (ShellClient *c = findClientInList(m_internalClients, id)) {
 
389
        return c;
 
390
    }
 
391
    return nullptr;
 
392
}
 
393
 
 
394
ShellClient *WaylandServer::findClient(SurfaceInterface *surface) const
 
395
{
 
396
    if (!surface) {
 
397
        return nullptr;
 
398
    }
 
399
    if (ShellClient *c = findClientInList(m_clients, surface)) {
 
400
        return c;
 
401
    }
 
402
    if (ShellClient *c = findClientInList(m_internalClients, surface)) {
 
403
        return c;
 
404
    }
 
405
    return nullptr;
 
406
}
 
407
 
 
408
quint32 WaylandServer::createWindowId(SurfaceInterface *surface)
 
409
{
 
410
    auto it = m_clientIds.constFind(surface->client());
 
411
    quint16 clientId = 0;
 
412
    if (it != m_clientIds.constEnd()) {
 
413
        clientId = it.value();
 
414
    } else {
 
415
        clientId = createClientId(surface->client());
 
416
    }
 
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;
 
423
        return 0;
 
424
    }
 
425
    return id;
 
426
}
 
427
 
 
428
quint16 WaylandServer::createClientId(ClientConnection *c)
 
429
{
 
430
    auto ids = m_clientIds.values().toSet();
 
431
    quint16 id = 1;
 
432
    if (!ids.isEmpty()) {
 
433
        for (quint16 i = ids.count() + 1; i >= 1 ; i--) {
 
434
            if (!ids.contains(i)) {
 
435
                id = i;
 
436
                break;
 
437
            }
 
438
        }
 
439
    }
 
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);
 
445
        }
 
446
    );
 
447
    return id;
 
448
}
 
449
 
157
450
}