13 #include "placement.h"
19 #include "workspace.h"
25 namespace KWinInternal
30 Placement::Placement(Workspace* w)
40 void Placement::place(Client* c, TQRect& area )
42 Policy policy = c->rules()->checkPlacement( Default );
43 if( policy != Default )
45 place( c, area, policy );
50 placeUtility(c, area, options->placement );
51 else if( c->isDialog())
52 placeDialog(c, area, options->placement );
53 else if( c->isSplash())
54 placeOnMainWindow( c, area );
56 place(c, area, options->placement);
59 void Placement::place(Client* c, TQRect& area, Policy policy, Policy nextPlacement )
61 if( policy == Unknown )
63 if( policy == Default )
64 policy = options->placement;
65 if( policy == NoPlacement )
67 else if (policy == Random)
68 placeAtRandom(c, area, nextPlacement);
69 else if (policy == Cascade)
70 placeCascaded(c, area, nextPlacement);
71 else if (policy == Centered)
72 placeCentered(c, area, nextPlacement);
73 else if (policy == ZeroCornered)
74 placeZeroCornered(c, area, nextPlacement);
75 else if (policy == UnderMouse)
76 placeUnderMouse(c, area, nextPlacement);
77 else if (policy == OnMainWindow)
78 placeOnMainWindow(c, area, nextPlacement);
79 else if( policy == Maximizing )
80 placeMaximizing(c, area, nextPlacement);
82 placeSmart(c, area, nextPlacement);
88 void Placement::placeAtRandom(Client* c,
const TQRect& area, Policy )
92 static int py = 2 * step;
95 const TQRect maxRect = checkArea( c, area );
105 if (px > maxRect.width()/2)
106 px = maxRect.x() + step;
107 if (py > maxRect.height()/2)
108 py = maxRect.y() + step;
111 if (tx + c->width() > maxRect.right())
113 tx = maxRect.right() - c->width();
118 if (ty + c->height() > maxRect.bottom())
120 ty = maxRect.bottom() - c->height();
131 void Placement::placeSmart(Client* c,
const TQRect& area, Policy )
142 const int none = 0, h_wrong = -1, w_wrong = -2;
143 long int overlap, min_overlap = 0;
144 int x_optimal, y_optimal;
146 int desktop = c->desktop() == 0 || c->isOnAllDesktops() ? m_WorkspacePtr->currentDesktop() : c->desktop();
148 int cxl, cxr, cyt, cyb;
153 const TQRect maxRect = checkArea( c, area );
154 int x = maxRect.left(), y = maxRect.top();
155 x_optimal = x; y_optimal = y;
158 int ch = c->height() - 1;
159 int cw = c->width() - 1;
161 bool first_pass =
true;
167 if (y + ch > maxRect.bottom() && ch < maxRect.height())
169 else if(x + cw > maxRect.right())
175 cxl = x; cxr = x + cw;
176 cyt = y; cyb = y + ch;
177 ClientList::ConstIterator l;
178 for(l = m_WorkspacePtr->stackingOrder().begin(); l != m_WorkspacePtr->stackingOrder().end() ; ++l)
180 if((*l)->isOnDesktop(desktop) &&
181 (*l)->isShown(
false ) && (*l) != c)
184 xl = (*l)->x(); yt = (*l)->y();
185 xr = xl + (*l)->width(); yb = yt + (*l)->height();
188 if((cxl < xr) && (cxr > xl) &&
189 (cyt < yb) && (cyb > yt))
191 xl = TQMAX(cxl, xl); xr = TQMIN(cxr, xr);
192 yt = TQMAX(cyt, yt); yb = TQMIN(cyb, yb);
193 if((*l)->keepAbove())
194 overlap += 16 * (xr - xl) * (yb - yt);
195 else if((*l)->keepBelow() && !(*l)->isDock())
198 overlap += (xr - xl) * (yb - yt);
215 min_overlap = overlap;
218 else if (overlap >= none && overlap < min_overlap)
220 min_overlap = overlap;
229 possible = maxRect.right();
230 if (possible - cw > x) possible -= cw;
233 ClientList::ConstIterator l;
234 for(l = m_WorkspacePtr->stackingOrder().begin(); l != m_WorkspacePtr->stackingOrder().end() ; ++l)
237 if ((*l)->isOnDesktop(desktop) &&
238 (*l)->isShown(
false ) && (*l) != c)
241 xl = (*l)->x(); yt = (*l)->y();
242 xr = xl + (*l)->width(); yb = yt + (*l)->height();
246 if((y < yb) && (yt < ch + y))
249 if((xr > x) && (possible > xr)) possible = xr;
252 if((basket > x) && (possible > basket)) possible = basket;
260 else if (overlap == w_wrong)
263 possible = maxRect.bottom();
265 if (possible - ch > y) possible -= ch;
268 ClientList::ConstIterator l;
269 for(l = m_WorkspacePtr->stackingOrder().begin(); l != m_WorkspacePtr->stackingOrder().end() ; ++l)
271 if((*l)->isOnDesktop(desktop) &&
272 (*l) != c && c->isShown(
false ))
275 xl = (*l)->x(); yt = (*l)->y();
276 xr = xl + (*l)->width(); yb = yt + (*l)->height();
280 if((yb > y) && (possible > yb)) possible = yb;
283 if((basket > y) && (possible > basket)) possible = basket;
289 while((overlap != none) && (overlap != h_wrong) && (y < maxRect.bottom()));
291 if(ch>= maxRect.height())
292 y_optimal=maxRect.top();
295 c->move(x_optimal, y_optimal);
299 void Placement::reinitCascading(
int desktop )
304 for(
int i = 0; i < m_WorkspacePtr->numberOfDesktops(); i++)
306 DesktopCascadingInfo inf;
307 inf.pos = TQPoint(-1,-1);
315 cci[desktop - 1].pos = TQPoint(-1, -1);
316 cci[desktop - 1].col = cci[desktop - 1].row = 0;
323 void Placement::placeCascaded (Client* c, TQRect& area, Policy nextPlacement)
331 const int delta_x = 24;
332 const int delta_y = 24;
334 const int dn = c->desktop() == 0 || c->isOnAllDesktops() ? (m_WorkspacePtr->currentDesktop() - 1) : (c->desktop() - 1);
337 TQRect maxRect = checkArea( c, area );
340 const int ch = c->height();
341 const int cw = c->width();
342 const int X = maxRect.left();
343 const int Y = maxRect.top();
344 const int H = maxRect.height();
345 const int W = maxRect.width();
347 if( nextPlacement == Unknown )
348 nextPlacement = Smart;
351 if (cci[dn].pos.x() < 0 || cci[dn].pos.x() < X || cci[dn].pos.y() < Y )
353 cci[dn].pos = TQPoint(X, Y);
354 cci[dn].col = cci[dn].row = 0;
358 xp = cci[dn].pos.x();
359 yp = cci[dn].pos.y();
362 if ((yp + ch) > H) yp = Y;
368 place(c,area,nextPlacement);
378 if (cci[dn].pos.x() != X && cci[dn].pos.y() != Y)
387 if (xp != X && yp == Y)
390 xp = delta_x * cci[dn].col;
392 if (yp != Y && xp == X)
395 yp = delta_y * cci[dn].row;
399 if (((xp + cw) > W - X) || ((yp + ch) > H - Y))
401 place(c,area,nextPlacement);
407 c->move(TQPoint(xp, yp));
410 cci[dn].pos = TQPoint(xp + delta_x, yp + delta_y);
416 void Placement::placeCentered (Client* c,
const TQRect& area, Policy )
420 const TQRect maxRect = checkArea( c, area );
422 const int xp = maxRect.left() + (maxRect.width() - c->width()) / 2;
423 const int yp = maxRect.top() + (maxRect.height() - c->height()) / 2;
426 c->move(TQPoint(xp, yp));
432 void Placement::placeZeroCornered(Client* c,
const TQRect& area, Policy )
435 const TQRect maxRect = checkArea( c, area );
438 c->move(TQPoint(maxRect.left(), maxRect.top()));
441 void Placement::placeUtility(Client* c, TQRect& area, Policy )
448 place( c, area, Default );
452 void Placement::placeDialog(Client* c, TQRect& area, Policy nextPlacement )
454 placeOnMainWindow( c, area, nextPlacement );
457 void Placement::placeUnderMouse(Client* c, TQRect& area, Policy )
459 area = checkArea( c, area );
460 TQRect geom = c->geometry();
461 geom.moveCenter( TQCursor::pos());
462 c->move( geom.topLeft());
463 c->keepInArea( area );
466 void Placement::placeOnMainWindow(Client* c, TQRect& area, Policy nextPlacement )
468 if( nextPlacement == Unknown )
469 nextPlacement = Centered;
470 if( nextPlacement == Maximizing )
471 placeMaximizing( c, area, NoPlacement );
472 area = checkArea( c, area );
473 ClientList mainwindows = c->mainClients();
474 Client* place_on = NULL;
475 Client* place_on2 = NULL;
477 for( ClientList::ConstIterator it = mainwindows.begin();
478 it != mainwindows.end();
481 if( mainwindows.count() > 1 && (*it)->isSpecialWindow())
485 if( (*it)->isOnCurrentDesktop())
487 if( place_on == NULL )
496 place( c, area, Centered );
501 if( place_on == NULL )
503 if( mains_count != 1 )
505 place( c, area, Centered );
508 place_on = place_on2;
510 if( place_on->isDesktop())
512 place( c, area, Centered );
515 TQRect geom = c->geometry();
516 geom.moveCenter( place_on->geometry().center());
517 c->move( geom.topLeft());
519 area = checkArea( c, TQRect());
520 c->keepInArea( area );
523 void Placement::placeMaximizing(Client* c, TQRect& area, Policy nextPlacement )
525 if( nextPlacement == Unknown )
526 nextPlacement = Smart;
527 if( c->isMaximizable() && c->maxSize().width() >= area.width() && c->maxSize().height() >= area.height())
529 if( m_WorkspacePtr->clientArea( MaximizeArea, c ) == area )
530 c->maximize( Client::MaximizeFull );
533 c->setGeometry( area );
538 c->resizeWithChecks( c->maxSize().boundedTo( area.size()));
539 place( c, area, nextPlacement );
543 TQRect Placement::checkArea(
const Client* c,
const TQRect& area )
546 return m_WorkspacePtr->clientArea( PlacementArea, c->geometry().center(), c->desktop());
553 Placement::Policy Placement::policyFromString(
const TQString& policy,
bool no_special )
555 if( policy ==
"NoPlacement" )
557 else if( policy ==
"Default" && !no_special )
559 else if( policy ==
"Random" )
561 else if( policy ==
"Cascade" )
563 else if( policy ==
"Centered" )
565 else if( policy ==
"ZeroCornered" )
567 else if( policy ==
"UnderMouse" && !no_special)
569 else if( policy ==
"OnMainWindow" && !no_special)
571 else if( policy ==
"Maximizing" )
577 const char* Placement::policyToString( Policy policy )
579 const char*
const policies[] =
580 {
"NoPlacement",
"Default",
"XXX should never see",
"Random",
"Smart",
"Cascade",
"Centered",
581 "ZeroCornered",
"UnderMouse",
"OnMainWindow",
"Maximizing" };
582 assert( policy <
int(
sizeof( policies ) /
sizeof( policies[ 0 ] )));
583 return policies[ policy ];
596 void Workspace::slotWindowPackLeft()
598 if( active_client && active_client->isMovable())
599 active_client->move( packPositionLeft( active_client, active_client->geometry().left(),
true ),
603 void Workspace::slotWindowPackRight()
605 if( active_client && active_client->isMovable())
607 packPositionRight( active_client, active_client->geometry().right(),
true )
608 - active_client->width() + 1, active_client->y());
611 void Workspace::slotWindowPackUp()
613 if( active_client && active_client->isMovable())
614 active_client->move( active_client->x(),
615 packPositionUp( active_client, active_client->geometry().top(),
true ));
618 void Workspace::slotWindowPackDown()
620 if( active_client && active_client->isMovable())
621 active_client->move( active_client->x(),
622 packPositionDown( active_client, active_client->geometry().bottom(),
true ) - active_client->height() + 1 );
625 void Workspace::slotWindowGrowHorizontal()
628 active_client->growHorizontal();
631 void Client::growHorizontal()
635 TQRect geom = geometry();
636 geom.setRight( workspace()->packPositionRight(
this, geom.right(),
true ));
637 TQSize adjsize =
adjustedSize( geom.size(), SizemodeFixedW );
638 if( geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.width_inc > 1 )
640 int newright = workspace()->packPositionRight(
this, geom.right() + xSizeHint.width_inc - 1,
true );
643 if( workspace()->clientArea( MovementArea,
644 TQPoint(( x() + newright ) / 2, geometry().center().y()),
desktop()).right() >= newright )
645 geom.setRight( newright );
647 geom.setSize(
adjustedSize( geom.size(), SizemodeFixedW ));
651 void Workspace::slotWindowShrinkHorizontal()
654 active_client->shrinkHorizontal();
657 void Client::shrinkHorizontal()
661 TQRect geom = geometry();
662 geom.setRight( workspace()->packPositionLeft(
this, geom.right(),
false ));
663 if( geom.width() <= 1 )
665 geom.setSize(
adjustedSize( geom.size(), SizemodeFixedW ));
666 if( geom.width() > 20 )
670 void Workspace::slotWindowGrowVertical()
673 active_client->growVertical();
676 void Client::growVertical()
680 TQRect geom = geometry();
681 geom.setBottom( workspace()->packPositionDown(
this, geom.bottom(),
true ));
682 TQSize adjsize =
adjustedSize( geom.size(), SizemodeFixedH );
683 if( geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.height_inc > 1 )
685 int newbottom = workspace()->packPositionDown(
this, geom.bottom() + xSizeHint.height_inc - 1,
true );
687 if( workspace()->clientArea( MovementArea,
688 TQPoint( geometry().center().x(), ( y() + newbottom ) / 2 ),
desktop()).bottom() >= newbottom )
689 geom.setBottom( newbottom );
691 geom.setSize(
adjustedSize( geom.size(), SizemodeFixedH ));
696 void Workspace::slotWindowShrinkVertical()
699 active_client->shrinkVertical();
702 void Client::shrinkVertical()
706 TQRect geom = geometry();
707 geom.setBottom( workspace()->packPositionUp(
this, geom.bottom(),
false ));
708 if( geom.height() <= 1 )
710 geom.setSize(
adjustedSize( geom.size(), SizemodeFixedH ));
711 if( geom.height() > 20 )
715 int Workspace::packPositionLeft(
const Client* cl,
int oldx,
bool left_edge )
const
717 int newx = clientArea( MovementArea, cl ).left();
719 newx = clientArea( MovementArea,
720 TQPoint( cl->geometry().left() - 1, cl->geometry().center().y()), cl->desktop()).left();
723 for( ClientList::ConstIterator it = clients.begin();
727 if( !(*it)->isShown(
false ) || !(*it)->isOnDesktop( active_client->desktop()))
729 int x = left_edge ? (*it)->geometry().right() + 1 : (*it)->geometry().left() - 1;
730 if( x > newx && x < oldx
731 && !( cl->geometry().top() > (*it)->geometry().bottom()
732 || cl->geometry().bottom() < (*it)->geometry().top()))
738 int Workspace::packPositionRight(
const Client* cl,
int oldx,
bool right_edge )
const
740 int newx = clientArea( MovementArea, cl ).right();
742 newx = clientArea( MovementArea,
743 TQPoint( cl->geometry().right() + 1, cl->geometry().center().y()), cl->desktop()).right();
746 for( ClientList::ConstIterator it = clients.begin();
750 if( !(*it)->isShown(
false ) || !(*it)->isOnDesktop( cl->desktop()))
752 int x = right_edge ? (*it)->geometry().left() - 1 : (*it)->geometry().right() + 1;
753 if( x < newx && x > oldx
754 && !( cl->geometry().top() > (*it)->geometry().bottom()
755 || cl->geometry().bottom() < (*it)->geometry().top()))
761 int Workspace::packPositionUp(
const Client* cl,
int oldy,
bool top_edge )
const
763 int newy = clientArea( MovementArea, cl ).top();
765 newy = clientArea( MovementArea,
766 TQPoint( cl->geometry().center().x(), cl->geometry().top() - 1 ), cl->desktop()).top();
769 for( ClientList::ConstIterator it = clients.begin();
773 if( !(*it)->isShown(
false ) || !(*it)->isOnDesktop( cl->desktop()))
775 int y = top_edge ? (*it)->geometry().bottom() + 1 : (*it)->geometry().top() - 1;
776 if( y > newy && y < oldy
777 && !( cl->geometry().left() > (*it)->geometry().right()
778 || cl->geometry().right() < (*it)->geometry().left()))
784 int Workspace::packPositionDown(
const Client* cl,
int oldy,
bool bottom_edge )
const
786 int newy = clientArea( MovementArea, cl ).bottom();
788 newy = clientArea( MovementArea,
789 TQPoint( cl->geometry().center().x(), cl->geometry().bottom() + 1 ), cl->desktop()).bottom();
792 for( ClientList::ConstIterator it = clients.begin();
796 if( !(*it)->isShown(
false ) || !(*it)->isOnDesktop( cl->desktop()))
798 int y = bottom_edge ? (*it)->geometry().top() - 1 : (*it)->geometry().bottom() + 1;
799 if( y < newy && y > oldy
800 && !( cl->geometry().left() > (*it)->geometry().right()
801 || cl->geometry().right() < (*it)->geometry().left()))
810 void Workspace::place(Client* c, TQRect& area)
812 initPositioning->place( c, area );
815 void Workspace::placeSmart(Client* c,
const TQRect& area)
817 initPositioning->placeSmart( c, area );
void setGeometry(int x, int y, int w, int h, ForceGeometry_t force=NormalGeometrySet)
TQSize adjustedSize(const TQSize &, Sizemode mode=SizemodeAny) const