13#if KWIN_BUILD_ACTIVITIES
36#include <KDecoration2/DecoratedClient>
37#include <KDecoration2/Decoration>
44 , m_shellSurface(shellSurface)
45 , m_configureTimer(new QTimer(this))
48 this, &XdgSurfaceWindow::handleConfigureAcknowledged);
52 this, &XdgSurfaceWindow::handleCommit);
69 this, &XdgSurfaceWindow::setHaveNextWindowGeometry);
71 this, &XdgSurfaceWindow::setHaveNextWindowGeometry);
73 this, &XdgSurfaceWindow::setHaveNextWindowGeometry);
75 this, &XdgSurfaceWindow::setHaveNextWindowGeometry);
77 this, &XdgSurfaceWindow::setHaveNextWindowGeometry);
79 this, &XdgSurfaceWindow::setHaveNextWindowGeometry);
85 m_configureTimer->setSingleShot(
true);
100 return m_lastAcknowledgedConfigure.get();
106 m_configureTimer->start();
115 if (!m_configureEvents.isEmpty()) {
121 configureEvent->
flags |= m_configureFlags;
122 m_configureFlags = {};
124 m_configureEvents.append(configureEvent);
127void XdgSurfaceWindow::handleConfigureAcknowledged(quint32 serial)
129 m_lastAcknowledgedConfigureSerial = serial;
132void XdgSurfaceWindow::handleCommit()
138 if (m_lastAcknowledgedConfigureSerial.has_value()) {
139 const quint32 serial = m_lastAcknowledgedConfigureSerial.value();
140 while (!m_configureEvents.isEmpty()) {
141 if (serial < m_configureEvents.constFirst()->serial) {
144 m_lastAcknowledgedConfigure.reset(m_configureEvents.takeFirst());
149 if (haveNextWindowGeometry()) {
150 handleNextWindowGeometry();
151 resetHaveNextWindowGeometry();
155 m_lastAcknowledgedConfigure.reset();
156 m_lastAcknowledgedConfigureSerial.reset();
169void XdgSurfaceWindow::maybeUpdateMoveResizeGeometry(
const QRectF &rect)
172 if (m_configureTimer->isActive()) {
179 for (
int i = m_configureEvents.count() - 1; i >= 0; --i) {
188void XdgSurfaceWindow::handleNextWindowGeometry()
199 if (m_windowGeometry.isValid()) {
200 m_windowGeometry &= boundingGeometry;
202 m_windowGeometry = boundingGeometry;
205 if (m_windowGeometry.isEmpty()) {
206 qCWarning(KWIN_CORE) <<
"Committed empty window geometry, dealing with a buggy client!";
225bool XdgSurfaceWindow::haveNextWindowGeometry()
const
227 return m_haveNextWindowGeometry || m_lastAcknowledgedConfigure;
230void XdgSurfaceWindow::setHaveNextWindowGeometry()
232 m_haveNextWindowGeometry =
true;
235void XdgSurfaceWindow::resetHaveNextWindowGeometry()
237 m_haveNextWindowGeometry =
false;
269 const qreal left =
rect.left() +
borderLeft() - m_windowGeometry.left();
270 const qreal top =
rect.top() +
borderTop() - m_windowGeometry.top();
271 return QRectF(QPoint(left, top),
surface()->
size());
279 m_shellSurface->disconnect(
this);
280 m_shellSurface->
surface()->disconnect(
this);
291 m_configureTimer->stop();
292 qDeleteAll(m_configureEvents);
293 m_configureEvents.clear();
314 auto updatePosition = [
this, shellSurface] {
317 auto showUnderCursor = [
this] {
319 auto moveUnderCursor = [
this] {
320 if (
input()->hasPointer()) {
327 auto updateRole = [
this, shellSurface] {
328 NET::WindowType
type = NET::Unknown;
329 switch (shellSurface->
role()) {
337 type = NET::OnScreenDisplay;
340 type = NET::Notification;
346 type = NET::CriticalNotification;
349 type = NET::AppletPopup;
363 case NET::OnScreenDisplay:
364 case NET::Notification:
365 case NET::CriticalNotification:
367 case NET::AppletPopup:
369#if KWIN_BUILD_ACTIVITIES
382 workspace()->activateWindow(this);
406 , m_shellSurface(shellSurface)
408 setDesktops({VirtualDesktopManager::self()->currentDesktop()});
409#if KWIN_BUILD_ACTIVITIES
417 this, &XdgToplevelWindow::handleWindowTitleChanged);
419 this, &XdgToplevelWindow::handleWindowClassChanged);
421 this, &XdgToplevelWindow::handleWindowMenuRequested);
423 this, &XdgToplevelWindow::handleMoveRequested);
425 this, &XdgToplevelWindow::handleResizeRequested);
427 this, &XdgToplevelWindow::handleMaximizeRequested);
429 this, &XdgToplevelWindow::handleUnmaximizeRequested);
431 this, &XdgToplevelWindow::handleFullscreenRequested);
433 this, &XdgToplevelWindow::handleUnfullscreenRequested);
435 this, &XdgToplevelWindow::handleMinimizeRequested);
437 this, &XdgToplevelWindow::handleTransientForChanged);
439 this, &XdgToplevelWindow::initialize);
443 this, &XdgToplevelWindow::handleMaximumSizeChanged);
445 this, &XdgToplevelWindow::handleMinimumSizeChanged);
447 this, &XdgToplevelWindow::handlePingTimeout);
449 this, &XdgToplevelWindow::handlePingDelayed);
451 this, &XdgToplevelWindow::handlePongReceived);
454 this, &XdgToplevelWindow::handleForeignTransientForChanged);
460 m_killPrompt->quit();
468 if (m_appMenuInterface) {
469 m_appMenuInterface->disconnect(
this);
471 if (m_paletteInterface) {
472 m_paletteInterface->disconnect(
this);
474 if (m_xdgDecoration) {
475 m_xdgDecoration->disconnect(
this);
477 if (m_serverDecoration) {
478 m_serverDecoration->disconnect(
this);
481 m_shellSurface->disconnect(
this);
484 this, &XdgToplevelWindow::handleForeignTransientForChanged);
491 return m_shellSurface;
496 return m_maximizeMode;
501 return m_requestedMaximizeMode;
506 const int enforcedMinimum = m_nextDecoration ? 150 : 20;
513 const int enforcedMinimum = m_nextDecoration ? 150 : 20;
519 return m_isFullScreen;
524 return m_isRequestedFullScreen;
560 if (
rules()->checkSize(QSize()).isValid()) {
565 return min.width() < max.width() || min.height() < max.height();
575 if (!
rules()->checkFullScreen(
true)) {
597 if (!
rules()->checkMinimize(
true)) {
613 return m_isTransient;
623 return m_userNoBorder;
629 if (m_userNoBorder == set) {
632 m_userNoBorder = set;
633 configureDecoration();
640 configureDecoration();
651 updateCapabilities();
657 sendPing(PingReason::CloseWindow);
664 QSize framePadding(0, 0);
665 if (m_nextDecoration) {
666 framePadding.setWidth(m_nextDecoration->borderLeft() + m_nextDecoration->borderRight());
667 framePadding.setHeight(m_nextDecoration->borderTop() + m_nextDecoration->borderBottom());
671 if (!nextClientSize.isEmpty()) {
672 nextClientSize.rwidth() -= framePadding.width();
673 nextClientSize.rheight() -= framePadding.height();
676 if (nextClientSize.isEmpty()) {
678 bounds.rwidth() -= framePadding.width();
679 bounds.rheight() -= framePadding.height();
683 const quint32 serial = m_shellSurface->
sendConfigure(nextClientSize.toSize(), m_nextStates);
687 configureEvent->
states = m_nextStates;
688 configureEvent->
decoration = m_nextDecoration;
689 configureEvent->
serial = serial;
691 return configureEvent;
697 if (configureEvent &&
decoration() != configureEvent->decoration.get()) {
698 connect(configureEvent->decoration.get(), &KDecoration2::Decoration::bordersChanged,
this, [
this]() {
709void XdgToplevelWindow::handleRoleCommit()
712 if (configureEvent) {
713 handleStatesAcknowledged(configureEvent->states);
717void XdgToplevelWindow::doMinimize()
719 if (m_isInitialized) {
727void XdgToplevelWindow::doInteractiveResizeSync(
const QRectF &rect)
732void XdgToplevelWindow::doSetActive()
734 WaylandWindow::doSetActive();
737 m_nextStates |= XdgToplevelInterface::State::Activated;
745void XdgToplevelWindow::doSetFullScreen()
747 if (isRequestedFullScreen()) {
748 m_nextStates |= XdgToplevelInterface::State::FullScreen;
756void XdgToplevelWindow::doSetMaximized()
759 m_nextStates |= XdgToplevelInterface::State::MaximizedHorizontal;
765 m_nextStates |= XdgToplevelInterface::State::MaximizedVertical;
773static Qt::Edges anchorsForQuickTileMode(QuickTileMode mode)
775 if (mode == QuickTileMode(QuickTileFlag::None)) {
779 Qt::Edges anchors = Qt::LeftEdge | Qt::TopEdge | Qt::RightEdge | Qt::BottomEdge;
781 if ((mode & QuickTileFlag::Left) && !(mode & QuickTileFlag::Right)) {
782 anchors &= ~Qt::RightEdge;
784 if ((mode & QuickTileFlag::Right) && !(mode & QuickTileFlag::Left)) {
785 anchors &= ~Qt::LeftEdge;
788 if ((mode & QuickTileFlag::Top) && !(mode & QuickTileFlag::Bottom)) {
789 anchors &= ~Qt::BottomEdge;
791 if ((mode & QuickTileFlag::Bottom) && !(mode & QuickTileFlag::Top)) {
792 anchors &= ~Qt::TopEdge;
798void XdgToplevelWindow::doSetQuickTileMode()
800 const Qt::Edges anchors = anchorsForQuickTileMode(quickTileMode());
802 if (anchors & Qt::LeftEdge) {
803 m_nextStates |= XdgToplevelInterface::State::TiledLeft;
808 if (anchors & Qt::RightEdge) {
809 m_nextStates |= XdgToplevelInterface::State::TiledRight;
814 if (anchors & Qt::TopEdge) {
815 m_nextStates |= XdgToplevelInterface::State::TiledTop;
820 if (anchors & Qt::BottomEdge) {
821 m_nextStates |= XdgToplevelInterface::State::TiledBottom;
829bool XdgToplevelWindow::doStartInteractiveMoveResize()
831 if (interactiveMoveResizeGravity() != Gravity::None) {
832 m_nextGravity = interactiveMoveResizeGravity();
833 m_nextStates |= XdgToplevelInterface::State::Resizing;
839void XdgToplevelWindow::doFinishInteractiveMoveResize()
841 if (m_nextStates & XdgToplevelInterface::State::Resizing) {
847void XdgToplevelWindow::doSetSuspended()
850 m_nextStates |= XdgToplevelInterface::State::Suspended;
858bool XdgToplevelWindow::takeFocus()
861 sendPing(PingReason::FocusWindow);
867bool XdgToplevelWindow::wantsInput()
const
869 return rules()->checkAcceptFocus(acceptsFocus());
872bool XdgToplevelWindow::dockWantsInput()
const
874 if (m_plasmaShellSurface) {
875 if (m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Panel) {
876 return m_plasmaShellSurface->panelTakesFocus();
882bool XdgToplevelWindow::acceptsFocus()
const
884 if (m_plasmaShellSurface) {
885 if (m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::OnScreenDisplay || m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::ToolTip) {
888 switch (m_plasmaShellSurface->role()) {
889 case PlasmaShellSurfaceInterface::Role::Notification:
890 case PlasmaShellSurfaceInterface::Role::CriticalNotification:
891 return m_plasmaShellSurface->panelTakesFocus();
896 return !isDeleted() && readyForPainting();
899void XdgToplevelWindow::handleWindowTitleChanged()
901 setCaption(m_shellSurface->windowTitle());
904void XdgToplevelWindow::handleWindowClassChanged()
906 const QString applicationId = m_shellSurface->windowClass();
907 setResourceClass(resourceName(), applicationId);
908 if (shellSurface()->isConfigured()) {
909 evaluateWindowRules();
911 setDesktopFileName(applicationId);
914void XdgToplevelWindow::handleWindowMenuRequested(SeatInterface *seat,
const QPoint &surfacePos,
917 performMouseCommand(Options::MouseOperationsMenu, mapFromLocal(surfacePos));
920void XdgToplevelWindow::handleMoveRequested(SeatInterface *seat, quint32 serial)
922 if (!
seat->hasImplicitPointerGrab(serial) && !
seat->hasImplicitTouchGrab(serial)
928 if (
seat->hasImplicitPointerGrab(serial)) {
930 }
else if (
seat->hasImplicitTouchGrab(serial)) {
935 performMouseCommand(Options::MouseMove, cursorPos);
937 qCDebug(KWIN_CORE) <<
this <<
"is immovable, ignoring the move request";
941void XdgToplevelWindow::handleResizeRequested(SeatInterface *seat, XdgToplevelInterface::ResizeAnchor anchor, quint32 serial)
943 if (!
seat->hasImplicitPointerGrab(serial) && !
seat->hasImplicitTouchGrab(serial)
947 if (!isResizable() || isShade()) {
950 if (isInteractiveMoveResize()) {
951 finishInteractiveMoveResize(
false);
953 setInteractiveMoveResizePointerButtonDown(
true);
955 if (
seat->hasImplicitPointerGrab(serial)) {
957 }
else if (
seat->hasImplicitTouchGrab(serial)) {
962 setInteractiveMoveOffset(cursorPos - pos());
963 setInvertedInteractiveMoveOffset(rect().bottomRight() - interactiveMoveOffset());
964 setUnrestrictedInteractiveMoveResize(
false);
967 case XdgToplevelInterface::ResizeAnchor::TopLeft:
968 gravity = Gravity::TopLeft;
970 case XdgToplevelInterface::ResizeAnchor::Top:
971 gravity = Gravity::Top;
973 case XdgToplevelInterface::ResizeAnchor::TopRight:
974 gravity = Gravity::TopRight;
976 case XdgToplevelInterface::ResizeAnchor::Right:
977 gravity = Gravity::Right;
979 case XdgToplevelInterface::ResizeAnchor::BottomRight:
980 gravity = Gravity::BottomRight;
982 case XdgToplevelInterface::ResizeAnchor::Bottom:
983 gravity = Gravity::Bottom;
985 case XdgToplevelInterface::ResizeAnchor::BottomLeft:
986 gravity = Gravity::BottomLeft;
988 case XdgToplevelInterface::ResizeAnchor::Left:
989 gravity = Gravity::Left;
992 gravity = Gravity::None;
995 setInteractiveMoveResizeGravity(gravity);
996 if (!startInteractiveMoveResize()) {
997 setInteractiveMoveResizePointerButtonDown(
false);
1002void XdgToplevelWindow::handleStatesAcknowledged(
const XdgToplevelInterface::States &states)
1004 const XdgToplevelInterface::States delta = m_acknowledgedStates ^ states;
1006 if (delta & XdgToplevelInterface::State::Maximized) {
1008 if (states & XdgToplevelInterface::State::MaximizedHorizontal) {
1009 maximizeMode =
MaximizeMode(maximizeMode | MaximizeHorizontal);
1011 if (states & XdgToplevelInterface::State::MaximizedVertical) {
1012 maximizeMode =
MaximizeMode(maximizeMode | MaximizeVertical);
1014 updateMaximizeMode(maximizeMode);
1016 if (delta & XdgToplevelInterface::State::FullScreen) {
1017 updateFullScreenMode(states & XdgToplevelInterface::State::FullScreen);
1020 m_acknowledgedStates = states;
1023void XdgToplevelWindow::handleMaximizeRequested()
1025 if (m_isInitialized) {
1026 maximize(MaximizeFull);
1027 scheduleConfigure();
1029 m_initialStates |= XdgToplevelInterface::State::Maximized;
1033void XdgToplevelWindow::handleUnmaximizeRequested()
1035 if (m_isInitialized) {
1036 maximize(MaximizeRestore);
1037 scheduleConfigure();
1039 m_initialStates &= ~XdgToplevelInterface::State::Maximized;
1043void XdgToplevelWindow::handleFullscreenRequested(OutputInterface *output)
1045 m_fullScreenRequestedOutput = output ? output->handle() :
nullptr;
1046 if (m_isInitialized) {
1047 setFullScreen(
true);
1048 scheduleConfigure();
1050 m_initialStates |= XdgToplevelInterface::State::FullScreen;
1054void XdgToplevelWindow::handleUnfullscreenRequested()
1056 m_fullScreenRequestedOutput.clear();
1057 if (m_isInitialized) {
1058 setFullScreen(
false);
1059 scheduleConfigure();
1061 m_initialStates &= ~XdgToplevelInterface::State::FullScreen;
1065void XdgToplevelWindow::handleMinimizeRequested()
1070void XdgToplevelWindow::handleTransientForChanged()
1072 SurfaceInterface *transientForSurface =
nullptr;
1073 if (XdgToplevelInterface *parentToplevel = m_shellSurface->parentXdgToplevel()) {
1074 transientForSurface = parentToplevel->surface();
1076 if (!transientForSurface) {
1080 if (transientForWindow != transientFor()) {
1081 if (transientFor()) {
1084 if (transientForWindow) {
1085 transientForWindow->addTransient(
this);
1087 setTransientFor(transientForWindow);
1089 m_isTransient = transientForWindow;
1092void XdgToplevelWindow::handleForeignTransientForChanged(SurfaceInterface *child)
1094 if (surface() == child) {
1095 handleTransientForChanged();
1099void XdgToplevelWindow::handlePingTimeout(quint32 serial)
1101 auto pingIt = m_pings.find(serial);
1102 if (pingIt == m_pings.end()) {
1105 if (pingIt.value() == PingReason::CloseWindow) {
1106 qCDebug(KWIN_CORE) <<
"Final ping timeout on a close attempt, asking to kill:" << caption();
1108 if (!m_killPrompt) {
1109 m_killPrompt = std::make_unique<KillPrompt>(
this);
1111 if (!m_killPrompt->isRunning()) {
1112 m_killPrompt->start();
1115 m_pings.erase(pingIt);
1118void XdgToplevelWindow::handlePingDelayed(quint32 serial)
1120 auto it = m_pings.find(serial);
1121 if (it != m_pings.end()) {
1122 qCDebug(KWIN_CORE) <<
"First ping timeout:" << caption();
1123 setUnresponsive(
true);
1127void XdgToplevelWindow::handlePongReceived(quint32 serial)
1129 if (m_pings.remove(serial)) {
1130 setUnresponsive(
false);
1132 m_killPrompt->quit();
1137void XdgToplevelWindow::handleMaximumSizeChanged()
1139 updateCapabilities();
1140 Q_EMIT maximizeableChanged(isMaximizable());
1143void XdgToplevelWindow::handleMinimumSizeChanged()
1145 updateCapabilities();
1146 Q_EMIT maximizeableChanged(isMaximizable());
1149void XdgToplevelWindow::sendPing(PingReason reason)
1151 XdgShellInterface *shell = m_shellSurface->shell();
1152 XdgSurfaceInterface *surface = m_shellSurface->xdgSurface();
1154 const quint32 serial = shell->ping(surface);
1155 m_pings.insert(serial, reason);
1158MaximizeMode XdgToplevelWindow::initialMaximizeMode()
const
1161 if (m_initialStates & XdgToplevelInterface::State::MaximizedHorizontal) {
1162 maximizeMode =
MaximizeMode(maximizeMode | MaximizeHorizontal);
1164 if (m_initialStates & XdgToplevelInterface::State::MaximizedVertical) {
1165 maximizeMode =
MaximizeMode(maximizeMode | MaximizeVertical);
1167 return maximizeMode;
1170bool XdgToplevelWindow::initialFullScreenMode()
const
1172 return m_initialStates & XdgToplevelInterface::State::FullScreen;
1175void XdgToplevelWindow::initialize()
1177 bool needsPlacement = isPlaceable();
1181 const QPointF forcedPosition = rules()->checkPositionSafe(invalidPoint,
true);
1182 if (forcedPosition != invalidPoint) {
1183 move(forcedPosition);
1185 const QSizeF forcedSize = rules()->checkSize(QSize(),
true);
1186 if (forcedSize.isValid()) {
1190 maximize(rules()->checkMaximize(initialMaximizeMode(),
true));
1191 setFullScreen(rules()->checkFullScreen(initialFullScreenMode(),
true));
1192 setOnActivities(rules()->checkActivity(activities(),
true));
1193 setDesktops(rules()->checkDesktops(desktops(),
true));
1194 setDesktopFileName(rules()->checkDesktopFile(desktopFileName(),
true));
1195 setMinimized(rules()->checkMinimize(isMinimized(),
true));
1196 setSkipTaskbar(rules()->checkSkipTaskbar(skipTaskbar(),
true));
1197 setSkipPager(rules()->checkSkipPager(skipPager(),
true));
1198 setSkipSwitcher(rules()->checkSkipSwitcher(skipSwitcher(),
true));
1199 setKeepAbove(rules()->checkKeepAbove(keepAbove(),
true));
1200 setKeepBelow(rules()->checkKeepBelow(keepBelow(),
true));
1201 setShortcut(rules()->checkShortcut(shortcut().toString(),
true));
1202 setNoBorder(rules()->checkNoBorder(noBorder(),
true));
1205 if (rules()->checkPosition(invalidPoint,
true) != invalidPoint) {
1206 needsPlacement =
false;
1210 if (requestedMaximizeMode() != MaximizeRestore) {
1211 needsPlacement =
false;
1215 updateWindowRules(Rules::All);
1217 if (isRequestedFullScreen()) {
1218 needsPlacement =
false;
1220 if (needsPlacement) {
1225 configureDecoration();
1226 scheduleConfigure();
1227 updateColorScheme();
1228 updateCapabilities();
1229 updateClientOutputs();
1230 setupWindowManagementInterface();
1232 m_isInitialized =
true;
1235void XdgToplevelWindow::updateMaximizeMode(MaximizeMode maximizeMode)
1237 if (m_maximizeMode == maximizeMode) {
1240 m_maximizeMode = maximizeMode;
1241 updateWindowRules(Rules::MaximizeVert | Rules::MaximizeHoriz);
1242 Q_EMIT maximizedChanged();
1245void XdgToplevelWindow::updateFullScreenMode(
bool set)
1247 if (m_isFullScreen == set) {
1250 StackingUpdatesBlocker blocker1(
workspace());
1251 m_isFullScreen = set;
1253 updateWindowRules(Rules::Fullscreen);
1254 Q_EMIT fullScreenChanged();
1257void XdgToplevelWindow::updateCapabilities()
1259 XdgToplevelInterface::Capabilities caps = XdgToplevelInterface::Capability::WindowMenu;
1261 if (isMaximizable()) {
1262 caps.setFlag(XdgToplevelInterface::Capability::Maximize);
1264 if (isFullScreenable()) {
1265 caps.setFlag(XdgToplevelInterface::Capability::FullScreen);
1267 if (isMinimizable()) {
1268 caps.setFlag(XdgToplevelInterface::Capability::Minimize);
1271 if (m_capabilities != caps) {
1272 m_capabilities = caps;
1273 m_shellSurface->sendWmCapabilities(caps);
1277QString XdgToplevelWindow::preferredColorScheme()
const
1279 if (m_paletteInterface) {
1280 return rules()->checkDecoColor(m_paletteInterface->palette());
1282 return rules()->checkDecoColor(QString());
1287 m_appMenuInterface = appMenu;
1290 updateApplicationMenuServiceName(address.serviceName);
1291 updateApplicationMenuObjectPath(address.objectPath);
1293 connect(m_appMenuInterface, &AppMenuInterface::addressChanged,
this, updateMenu);
1294 updateMenu(appMenu->address());
1297XdgToplevelWindow::DecorationMode XdgToplevelWindow::preferredDecorationMode()
const
1299 if (!Decoration::DecorationBridge::hasPlugin()) {
1300 return DecorationMode::Client;
1301 }
else if (m_userNoBorder || isRequestedFullScreen()) {
1302 return DecorationMode::None;
1305 if (m_xdgDecoration) {
1306 switch (m_xdgDecoration->preferredMode()) {
1307 case XdgToplevelDecorationV1Interface::Mode::Undefined:
1308 return DecorationMode::Server;
1309 case XdgToplevelDecorationV1Interface::Mode::None:
1310 return DecorationMode::None;
1311 case XdgToplevelDecorationV1Interface::Mode::Client:
1312 return DecorationMode::Client;
1313 case XdgToplevelDecorationV1Interface::Mode::Server:
1314 return DecorationMode::Server;
1318 if (m_serverDecoration) {
1319 switch (m_serverDecoration->preferredMode()) {
1320 case ServerSideDecorationManagerInterface::Mode::None:
1321 return DecorationMode::None;
1322 case ServerSideDecorationManagerInterface::Mode::Client:
1323 return DecorationMode::Client;
1324 case ServerSideDecorationManagerInterface::Mode::Server:
1325 return DecorationMode::Server;
1329 return DecorationMode::Client;
1332void XdgToplevelWindow::clearDecoration()
1334 m_nextDecoration =
nullptr;
1337void XdgToplevelWindow::configureDecoration()
1339 const DecorationMode decorationMode = preferredDecorationMode();
1340 switch (decorationMode) {
1341 case DecorationMode::None:
1342 case DecorationMode::Client:
1345 case DecorationMode::Server:
1346 if (!m_nextDecoration) {
1347 m_nextDecoration.reset(Workspace::self()->decorationBridge()->createDecoration(
this));
1353 if (m_xdgDecoration) {
1354 configureXdgDecoration(decorationMode);
1355 }
else if (m_serverDecoration) {
1356 configureServerDecoration(decorationMode);
1360void XdgToplevelWindow::configureXdgDecoration(DecorationMode decorationMode)
1362 switch (decorationMode) {
1363 case DecorationMode::None:
1364 m_xdgDecoration->sendConfigure(XdgToplevelDecorationV1Interface::Mode::None);
1366 case DecorationMode::Client:
1367 m_xdgDecoration->sendConfigure(XdgToplevelDecorationV1Interface::Mode::Client);
1369 case DecorationMode::Server:
1370 m_xdgDecoration->sendConfigure(XdgToplevelDecorationV1Interface::Mode::Server);
1373 scheduleConfigure();
1376void XdgToplevelWindow::configureServerDecoration(DecorationMode decorationMode)
1378 switch (decorationMode) {
1379 case DecorationMode::None:
1380 m_serverDecoration->setMode(ServerSideDecorationManagerInterface::Mode::None);
1382 case DecorationMode::Client:
1383 m_serverDecoration->setMode(ServerSideDecorationManagerInterface::Mode::Client);
1385 case DecorationMode::Server:
1386 m_serverDecoration->setMode(ServerSideDecorationManagerInterface::Mode::Server);
1389 scheduleConfigure();
1394 m_xdgDecoration = decoration;
1396 connect(m_xdgDecoration, &XdgToplevelDecorationV1Interface::destroyed,
1397 this, &XdgToplevelWindow::clearDecoration);
1398 connect(m_xdgDecoration, &XdgToplevelDecorationV1Interface::preferredModeChanged,
this, [
this] {
1399 if (m_isInitialized) {
1400 configureDecoration();
1407 m_serverDecoration = decoration;
1408 if (m_isInitialized) {
1409 configureDecoration();
1412 connect(m_serverDecoration, &ServerSideDecorationInterface::destroyed,
1413 this, &XdgToplevelWindow::clearDecoration);
1414 connect(m_serverDecoration, &ServerSideDecorationInterface::preferredModeChanged,
this, [
this]() {
1415 if (m_isInitialized) {
1416 configureDecoration();
1423 m_paletteInterface = palette;
1425 connect(m_paletteInterface, &ServerSideDecorationPaletteInterface::paletteChanged,
1426 this, &XdgToplevelWindow::updateColorScheme);
1427 connect(m_paletteInterface, &QObject::destroyed,
1428 this, &XdgToplevelWindow::updateColorScheme);
1429 updateColorScheme();
1432void XdgToplevelWindow::setFullScreen(
bool set)
1434 if (!isFullScreenable()) {
1438 set = rules()->checkFullScreen(set);
1439 if (m_isRequestedFullScreen == set) {
1443 m_isRequestedFullScreen = set;
1444 configureDecoration();
1447 const Output *output = m_fullScreenRequestedOutput ? m_fullScreenRequestedOutput.data() : moveResizeOutput();
1448 setFullscreenGeometryRestore(moveResizeGeometry());
1451 m_fullScreenRequestedOutput.clear();
1452 if (fullscreenGeometryRestore().isValid()) {
1453 moveResize(QRectF(fullscreenGeometryRestore().topLeft(),
1454 constrainFrameSize(fullscreenGeometryRestore().size())));
1465static bool changeMaximizeRecursion =
false;
1468 if (changeMaximizeRecursion) {
1472 if (!isResizable() || isAppletPopup()) {
1479 const QRectF oldGeometry = moveResizeGeometry();
1481 mode = rules()->checkMaximize(mode);
1482 if (m_requestedMaximizeMode == mode) {
1486 Q_EMIT maximizedAboutToChange(mode);
1487 m_requestedMaximizeMode = mode;
1491 changeMaximizeRecursion =
true;
1492 const auto c = m_nextDecoration->client();
1494 Q_EMIT c->maximizedVerticallyChanged(m_requestedMaximizeMode &
MaximizeVertical);
1497 Q_EMIT c->maximizedHorizontallyChanged(m_requestedMaximizeMode &
MaximizeHorizontal);
1500 Q_EMIT c->maximizedChanged(m_requestedMaximizeMode ==
MaximizeFull);
1502 changeMaximizeRecursion =
false;
1509 if (quickTileMode() == QuickTileMode(QuickTileFlag::None)) {
1510 QRectF savedGeometry = geometryRestore();
1512 savedGeometry.setTop(oldGeometry.top());
1513 savedGeometry.setBottom(oldGeometry.bottom());
1516 savedGeometry.setLeft(oldGeometry.left());
1517 savedGeometry.setRight(oldGeometry.right());
1519 setGeometryRestore(savedGeometry);
1522 const MaximizeMode delta = m_requestedMaximizeMode ^ oldMode;
1523 QRectF geometry = oldGeometry;
1528 geometry.setX(clientArea.x());
1529 geometry.setWidth(clientArea.width());
1530 }
else if (geometryRestore().isValid()) {
1532 geometry.setX(geometryRestore().x());
1533 geometry.setWidth(geometryRestore().width());
1538 geometry.setX(clientArea.x());
1539 geometry.setWidth(0);
1546 geometry.setY(clientArea.y());
1547 geometry.setHeight(clientArea.height());
1548 }
else if (geometryRestore().isValid()) {
1550 geometry.setY(geometryRestore().y());
1551 geometry.setHeight(geometryRestore().height());
1556 geometry.setY(clientArea.y());
1557 geometry.setHeight(0);
1561 const auto oldQuickTileMode = quickTileMode();
1564 updateQuickTileMode(QuickTileFlag::Maximize);
1566 updateQuickTileMode(QuickTileFlag::None);
1570 updateQuickTileMode(QuickTileFlag::None);
1573 moveResize(geometry);
1575 if (oldQuickTileMode != quickTileMode()) {
1576 doSetQuickTileMode();
1577 Q_EMIT quickTileModeChanged();
1585 , m_shellSurface(shellSurface)
1590 this, &XdgPopupWindow::handleGrabRequested);
1592 this, &XdgPopupWindow::initialize);
1594 this, &XdgPopupWindow::handleRepositionRequested);
1602 this, &XdgPopupWindow::relayout);
1603 m_shellSurface->disconnect(
this);
1608void XdgPopupWindow::handleRepositionRequested(quint32 token)
1610 updateRelativePlacement();
1615void XdgPopupWindow::updateRelativePlacement()
1622 m_relativePlacement = QRectF(
m_plasmaShellSurface->position(), positioner.size()).translated(-parentPosition);
1624 m_relativePlacement = positioner.placement(bounds);
1628void XdgPopupWindow::relayout()
1631 updateRelativePlacement();
1643 return m_haveExplicitGrab;
1684 return m_relativePlacement.translated(parentPosition);
1720 configureEvent->
serial = serial;
1722 return configureEvent;
1725void XdgPopupWindow::handleGrabRequested(
SeatInterface *seat, quint32 serial)
1727 m_haveExplicitGrab =
true;
1730void XdgPopupWindow::initialize()
1733 parent->addTransient(
this);
1736#if KWIN_BUILD_ACTIVITIES
1740 updateRelativePlacement();
1749#include "moc_xdgshellwindow.cpp"
bool borderlessMaximizedWindows
bool electricBorderMaximize
void place(Window *c, const QRectF &area)
Resource for the org_kde_plasma_shell_surface interface.
void skipTaskbarChanged()
bool wantsOpenUnderCursor() const
bool skipSwitcher() const
void skipSwitcherChanged()
void openUnderCursorRequested()
bool isPositionSet() const
void panelTakesFocusChanged()
@ Desktop
The surface represents a desktop, normally stacked below all other surfaces.
@ CriticalNotification
The surface represents a critical notification, like battery is running out.
@ Normal
A normal surface.
@ Notification
The surface represents a notification.
@ Panel
The surface represents a panel (dock), normally stacked above normal surfaces.
@ OnScreenDisplay
The surface represents an on screen display, like a volume changed notification.
@ ToolTip
The surface represents a tooltip.
@ AppletPopup
The surface represents an applet popup window.
void discardUsed(Window *c, bool withdraw)
Represents a Seat on the Wayland Display.
Representing how a SurfaceInterface should be decorated.
void aboutToBeDestroyed()
QRectF boundingRect() const
SurfaceInterface * findForeignTransientForSurface(SurfaceInterface *surface)
Window * findWindow(const SurfaceInterface *surface) const
void removeWindow(Window *c)
void foreignTransientChanged(KWin::SurfaceInterface *child)
void updateGeometry(const QRectF &rect)
virtual QSizeF clientSizeToFrameSize(const QSizeF &size) const
void frameGeometryAboutToChange()
virtual void updateWindowRules(Rules::Types selection)
virtual QPointF framePosToClientPos(const QPointF &point) const
void keepInArea(QRectF area, bool partial=false)
void setDecoration(std::shared_ptr< KDecoration2::Decoration > decoration)
SurfaceInterface * surface() const
void setSkipTaskbar(bool set)
virtual void destroyWindow()=0
void setTransientFor(Window *transientFor)
virtual void applyWindowRules()
bool isInteractiveMoveResize() const
void windowShown(KWin::Window *window)
std::shared_ptr< KDecoration2::Decoration > decoration
void setOnAllDesktops(bool set)
virtual bool isFullScreen() const
QSizeF clientSize() const
void interactiveMoveResizeFinished()
void setDesktops(QList< VirtualDesktop * > desktops)
bool isAppletPopup() const
void destroyWindowManagementInterface()
virtual void leaveInteractiveMoveResize()
Output * moveResizeOutput() const
QRectF moveResizeGeometry() const
const WindowRules * rules() const
void setMoveResizeGeometry(const QRectF &geo)
virtual void removeTransient(Window *transient)
KWin::Window * transientFor
void frameGeometryChanged(const QRectF &oldGeometry)
bool isSpecialWindow() const
void setOnAllActivities(bool all)
bool areGeometryUpdatesBlocked() const
void setPendingMoveResizeMode(MoveResizeMode mode)
void setOnActivities(const QStringList &newActivitiesList)
virtual QSizeF frameSizeToClientSize(const QSizeF &size) const
void setSkipSwitcher(bool set)
QSizeF checkMaxSize(QSizeF s) const
bool checkNoBorder(bool noborder, bool init=false) const
bool checkCloseable(bool closeable) const
QSizeF checkMinSize(QSizeF s) const
QRectF clientArea(clientAreaOption, const Output *output, const VirtualDesktop *desktop) const
void windowHidden(Window *)
void updateMinimizedOfTransients(Window *)
Placement * placement() const
static Workspace * self()
RuleBook * rulebook() const
void pingTimeout(quint32 serial)
void pingDelayed(quint32 serial)
void pongReceived(quint32 serial)
QRect windowGeometry() const
void windowGeometryChanged(const QRect &rect)
void aboutToBeDestroyed()
SurfaceInterface * surface() const
void configureAcknowledged(quint32 serial)
NET::WindowType m_windowType
virtual void handleRoleDestroyed()
NET::WindowType windowType() const override
XdgSurfaceWindow(XdgSurfaceInterface *shellSurface)
void destroyWindow() override
void installPlasmaShellSurface(PlasmaShellSurfaceInterface *shellSurface)
XdgSurfaceConfigure * lastAcknowledgedConfigure() const
QRectF frameRectToBufferRect(const QRectF &rect) const override
~XdgSurfaceWindow() override
virtual XdgSurfaceConfigure * sendRoleConfigure() const =0
virtual void handleRoleCommit()
virtual void handleRolePrecommit()
void moveResizeInternal(const QRectF &rect, MoveResizeMode mode) override
QPointer< PlasmaShellSurfaceInterface > m_plasmaShellSurface
void windowClassChanged(const QString &windowClass)
void windowMenuRequested(KWin::SeatInterface *seat, const QPoint &pos, quint32 serial)
XdgShellInterface * shell() const
void minimumSizeChanged(const QSize &size)
quint32 sendConfigure(const QSize &size, const States &states)
void unfullscreenRequested()
void windowTitleChanged(const QString &windowTitle)
QSize maximumSize() const
void fullscreenRequested(KWin::OutputInterface *output)
void maximumSizeChanged(const QSize &size)
void moveRequested(KWin::SeatInterface *seat, quint32 serial)
void aboutToBeDestroyed()
void parentXdgToplevelChanged()
void sendConfigureBounds(const QSize &size)
QSize minimumSize() const
void unmaximizeRequested()
void initializeRequested()
void resizeRequested(KWin::SeatInterface *seat, KWin::XdgToplevelInterface::ResizeAnchor anchor, quint32 serial)
XdgToplevelInterface * shellSurface() const
~XdgToplevelWindow() override
bool isCloseable() const override
bool noBorder() const override
MaximizeMode requestedMaximizeMode() const override
bool isRequestedFullScreen() const override
bool isMovable() const override
XdgToplevelWindow(XdgToplevelInterface *shellSurface)
QSizeF maxSize() const override
bool isFullScreenable() const override
bool userCanSetNoBorder() const override
void handleRoleDestroyed() override
bool isTransient() const override
QSizeF minSize() const override
void closeWindow() override
bool isPlaceable() const override
void applyWindowRules() override
bool isFullScreen() const override
bool supportsWindowRules() const override
bool isMaximizable() const override
MaximizeMode maximizeMode() const override
void setNoBorder(bool set) override
bool isResizable() const override
void invalidateDecoration() override
bool isMovableAcrossScreens() const override
void handleRolePrecommit() override
bool isMinimizable() const override
XdgSurfaceConfigure * sendRoleConfigure() const override
KWayland::Client::Seat * seat
const QPoint invalidPoint(INT_MIN, INT_MIN)
@ MaximizeVertical
The window is maximized vertically.
@ MaximizeRestore
The window is not maximized in any direction.
@ MaximizeFull
Equal to MaximizeVertical | MaximizeHorizontal.
WaylandServer * waylandServer()
QRectF gravitateGeometry(const QRectF &rect, const QRectF &bounds, Gravity gravity)
InputRedirection * input()