44 place(c, area, policy);
53 placeOnMainWindow(c, area.toRect());
55 placeOnScreenDisplay(c, area.toRect());
75 placeAtRandom(c, area.toRect(), nextPlacement);
81 placeZeroCornered(c, area.toRect(), nextPlacement);
84 placeUnderMouse(c, area.toRect(), nextPlacement);
87 placeOnMainWindow(c, area.toRect(), nextPlacement);
90 placeMaximizing(c, area.toRect(), nextPlacement);
102 Q_ASSERT(area.isValid());
105 static int px = step;
106 static int py = 2 * step;
119 if (px > area.width() / 2) {
120 px = area.x() + step;
122 if (py > area.height() / 2) {
123 py = area.y() + step;
127 if (tx + c->width() > area.right()) {
128 tx = area.right() - c->width();
134 if (ty + c->height() > area.bottom()) {
135 ty = area.bottom() - c->height();
141 c->move(QPoint(tx, ty));
145static inline bool isIrrelevant(
const Window *window,
const Window *regarding, VirtualDesktop *desktop)
147 return window == regarding
148 || !window->isClient()
149 || !window->isShown()
151 || !window->isOnDesktop(desktop)
152 || !window->isOnCurrentActivity()
153 || window->isDesktop();
161 Q_ASSERT(area.isValid());
176 const int none = 0, h_wrong = -1, w_wrong = -2;
177 long int overlap, min_overlap = 0;
178 int x_optimal, y_optimal;
182 int cxl, cxr, cyt, cyb;
193 int ch = std::ceil(window->
height());
194 int cw = std::ceil(window->
width());
198 int area_xr = std::floor(area.x() + area.width());
199 int area_yb = std::floor(area.y() + area.height());
201 bool first_pass =
true;
206 if (y + ch > area_yb && ch < area.height()) {
208 }
else if (x + cw > area_xr) {
219 if (isIrrelevant(client, window, desktop)) {
224 xr = xl + client->width();
225 yb = yt + client->height();
228 if ((cxl < xr) && (cxr > xl) && (cyt < yb) && (cyb > yt)) {
229 xl = std::max(cxl, xl);
230 xr = std::min(cxr, xr);
231 yt = std::max(cyt, yt);
232 yb = std::min(cyb, yb);
233 if (client->keepAbove()) {
234 overlap += 16 * (xr - xl) * (yb - yt);
235 }
else if (client->keepBelow() && !client->isDock()) {
238 overlap += (xr - xl) * (yb - yt);
245 if (overlap == none) {
253 min_overlap = overlap;
256 else if (overlap >= none && overlap < min_overlap) {
257 min_overlap = overlap;
263 if (overlap > none) {
266 if (possible - cw > x) {
273 if (isIrrelevant(client, window, desktop)) {
279 xr = xl + client->width();
280 yb = yt + client->height();
284 if ((y < yb) && (yt < ch + y)) {
286 if ((xr > x) && (possible > xr)) {
291 if ((basket > x) && (possible > basket)) {
300 else if (overlap == w_wrong) {
304 if (possible - ch > y) {
311 if (isIrrelevant(client, window, desktop)) {
317 xr = xl + client->width();
318 yb = yt + client->height();
322 if ((yb > y) && (possible > yb)) {
327 if ((basket > y) && (possible > basket)) {
333 }
while ((overlap != none) && (overlap != h_wrong) && (y < area_yb));
335 if (ch >= area.height()) {
336 y_optimal = area.top();
340 window->
move(QPoint(x_optimal, y_optimal));
346 const auto desktops = VirtualDesktopManager::self()->desktops();
354 cci[desktop] = DesktopCascadingInfo{
355 .pos = QPoint(-1, -1),
364 return QPoint(area.width() / 48, area.height() / 48);
372 Q_ASSERT(area.isValid());
388 if (cci[dn].pos.x() < 0 || cci[dn].pos.x() < area.left() || cci[dn].pos.y() < area.top()) {
389 cci[dn].pos = QPoint(area.left(), area.top());
390 cci[dn].col = cci[dn].row = 0;
393 int xp = cci[dn].pos.x();
394 int yp = cci[dn].pos.y();
397 if ((yp + c->
height()) > area.height()) {
401 if ((xp + c->
width()) > area.width()) {
403 place(c, area, nextPlacement);
411 if (cci[dn].pos.x() != area.left() && cci[dn].pos.y() != area.top()) {
412 if (xp != area.left() && yp == area.top()) {
414 xp = delta.x() * cci[dn].col;
416 if (yp != area.top() && xp == area.left()) {
418 yp = delta.y() * cci[dn].row;
422 if (((xp + c->
width()) > area.width() - area.left()) || ((yp + c->
height()) > area.height() - area.top())) {
423 place(c, area, nextPlacement);
429 c->
move(QPoint(xp, yp));
432 cci[dn].pos = QPoint(xp + delta.x(), yp + delta.y());
440 Q_ASSERT(area.isValid());
446 const int xp = area.left() + (area.width() - c->
width()) / 2;
447 const int yp = area.top() + (area.height() - c->
height()) / 2;
450 c->
move(QPoint(xp, yp));
459 Q_ASSERT(area.isValid());
462 c->
move(area.topLeft());
476void Placement::placeOnScreenDisplay(
Window *c,
const QRect &area)
478 Q_ASSERT(area.isValid());
481 const int x = area.left() + (area.width() - c->width()) / 2;
482 const int y = area.top() + 2 * area.height() / 3 - c->height() / 2;
484 c->move(QPoint(x, y));
487void Placement::placeTransient(
Window *c)
489 c->moveResize(c->transientPlacement());
494 placeOnMainWindow(c, area, nextPlacement);
499 Q_ASSERT(area.isValid());
501 QRectF geom = c->frameGeometry();
503 c->move(geom.topLeft().toPoint());
510 Q_ASSERT(area.isValid());
518 auto mainwindows = c->mainWindows();
519 Window *place_on =
nullptr;
520 Window *place_on2 =
nullptr;
522 for (
auto it = mainwindows.constBegin(); it != mainwindows.constEnd(); ++it) {
523 if (mainwindows.count() > 1 && (*it)->isSpecialWindow()) {
528 if ((*it)->isOnCurrentDesktop()) {
529 if (place_on ==
nullptr) {
543 if (place_on ==
nullptr) {
545 if (mains_count != 1) {
549 place_on = place_on2;
551 if (place_on->isDesktop()) {
555 QRect geom = c->frameGeometry().toRect();
556 geom.moveCenter(place_on->frameGeometry().center().toPoint());
557 c->move(geom.topLeft());
560 c->keepInArea(placementArea);
565 Q_ASSERT(area.isValid());
570 if (c->isMaximizable() && c->maxSize().width() >= area.width() && c->maxSize().height() >= area.height()) {
578 c->moveResize(c->resizeWithChecks(c->moveResizeGeometry(), c->maxSize().boundedTo(area.size())));
579 place(c, area, nextPlacement);
593 bool noOverlap =
false;
602 if (isIrrelevant(other, window, desktop) || !other->frameGeometry().intersects(possibleGeo)) {
606 if (possibleGeo.contains(other->frameGeometry()) && !coveredArea.contains(other->frameGeometry())) {
611 possibleGeo.moveTopLeft(other->pos() + offset);
612 if (possibleGeo.right() > area.right() || possibleGeo.bottom() > area.bottom()) {
623 coveredArea |= other->frameGeometry();
624 if (coveredArea.contains(area)) {
630 window->
move(possibleGeo.topLeft());
638 for (
Window *window : stackingOrder) {
639 if (!window->isClient() || (!window->isOnCurrentDesktop()) || (window->isMinimized()) || (window->isOnAllDesktops()) || (!window->isMovable())) {
643 placeCascaded(window, placementArea);
650 for (
int i = windows.size() - 1; i >= 0; i--) {
651 auto window = windows.at(i);
652 if (!window->isClient()) {
655 if ((!window->isOnCurrentDesktop()) || (window->isMinimized()) || (window->isOnAllDesktops()) || (!window->isMovable())) {
667 const char *
const policies[] = {
668 "NoPlacement",
"Default",
"XXX should never see",
"Random",
"Smart",
"Centered",
669 "ZeroCornered",
"UnderMouse",
"OnMainWindow",
"Maximizing"};
670 Q_ASSERT(policy <
int(
sizeof(policies) /
sizeof(policies[0])));
671 return policies[policy];
685 move(QPoint(left, top));
699 if (m_activeWindow && m_activeWindow->
isMovable()) {
708 if (m_activeWindow && m_activeWindow->
isMovable()) {
717 if (m_activeWindow && m_activeWindow->
isMovable()) {
726 if (m_activeWindow && m_activeWindow->
isMovable()) {
736 if (m_activeWindow && m_activeWindow->
isMovable()) {
740 center.y() - (
geometry.height() / 2));
746 if (m_activeWindow) {
757 geom.setRight(
workspace()->packPositionRight(
this, geom.right(),
true));
768 geom.setRight(newright);
779 if (m_activeWindow) {
790 geom.setRight(
workspace()->packPositionLeft(
this, geom.right(),
false) + 1);
791 if (geom.width() <= 1) {
795 if (geom.width() > 20) {
803 if (m_activeWindow) {
814 geom.setBottom(
workspace()->packPositionDown(
this, geom.bottom(),
true));
824 geom.setBottom(newbottom);
834 if (m_activeWindow) {
845 geom.setBottom(
workspace()->packPositionUp(
this, geom.bottom(),
false) + 1);
846 if (geom.height() <= 1) {
850 if (geom.height() > 20) {
858 if (!m_activeWindow) {
864#define FLAG(name) QuickTileMode(QuickTileFlag::name)
865 if (!m_quickTileCombineTimer->isActive()) {
866 m_quickTileCombineTimer->start(1000);
867 m_lastTilingMode = mode;
874 mode |= m_lastTilingMode;
876 m_quickTileCombineTimer->stop();
895 for (
auto it = m_windows.constBegin(), end = m_windows.constEnd(); it != end; ++it) {
896 if (isIrrelevant(*it, window, desktop)) {
899 const qreal x = leftEdge ? (*it)->frameGeometry().right() : (*it)->frameGeometry().left() - 1;
900 if (x > newX && x < oldX
901 && !(window->
frameGeometry().top() > (*it)->frameGeometry().bottom() - 1
902 || window->
frameGeometry().bottom() - 1 < (*it)->frameGeometry().top())) {
922 for (
auto it = m_windows.constBegin(), end = m_windows.constEnd(); it != end; ++it) {
923 if (isIrrelevant(*it, window, desktop)) {
926 const qreal x = rightEdge ? (*it)->frameGeometry().left() : (*it)->frameGeometry().right() + 1;
928 if (x < newX && x > oldX
929 && !(window->
frameGeometry().top() > (*it)->frameGeometry().bottom() - 1
930 || window->
frameGeometry().bottom() - 1 < (*it)->frameGeometry().top())) {
950 for (
auto it = m_windows.constBegin(), end = m_windows.constEnd(); it != end; ++it) {
951 if (isIrrelevant(*it, window, desktop)) {
954 const qreal y = topEdge ? (*it)->frameGeometry().bottom() : (*it)->frameGeometry().top() - 1;
955 if (y > newY && y < oldY
956 && !(window->
frameGeometry().left() > (*it)->frameGeometry().right() - 1
957 || window->
frameGeometry().right() - 1 < (*it)->frameGeometry().left())) {
977 for (
auto it = m_windows.constBegin(), end = m_windows.constEnd(); it != end; ++it) {
978 if (isIrrelevant(*it, window, desktop)) {
981 const qreal y = bottomEdge ? (*it)->frameGeometry().top() : (*it)->frameGeometry().bottom() + 1;
982 if (y < newY && y > oldY
983 && !(window->
frameGeometry().left() > (*it)->frameGeometry().right() - 1
984 || window->
frameGeometry().right() - 1 < (*it)->frameGeometry().left())) {
PlacementPolicy placement
void placeCentered(Window *c, const QRectF &area, PlacementPolicy next=PlacementUnknown)
static const char * policyToString(PlacementPolicy policy)
void placeSmart(Window *c, const QRectF &area, PlacementPolicy next=PlacementUnknown)
void place(Window *c, const QRectF &area)
void cascadeIfCovering(Window *c, const QRectF &area)
virtual bool hasTransientPlacementHint() const
void moveResize(const QRectF &rect)
virtual bool isTransient() const
bool isNotification() const
SurfaceInterface * surface() const
bool isOnScreenDisplay() const
bool isCriticalNotification() const
void packTo(qreal left, qreal top)
virtual QSizeF resizeIncrements() const
void setQuickTileMode(QuickTileMode mode, bool keyboard=false)
bool isOnCurrentDesktop() const
virtual MaximizeMode requestedMaximizeMode() const
QList< KWin::VirtualDesktop * > desktops
virtual bool isMovable() const =0
@ SizeModeFixedW
Try not to affect width.
@ SizeModeFixedH
Try not to affect height.
Output * moveResizeOutput() const
QRectF moveResizeGeometry() const
const WindowRules * rules() const
QSizeF constrainFrameSize(const QSizeF &size, SizeMode mode=SizeModeAny) const
void checkWorkspacePosition(QRectF oldGeometry=QRectF(), const VirtualDesktop *oldDesktop=nullptr)
virtual bool isResizable() const =0
PlacementPolicy checkPlacement(PlacementPolicy placement) const
void quickTileWindow(QuickTileMode mode)
QRectF clientArea(clientAreaOption, const Output *output, const VirtualDesktop *desktop) const
const QList< Window * > & stackingOrder() const
void sendWindowToOutput(Window *window, Output *output)
qreal packPositionDown(const Window *window, qreal oldY, bool bottomEdge) const
void slotWindowShrinkHorizontal()
void slotWindowExpandHorizontal()
static Workspace * self()
void slotWindowMoveDown()
void updateFocusMousePosition(const QPointF &pos)
QPoint cascadeOffset(const Window *c) const
void slotWindowMoveRight()
void slotWindowShrinkVertical()
const QList< Window * > windows() const
qreal packPositionRight(const Window *window, qreal oldX, bool rightEdge) const
void slotWindowExpandVertical()
qreal packPositionUp(const Window *window, qreal oldY, bool topEdge) const
qreal packPositionLeft(const Window *window, qreal oldX, bool leftEdge) const
void slotWindowMoveLeft()
@ MaximizeRestore
The window is not maximized in any direction.
@ MaximizeFull
Equal to MaximizeVertical | MaximizeHorizontal.