[wayland] Improve creation of KWayland::Server::PlasmaWindowInterface

The creation of PlasmaWindowInterface is moved from WaylandServer into
AbstractClient. This allows the sub classes to better control when to
create/destroy the Client.

For creation it's bound to becoming visible - that is Windows which are
only created but never shown are not announced at all.

For Client it's destroyed with the normal tear-down of a Client, for
ShellClient it's destroyed on unmapped (which also means a new one
will be created again in case of another mapping of the surface).

As a side effect, this works around the problem that ShellClients do not
yet get destroyed for QtWayland's menus (needs further investigation).
This commit is contained in:
Martin Gräßlin 2015-07-09 09:10:33 +02:00
parent f6458fa1e8
commit 72635101f0
9 changed files with 163 additions and 110 deletions

View file

@ -25,6 +25,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#include "workspace.h"
#if HAVE_WAYLAND
#include "wayland_server.h"
#include <KWayland/Server/plasmawindowmanagement_interface.h>
#endif
namespace KWin
{
@ -509,4 +514,122 @@ bool AbstractClient::hasStrut() const
return false;
}
void AbstractClient::setupWindowManagementInterface()
{
#if HAVE_WAYLAND
if (m_windowManagementInterface) {
// already setup
return;
}
if (!waylandServer() || !surface()) {
return;
}
if (!waylandServer()->windowManagement()) {
return;
}
using namespace KWayland::Server;
auto w = waylandServer()->windowManagement()->createWindow(this);
w->setTitle(caption());
w->setVirtualDesktop(isOnAllDesktops() ? 0 : desktop() - 1);
w->setActive(isActive());
w->setFullscreen(isFullScreen());
w->setKeepAbove(keepAbove());
w->setKeepBelow(keepBelow());
w->setMaximized(maximizeMode() == KWin::MaximizeFull);
w->setMinimized(isMinimized());
w->setOnAllDesktops(isOnAllDesktops());
w->setDemandsAttention(isDemandingAttention());
w->setCloseable(isCloseable());
w->setMaximizeable(isMaximizable());
w->setMinimizeable(isMinimizable());
w->setFullscreenable(isFullScreenable());
w->setThemedIconName(icon().name().isEmpty() ? QStringLiteral("xorg") : icon().name());
connect(this, &AbstractClient::captionChanged, w, [w, this] { w->setTitle(caption()); });
connect(this, &AbstractClient::desktopChanged, w,
[w, this] {
if (isOnAllDesktops()) {
w->setOnAllDesktops(true);
return;
}
w->setVirtualDesktop(desktop() - 1);
w->setOnAllDesktops(false);
}
);
connect(this, &AbstractClient::activeChanged, w, [w, this] { w->setActive(isActive()); });
connect(this, &AbstractClient::fullScreenChanged, w, [w, this] { w->setFullscreen(isFullScreen()); });
connect(this, &AbstractClient::keepAboveChanged, w, &PlasmaWindowInterface::setKeepAbove);
connect(this, &AbstractClient::keepBelowChanged, w, &PlasmaWindowInterface::setKeepBelow);
connect(this, &AbstractClient::minimizedChanged, w, [w, this] { w->setMinimized(isMinimized()); });
connect(this, static_cast<void (AbstractClient::*)(AbstractClient*,MaximizeMode)>(&AbstractClient::clientMaximizedStateChanged), w,
[w] (KWin::AbstractClient *c, MaximizeMode mode) {
Q_UNUSED(c);
w->setMaximized(mode == KWin::MaximizeFull);
}
);
connect(this, &AbstractClient::demandsAttentionChanged, w, [w, this] { w->setDemandsAttention(isDemandingAttention()); });
connect(this, &AbstractClient::iconChanged, w,
[w, this] {
const QIcon i = icon();
w->setThemedIconName(i.name().isEmpty() ? QStringLiteral("xorg") : i.name());
}
);
connect(w, &PlasmaWindowInterface::closeRequested, this, [this] { closeWindow(); });
connect(w, &PlasmaWindowInterface::virtualDesktopRequested, this,
[this] (quint32 desktop) {
workspace()->sendClientToDesktop(this, desktop + 1, true);
}
);
connect(w, &PlasmaWindowInterface::fullscreenRequested, this,
[this] (bool set) {
setFullScreen(set, false);
}
);
connect(w, &PlasmaWindowInterface::minimizedRequested, this,
[this] (bool set) {
if (set) {
minimize();
} else {
unminimize();
}
}
);
connect(w, &PlasmaWindowInterface::maximizedRequested, this,
[this] (bool set) {
maximize(set ? MaximizeFull : MaximizeRestore);
}
);
connect(w, &PlasmaWindowInterface::keepAboveRequested, this,
[this] (bool set) {
setKeepAbove(set);
}
);
connect(w, &PlasmaWindowInterface::keepBelowRequested, this,
[this] (bool set) {
setKeepBelow(set);
}
);
connect(w, &PlasmaWindowInterface::demandsAttentionRequested, this,
[this] (bool set) {
demandAttention(set);
}
);
connect(w, &PlasmaWindowInterface::activeRequested, this,
[this] (bool set) {
if (set) {
workspace()->activateClient(this, true);
}
}
);
m_windowManagementInterface = w;
#endif
}
void AbstractClient::destroyWindowManagementInterface()
{
#if HAVE_WAYLAND
delete m_windowManagementInterface;
m_windowManagementInterface = nullptr;
#endif
}
}

