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