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 }