00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "workspace.h"
00014 #include "client.h"
00015 #include "options.h"
00016 #include "placement.h"
00017
00018 #include <qrect.h>
00019
00020
00021 namespace KWinInternal
00022 {
00023
00024 Placement::Placement(Workspace* w)
00025 {
00026 m_WorkspacePtr = w;
00027
00028
00029 for( int i = 0; i < m_WorkspacePtr->numberOfDesktops(); i++)
00030 {
00031 DesktopCascadingInfo inf;
00032 inf.pos = QPoint(0,0);
00033 inf.col = 0;
00034 inf.row = 0;
00035 cci.append(inf);
00036 }
00037
00038 }
00039
00043 void Placement::place(Client* c, QRect& area )
00044 {
00045 if( c->isUtility())
00046 placeUtility(c, area);
00047 else if( c->isDialog())
00048 placeDialog(c, area);
00049 else if( c->isSplash())
00050 placeOnMainWindow( c, area );
00051 else
00052 placeInternal(c, area);
00053 }
00054
00055 void Placement::placeInternal(Client* c, const QRect& area )
00056 {
00057 if (options->placement == Options::Random) placeAtRandom(c, area);
00058 else if (options->placement == Options::Cascade) placeCascaded(c, area);
00059 else if (options->placement == Options::Centered) placeCentered(c, area);
00060 else if (options->placement == Options::ZeroCornered) placeZeroCornered(c, area);
00061 else placeSmart(c, area);
00062 }
00063
00067 void Placement::placeAtRandom(Client* c, const QRect& area )
00068 {
00069 const int step = 24;
00070 static int px = step;
00071 static int py = 2 * step;
00072 int tx,ty;
00073
00074 const QRect maxRect = checkArea( c, area );
00075
00076 if (px < maxRect.x())
00077 px = maxRect.x();
00078 if (py < maxRect.y())
00079 py = maxRect.y();
00080
00081 px += step;
00082 py += 2*step;
00083
00084 if (px > maxRect.width()/2)
00085 px = maxRect.x() + step;
00086 if (py > maxRect.height()/2)
00087 py = maxRect.y() + step;
00088 tx = px;
00089 ty = py;
00090 if (tx + c->width() > maxRect.right())
00091 {
00092 tx = maxRect.right() - c->width();
00093 if (tx < 0)
00094 tx = 0;
00095 px = maxRect.x();
00096 }
00097 if (ty + c->height() > maxRect.bottom())
00098 {
00099 ty = maxRect.bottom() - c->height();
00100 if (ty < 0)
00101 ty = 0;
00102 py = maxRect.y();
00103 }
00104 c->move(tx, ty);
00105 }
00106
00110 void Placement::placeSmart(Client* c, const QRect& area )
00111 {
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 const int none = 0, h_wrong = -1, w_wrong = -2;
00122 long int overlap, min_overlap = 0;
00123 int x_optimal, y_optimal;
00124 int possible;
00125 int desktop = c->desktop() == 0 || c->isOnAllDesktops() ? m_WorkspacePtr->currentDesktop() : c->desktop();
00126
00127 int cxl, cxr, cyt, cyb;
00128 int xl, xr, yt, yb;
00129 int basket;
00130
00131
00132 const QRect maxRect = checkArea( c, area );
00133 int x = maxRect.left(), y = maxRect.top();
00134 x_optimal = x; y_optimal = y;
00135
00136
00137 int ch = c->height() - 1;
00138 int cw = c->width() - 1;
00139
00140 bool first_pass = true;
00141
00142
00143 do
00144 {
00145
00146 if (y + ch > maxRect.bottom() && ch < maxRect.height())
00147 overlap = h_wrong;
00148 else if(x + cw > maxRect.right())
00149 overlap = w_wrong;
00150 else
00151 {
00152 overlap = none;
00153
00154 cxl = x; cxr = x + cw;
00155 cyt = y; cyb = y + ch;
00156 ClientList::ConstIterator l;
00157 for(l = m_WorkspacePtr->stackingOrder().begin(); l != m_WorkspacePtr->stackingOrder().end() ; ++l)
00158 {
00159 if((*l)->isOnDesktop(desktop) &&
00160 (*l)->isShown( false ) && (*l) != c)
00161 {
00162
00163 xl = (*l)->x(); yt = (*l)->y();
00164 xr = xl + (*l)->width(); yb = yt + (*l)->height();
00165
00166
00167 if((cxl < xr) && (cxr > xl) &&
00168 (cyt < yb) && (cyb > yt))
00169 {
00170 xl = QMAX(cxl, xl); xr = QMIN(cxr, xr);
00171 yt = QMAX(cyt, yt); yb = QMIN(cyb, yb);
00172 if((*l)->keepAbove())
00173 overlap += 16 * (xr - xl) * (yb - yt);
00174 else if((*l)->keepBelow() && !(*l)->isDock())
00175 overlap += 0;
00176 else
00177 overlap += (xr - xl) * (yb - yt);
00178 }
00179 }
00180 }
00181 }
00182
00183
00184 if (overlap == none)
00185 {
00186 x_optimal = x;
00187 y_optimal = y;
00188 break;
00189 }
00190
00191 if (first_pass)
00192 {
00193 first_pass = false;
00194 min_overlap = overlap;
00195 }
00196
00197 else if (overlap >= none && overlap < min_overlap)
00198 {
00199 min_overlap = overlap;
00200 x_optimal = x;
00201 y_optimal = y;
00202 }
00203
00204
00205 if (overlap > none)
00206 {
00207
00208 possible = maxRect.right();
00209 if (possible - cw > x) possible -= cw;
00210
00211
00212 ClientList::ConstIterator l;
00213 for(l = m_WorkspacePtr->stackingOrder().begin(); l != m_WorkspacePtr->stackingOrder().end() ; ++l)
00214 {
00215
00216 if ((*l)->isOnDesktop(desktop) &&
00217 (*l)->isShown( false ) && (*l) != c)
00218 {
00219
00220 xl = (*l)->x(); yt = (*l)->y();
00221 xr = xl + (*l)->width(); yb = yt + (*l)->height();
00222
00223
00224
00225 if((y < yb) && (yt < ch + y))
00226 {
00227
00228 if((xr > x) && (possible > xr)) possible = xr;
00229
00230 basket = xl - cw;
00231 if((basket > x) && (possible > basket)) possible = basket;
00232 }
00233 }
00234 }
00235 x = possible;
00236 }
00237
00238
00239 else if (overlap == w_wrong)
00240 {
00241 x = maxRect.left();
00242 possible = maxRect.bottom();
00243
00244 if (possible - ch > y) possible -= ch;
00245
00246
00247 ClientList::ConstIterator l;
00248 for(l = m_WorkspacePtr->stackingOrder().begin(); l != m_WorkspacePtr->stackingOrder().end() ; ++l)
00249 {
00250 if((*l)->isOnDesktop(desktop) &&
00251 (*l) != c && c->isShown( false ))
00252 {
00253
00254 xl = (*l)->x(); yt = (*l)->y();
00255 xr = xl + (*l)->width(); yb = yt + (*l)->height();
00256
00257
00258
00259 if((yb > y) && (possible > yb)) possible = yb;
00260
00261 basket = yt - ch;
00262 if((basket > y) && (possible > basket)) possible = basket;
00263 }
00264 }
00265 y = possible;
00266 }
00267 }
00268 while((overlap != none) && (overlap != h_wrong) && (y < maxRect.bottom()));
00269
00270 if(ch>= maxRect.height())
00271 y_optimal=maxRect.top();
00272
00273
00274 c->move(x_optimal, y_optimal);
00275
00276 }
00277
00281 void Placement::placeCascaded (Client* c, const QRect& area, bool re_init)
00282 {
00283
00284
00285
00286 int xp, yp;
00287
00288
00289 const int delta_x = 24;
00290 const int delta_y = 24;
00291
00292 const int dn = c->desktop() == 0 || c->isOnAllDesktops() ? (m_WorkspacePtr->currentDesktop() - 1) : (c->desktop() - 1);
00293
00294
00295 QRect maxRect = checkArea( c, area );
00296
00297
00298 const int ch = c->height();
00299 const int cw = c->width();
00300 const int X = maxRect.left();
00301 const int Y = maxRect.top();
00302 const int H = maxRect.height();
00303 const int W = maxRect.width();
00304
00305
00306 if (re_init || cci[dn].pos.x() < X || cci[dn].pos.y() < Y )
00307 {
00308 cci[dn].pos = QPoint(X, Y);
00309 cci[dn].col = cci[dn].row = 0;
00310 }
00311
00312
00313 xp = cci[dn].pos.x();
00314 yp = cci[dn].pos.y();
00315
00316
00317 if ((yp + ch) > H) yp = Y;
00318
00319 if ((xp + cw) > W)
00320 if (!yp)
00321 {
00322 placeSmart(c,area);
00323 return;
00324 }
00325 else xp = X;
00326
00327
00328 if (cci[dn].pos.x() != X && cci[dn].pos.y() != Y)
00329 {
00330
00331
00332
00333
00334
00335
00336
00337 if (xp != X && yp == Y)
00338 {
00339 ++(cci[dn].col);
00340 xp = delta_x * cci[dn].col;
00341 }
00342 if (yp != Y && xp == X)
00343 {
00344 ++(cci[dn].row);
00345 yp = delta_y * cci[dn].row;
00346 }
00347
00348
00349 if (((xp + cw) > W - X) || ((yp + ch) > H - Y))
00350 {
00351 placeSmart(c,area);
00352 return;
00353 }
00354 }
00355
00356
00357 c->move(QPoint(xp, yp));
00358
00359
00360 cci[dn].pos = QPoint(xp + delta_x, yp + delta_y);
00361 }
00362
00366 void Placement::placeCentered (Client* c, const QRect& area )
00367 {
00368
00369
00370 const QRect maxRect = checkArea( c, area );
00371
00372 const int xp = maxRect.left() + (maxRect.width() - c->width()) / 2;
00373 const int yp = maxRect.top() + (maxRect.height() - c->height()) / 2;
00374
00375
00376 c->move(QPoint(xp, yp));
00377 }
00378
00382 void Placement::placeZeroCornered(Client* c, const QRect& area )
00383 {
00384
00385 const QRect maxRect = checkArea( c, area );
00386
00387
00388 c->move(QPoint(maxRect.left(), maxRect.top()));
00389 }
00390
00391 void Placement::placeUtility(Client* c, QRect& area )
00392 {
00393
00394
00395
00396
00397
00398 placeInternal( c, area );
00399 }
00400
00401
00402 void Placement::placeDialog(Client* c, QRect& area )
00403 {
00404
00405
00406 if( !c->hasNETSupport())
00407 return;
00408 placeOnMainWindow( c, area );
00409 }
00410
00411 void Placement::placeUnderMouse(Client* c, QRect& area )
00412 {
00413 area = checkArea( c, area );
00414 QRect geom = c->geometry();
00415 geom.moveCenter( QCursor::pos());
00416 c->move( geom.topLeft());
00417 c->keepInArea( area );
00418 }
00419
00420 void Placement::placeOnMainWindow(Client* c, QRect& area )
00421 {
00422 area = checkArea( c, area );
00423 ClientList mainwindows = c->mainClients();
00424 Client* place_on = NULL;
00425 Client* place_on2 = NULL;
00426 int mains_count = 0;
00427 for( ClientList::ConstIterator it = mainwindows.begin();
00428 it != mainwindows.end();
00429 ++it )
00430 {
00431 if( (*it)->isSpecialWindow() && !(*it)->isOverride())
00432 continue;
00433 ++mains_count;
00434 place_on2 = *it;
00435 if( (*it)->isOnCurrentDesktop())
00436 {
00437 if( place_on == NULL )
00438 place_on = *it;
00439 else
00440 {
00441 placeCentered( c, area );
00442 return;
00443 }
00444 }
00445 }
00446 if( place_on == NULL )
00447 {
00448 if( mains_count != 1 )
00449 {
00450 placeCentered( c, area );
00451 return;
00452 }
00453 place_on = place_on2;
00454 }
00455 QRect geom = c->geometry();
00456 geom.moveCenter( place_on->geometry().center());
00457 c->move( geom.topLeft());
00458
00459 area = checkArea( c, QRect());
00460 c->keepInArea( area );
00461 }
00462
00463 QRect Placement::checkArea( const Client* c, const QRect& area )
00464 {
00465 if( area.isNull())
00466 return m_WorkspacePtr->clientArea( PlacementArea, c->geometry().center(), c->desktop());
00467 return area;
00468 }
00469
00470
00471
00472
00473
00477 void Workspace::slotWindowPackLeft()
00478 {
00479 if( active_client )
00480 active_client->move( packPositionLeft( active_client, active_client->geometry().left(), true ),
00481 active_client->y());
00482 }
00483
00484 void Workspace::slotWindowPackRight()
00485 {
00486 if( active_client )
00487 active_client->move(
00488 packPositionRight( active_client, active_client->geometry().right(), true )
00489 - active_client->width() + 1, active_client->y());
00490 }
00491
00492 void Workspace::slotWindowPackUp()
00493 {
00494 if( active_client )
00495 active_client->move( active_client->x(),
00496 packPositionUp( active_client, active_client->geometry().top(), true ));
00497 }
00498
00499 void Workspace::slotWindowPackDown()
00500 {
00501 if( active_client )
00502 active_client->move( active_client->x(),
00503 packPositionDown( active_client, active_client->geometry().bottom(), true ) - active_client->height() + 1 );
00504 }
00505
00506 void Workspace::slotWindowGrowHorizontal()
00507 {
00508 if( active_client )
00509 active_client->growHorizontal();
00510 }
00511
00512 void Client::growHorizontal()
00513 {
00514 QRect geom = geometry();
00515 geom.setRight( workspace()->packPositionRight( this, geom.right(), true ));
00516 QSize adjsize = adjustedSize( geom.size(), SizemodeFixedW );
00517 if( geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.width_inc > 1 )
00518 {
00519 int newright = workspace()->packPositionRight( this, geom.right() + xSizeHint.width_inc - 1, true );
00520
00521
00522 if( workspace()->clientArea( MovementArea,
00523 QPoint(( x() + newright ) / 2, geometry().center().y()), desktop()).right() >= newright )
00524 geom.setRight( newright );
00525 }
00526 geom.setSize( adjustedSize( geom.size(), SizemodeFixedW ));
00527 setGeometry( geom );
00528 }
00529
00530 void Workspace::slotWindowShrinkHorizontal()
00531 {
00532 if( active_client )
00533 active_client->shrinkHorizontal();
00534 }
00535
00536 void Client::shrinkHorizontal()
00537 {
00538 QRect geom = geometry();
00539 geom.setRight( workspace()->packPositionLeft( this, geom.right(), false ));
00540 if( geom.width() <= 1 )
00541 return;
00542 geom.setSize( adjustedSize( geom.size(), SizemodeFixedW ));
00543 if( geom.width() > 20 )
00544 setGeometry( geom );
00545 }
00546
00547 void Workspace::slotWindowGrowVertical()
00548 {
00549 if( active_client )
00550 active_client->growVertical();
00551 }
00552
00553 void Client::growVertical()
00554 {
00555 QRect geom = geometry();
00556 geom.setBottom( workspace()->packPositionDown( this, geom.bottom(), true ));
00557 QSize adjsize = adjustedSize( geom.size(), SizemodeFixedH );
00558 if( geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.height_inc > 1 )
00559 {
00560 int newbottom = workspace()->packPositionDown( this, geom.bottom() + xSizeHint.height_inc - 1, true );
00561
00562 if( workspace()->clientArea( MovementArea,
00563 QPoint( geometry().center().x(), ( y() + newbottom ) / 2 ), desktop()).bottom() >= newbottom )
00564 geom.setBottom( newbottom );
00565 }
00566 geom.setSize( adjustedSize( geom.size(), SizemodeFixedH ));
00567 setGeometry( geom );
00568 }
00569
00570
00571 void Workspace::slotWindowShrinkVertical()
00572 {
00573 if( active_client )
00574 active_client->shrinkVertical();
00575 }
00576
00577 void Client::shrinkVertical()
00578 {
00579 QRect geom = geometry();
00580 geom.setBottom( workspace()->packPositionUp( this, geom.bottom(), false ));
00581 if( geom.height() <= 1 )
00582 return;
00583 geom.setSize( adjustedSize( geom.size(), SizemodeFixedH ));
00584 if( geom.height() > 20 )
00585 setGeometry( geom );
00586 }
00587
00588 int Workspace::packPositionLeft( const Client* cl, int oldx, bool left_edge ) const
00589 {
00590 int newx = clientArea( MovementArea, cl ).left();
00591 if( oldx <= newx )
00592 newx = clientArea( MovementArea,
00593 QPoint( cl->geometry().left() - 1, cl->geometry().center().y()), cl->desktop()).left();
00594 if( oldx <= newx )
00595 return oldx;
00596 for( ClientList::ConstIterator it = clients.begin();
00597 it != clients.end();
00598 ++it)
00599 {
00600 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( active_client->desktop()))
00601 continue;
00602 int x = left_edge ? (*it)->geometry().right() + 1 : (*it)->geometry().left() - 1;
00603 if( x > newx && x < oldx
00604 && !( cl->geometry().top() > (*it)->geometry().bottom()
00605 || cl->geometry().bottom() < (*it)->geometry().top()))
00606 newx = x;
00607 }
00608 return newx;
00609 }
00610
00611 int Workspace::packPositionRight( const Client* cl, int oldx, bool right_edge ) const
00612 {
00613 int newx = clientArea( MovementArea, cl ).right();
00614 if( oldx >= newx )
00615 newx = clientArea( MovementArea,
00616 QPoint( cl->geometry().right() + 1, cl->geometry().center().y()), cl->desktop()).right();
00617 if( oldx >= newx )
00618 return oldx;
00619 for( ClientList::ConstIterator it = clients.begin();
00620 it != clients.end();
00621 ++it)
00622 {
00623 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( cl->desktop()))
00624 continue;
00625 int x = right_edge ? (*it)->geometry().left() - 1 : (*it)->geometry().right() + 1;
00626 if( x < newx && x > oldx
00627 && !( cl->geometry().top() > (*it)->geometry().bottom()
00628 || cl->geometry().bottom() < (*it)->geometry().top()))
00629 newx = x;
00630 }
00631 return newx;
00632 }
00633
00634 int Workspace::packPositionUp( const Client* cl, int oldy, bool top_edge ) const
00635 {
00636 int newy = clientArea( MovementArea, cl ).top();
00637 if( oldy <= newy )
00638 newy = clientArea( MovementArea,
00639 QPoint( cl->geometry().center().x(), cl->geometry().top() - 1 ), cl->desktop()).top();
00640 if( oldy <= newy )
00641 return oldy;
00642 for( ClientList::ConstIterator it = clients.begin();
00643 it != clients.end();
00644 ++it)
00645 {
00646 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( cl->desktop()))
00647 continue;
00648 int y = top_edge ? (*it)->geometry().bottom() + 1 : (*it)->geometry().top() - 1;
00649 if( y > newy && y < oldy
00650 && !( cl->geometry().left() > (*it)->geometry().right()
00651 || cl->geometry().right() < (*it)->geometry().left()))
00652 newy = y;
00653 }
00654 return newy;
00655 }
00656
00657 int Workspace::packPositionDown( const Client* cl, int oldy, bool bottom_edge ) const
00658 {
00659 int newy = clientArea( MovementArea, cl ).bottom();
00660 if( oldy >= newy )
00661 newy = clientArea( MovementArea,
00662 QPoint( cl->geometry().center().x(), cl->geometry().bottom() + 1 ), cl->desktop()).bottom();
00663 if( oldy >= newy )
00664 return oldy;
00665 for( ClientList::ConstIterator it = clients.begin();
00666 it != clients.end();
00667 ++it)
00668 {
00669 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( cl->desktop()))
00670 continue;
00671 int y = bottom_edge ? (*it)->geometry().top() - 1 : (*it)->geometry().bottom() + 1;
00672 if( y < newy && y > oldy
00673 && !( cl->geometry().left() > (*it)->geometry().right()
00674 || cl->geometry().right() < (*it)->geometry().left()))
00675 newy = y;
00676 }
00677 return newy;
00678 }
00679
00683 void Workspace::place(Client* c, QRect& area)
00684 {
00685 initPositioning->place( c, area );
00686 }
00687
00688 void Workspace::placeSmart(Client* c, const QRect& area)
00689 {
00690 initPositioning->placeSmart( c, area );
00691 }
00692
00693 }