View file

@ -26,6 +26,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <memory>
namespace KWayland
{
namespace Server
{
class PlasmaWindowInterface;
}
}
namespace KWin
{
@ -430,6 +438,9 @@ protected:
virtual void doSetSkipTaskbar();
virtual void doSetSkipPager();
void setupWindowManagementInterface();
void destroyWindowManagementInterface();
void updateColorScheme(QString path);
private:
@ -456,6 +467,8 @@ private:
std::shared_ptr<Decoration::DecorationPalette> m_palette;
static QHash<QString, std::weak_ptr<Decoration::DecorationPalette>> s_palettes;
static std::shared_ptr<Decoration::DecorationPalette> s_defaultPalette;
KWayland::Server::PlasmaWindowInterface *m_windowManagementInterface = nullptr;
};
inline void AbstractClient::move(const QPoint& p, ForceGeometry_t force)

View file

@ -223,6 +223,7 @@ void Client::releaseWindow(bool on_shutdown)
{
assert(!deleting);
deleting = true;
destroyWindowManagementInterface();
Deleted* del = NULL;
if (!on_shutdown) {
del = Deleted::create(this);
@ -293,6 +294,7 @@ void Client::destroyClient()
{
assert(!deleting);
deleting = true;
destroyWindowManagementInterface();
Deleted* del = Deleted::create(this);
if (moveResizeMode)
emit clientFinishUserMovedResized(this);
@ -1824,6 +1826,7 @@ void Client::sendSyncRequest()
if (!ready_for_painting) {
// failed on initial pre-show request
setReadyForPainting();
setupWindowManagementInterface();
return;
}
// failed during resize
@ -2231,8 +2234,10 @@ void Client::setDecoratedClient(QPointer< Decoration::DecoratedClientImpl > clie
void Client::addDamage(const QRegion &damage)
{
if (!ready_for_painting) { // avoid "setReadyForPainting()" function calling overhead
if (syncRequest.counter == XCB_NONE) // cannot detect complete redraw, consider done now
if (syncRequest.counter == XCB_NONE) { // cannot detect complete redraw, consider done now
setReadyForPainting();
setupWindowManagementInterface();
}
}
Toplevel::addDamage(damage);
}

View file

@ -1024,8 +1024,10 @@ void Client::damageNotifyEvent()
}
if (!ready_for_painting) { // avoid "setReadyForPainting()" function calling overhead
if (syncRequest.counter == XCB_NONE) // cannot detect complete redraw, consider done now
if (syncRequest.counter == XCB_NONE) { // cannot detect complete redraw, consider done now
setReadyForPainting();
setupWindowManagementInterface();
}
}
Toplevel::damageNotifyEvent();

View file

@ -1547,6 +1547,7 @@ void Client::syncEvent(xcb_sync_alarm_notify_event_t* e)
{
if (e->alarm == syncRequest.alarm && e->counter_value.hi == syncRequest.value.hi && e->counter_value.lo == syncRequest.value.lo) {
setReadyForPainting();
setupWindowManagementInterface();
syncRequest.isPending = false;
if (syncRequest.failsafeTimeout)
syncRequest.failsafeTimeout->stop();

View file

@ -52,6 +52,7 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface)
setupCompositing();
if (surface->surface()->buffer()) {
setReadyForPainting();
setupWindowManagementInterface();
m_unmapped = false;
m_clientSize = surface->surface()->buffer()->size();
} else {
@ -211,12 +212,21 @@ void ShellClient::addDamage(const QRegion &damage)
}
setGeometry(QRect(position, m_clientSize));
}
m_unmapped = false;
markAsUnmapped();
setDepth(m_shellSurface->surface()->buffer()->hasAlphaChannel() ? 32 : 24);
setReadyForPainting();
Toplevel::addDamage(damage);
}
void ShellClient::markAsUnmapped()
{
if (!m_unmapped) {
return;
}
m_unmapped = false;
setReadyForPainting();
setupWindowManagementInterface();
}
void ShellClient::setGeometry(const QRect &rect)
{
if (geom == rect) {
@ -591,6 +601,7 @@ void ShellClient::unmap()
{
m_unmapped = true;
ready_for_painting = false;
destroyWindowManagementInterface();
addWorkspaceRepaint(visibleRect());
workspace()->clientHidden(this);
emit windowHidden(this);

View file

@ -127,6 +127,7 @@ private:
void findInternalWindow();
void updateInternalWindowGeometry();
void updateIcon();
void markAsUnmapped();
static void deleteClient(ShellClient *c);
KWayland::Server::ShellSurfaceInterface *m_shellSurface;

View file

@ -87,9 +87,6 @@ void WaylandServer::init(const QByteArray &socketName)
};
if (Toplevel *t = ws->findToplevel(check)) {
t->setSurface(surface);
if (Client *c = dynamic_cast<Client*>(t)) {
announceClientToWindowManagement(c);
}
}
}
);
@ -201,111 +198,9 @@ void WaylandServer::initWorkspace()
);
}
);
connect(workspace(), &Workspace::clientAdded, this, &WaylandServer::announceClientToWindowManagement);
connect(this, &WaylandServer::shellClientAdded, this, &WaylandServer::announceClientToWindowManagement);
}
}
void WaylandServer::announceClientToWindowManagement(AbstractClient *c)
{
if (!c->surface()) {
return;
}
using namespace KWayland::Server;
auto w = m_windowManagement->createWindow(c);
w->setTitle(c->caption());
w->setVirtualDesktop(c->isOnAllDesktops() ? 0 : c->desktop() - 1);
w->setActive(c->isActive());
w->setFullscreen(c->isFullScreen());
w->setKeepAbove(c->keepAbove());
w->setKeepBelow(c->keepBelow());
w->setMaximized(c->maximizeMode() == KWin::MaximizeFull);
w->setMinimized(c->isMinimized());
w->setOnAllDesktops(c->isOnAllDesktops());
w->setDemandsAttention(c->isDemandingAttention());
w->setCloseable(c->isCloseable());
w->setMaximizeable(c->isMaximizable());
w->setMinimizeable(c->isMinimizable());
w->setFullscreenable(c->isFullScreenable());
w->setThemedIconName(c->icon().name().isEmpty() ? QStringLiteral("xorg") : c->icon().name());
connect(c, &AbstractClient::captionChanged, w, [w, c] { w->setTitle(c->caption()); });
connect(c, &AbstractClient::desktopChanged, w,
[w, c] {
if (c->isOnAllDesktops()) {
w->setOnAllDesktops(true);
return;
}
w->setVirtualDesktop(c->desktop() - 1);
w->setOnAllDesktops(false);
}
);
connect(c, &AbstractClient::activeChanged, w, [w, c] { w->setActive(c->isActive()); });
connect(c, &AbstractClient::fullScreenChanged, w, [w, c] { w->setFullscreen(c->isFullScreen()); });
connect(c, &AbstractClient::keepAboveChanged, w, &PlasmaWindowInterface::setKeepAbove);
connect(c, &AbstractClient::keepBelowChanged, w, &PlasmaWindowInterface::setKeepBelow);
connect(c, &AbstractClient::minimizedChanged, w, [w, c] { w->setMinimized(c->isMinimized()); });
connect(c, static_cast<void (AbstractClient::*)(AbstractClient*,MaximizeMode)>(&AbstractClient::clientMaximizedStateChanged), w,
[w] (KWin::AbstractClient *c, MaximizeMode mode) {
Q_UNUSED(c);
w->setMaximized(mode == KWin::MaximizeFull);
}
);
connect(c, &AbstractClient::demandsAttentionChanged, w, [w, c] { w->setDemandsAttention(c->isDemandingAttention()); });
connect(c, &AbstractClient::iconChanged, w,
[w, c] {
const QIcon icon = c->icon();
w->setThemedIconName(icon.name().isEmpty() ? QStringLiteral("xorg") : icon.name());
}
);
connect(w, &PlasmaWindowInterface::closeRequested, c, [c] { c->closeWindow(); });
connect(w, &PlasmaWindowInterface::virtualDesktopRequested, c,
[c] (quint32 desktop) {
workspace()->sendClientToDesktop(c, desktop + 1, true);
}
);
connect(w, &PlasmaWindowInterface::fullscreenRequested, c,
[c] (bool set) {
c->setFullScreen(set, false);
}
);
connect(w, &PlasmaWindowInterface::minimizedRequested, c,
[c] (bool set) {
if (set) {
c->minimize();
} else {
c->unminimize();
}
}
);
connect(w, &PlasmaWindowInterface::maximizedRequested, c,
[c] (bool set) {
c->maximize(set ? MaximizeFull : MaximizeRestore);
}
);
connect(w, &PlasmaWindowInterface::keepAboveRequested, c,
[c] (bool set) {
c->setKeepAbove(set);
}
);
connect(w, &PlasmaWindowInterface::keepBelowRequested, c,
[c] (bool set) {
c->setKeepBelow(set);
}
);
connect(w, &PlasmaWindowInterface::demandsAttentionRequested, c,
[c] (bool set) {
c->demandAttention(set);
}
);
connect(w, &PlasmaWindowInterface::activeRequested, c,
[c] (bool set) {
if (set) {
workspace()->activateClient(c, true);
}
}
);
}
void WaylandServer::initOutputs()
{
if (m_backend && m_backend->handlesOutputs()) {

View file

@ -76,6 +76,9 @@ public:
KWayland::Server::ShellInterface *shell() {
return m_shell;
}
KWayland::Server::PlasmaWindowManagementInterface *windowManagement() {
return m_windowManagement;
}
QList<ShellClient*> clients() const {
return m_clients;
}
@ -138,7 +141,6 @@ Q_SIGNALS:
private:
void fakeDummyQtWindowInput();
quint16 createClientId(KWayland::Server::ClientConnection *c);
void announceClientToWindowManagement(AbstractClient *c);
KWayland::Server::Display *m_display = nullptr;
KWayland::Server::CompositorInterface *m_compositor = nullptr;
KWayland::Server::SeatInterface *m_seat = nullptr;