placement.cpp
00001 /***************************************************************** 00002 KWin - the KDE window manager 00003 This file is part of the KDE project. 00004 00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org> 00006 Copyright (C) 1997 to 2002 Cristian Tibirna <tibirna@kde.org> 00007 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> 00008 00009 You can Freely distribute this program under the GNU General Public 00010 License. See the file "COPYING" for the exact licensing terms. 00011 ******************************************************************/ 00012 00013 #include "placement.h" 00014 00015 #include <tqrect.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 reinitCascading( 0 ); 00035 } 00036 00040 void Placement::place(Client* c, TQRect& area ) 00041 { 00042 Policy policy = c->rules()->checkPlacement( Default ); 00043 if( policy != Default ) 00044 { 00045 place( c, area, policy ); 00046 return; 00047 } 00048 00049 if( c->isUtility()) 00050 placeUtility(c, area, options->placement ); 00051 else if( c->isDialog()) 00052 placeDialog(c, area, options->placement ); 00053 else if( c->isSplash()) 00054 placeOnMainWindow( c, area ); // on mainwindow, if any, otherwise centered 00055 else 00056 place(c, area, options->placement); 00057 } 00058 00059 void Placement::place(Client* c, TQRect& area, Policy policy, Policy nextPlacement ) 00060 { 00061 if( policy == Unknown ) 00062 policy = Default; 00063 if( policy == Default ) 00064 policy = options->placement; 00065 if( policy == NoPlacement ) 00066 return; 00067 else if (policy == Random) 00068 placeAtRandom(c, area, nextPlacement); 00069 else if (policy == Cascade) 00070 placeCascaded(c, area, nextPlacement); 00071 else if (policy == Centered) 00072 placeCentered(c, area, nextPlacement); 00073 else if (policy == ZeroCornered) 00074 placeZeroCornered(c, area, nextPlacement); 00075 else if (policy == UnderMouse) 00076 placeUnderMouse(c, area, nextPlacement); 00077 else if (policy == OnMainWindow) 00078 placeOnMainWindow(c, area, nextPlacement); 00079 else if( policy == Maximizing ) 00080 placeMaximizing(c, area, nextPlacement); 00081 else 00082 placeSmart(c, area, nextPlacement); 00083 } 00084 00088 void Placement::placeAtRandom(Client* c, const TQRect& area, Policy /*next*/ ) 00089 { 00090 const int step = 24; 00091 static int px = step; 00092 static int py = 2 * step; 00093 int tx,ty; 00094 00095 const TQRect maxRect = checkArea( c, area ); 00096 00097 if (px < maxRect.x()) 00098 px = maxRect.x(); 00099 if (py < maxRect.y()) 00100 py = maxRect.y(); 00101 00102 px += step; 00103 py += 2*step; 00104 00105 if (px > maxRect.width()/2) 00106 px = maxRect.x() + step; 00107 if (py > maxRect.height()/2) 00108 py = maxRect.y() + step; 00109 tx = px; 00110 ty = py; 00111 if (tx + c->width() > maxRect.right()) 00112 { 00113 tx = maxRect.right() - c->width(); 00114 if (tx < 0) 00115 tx = 0; 00116 px = maxRect.x(); 00117 } 00118 if (ty + c->height() > maxRect.bottom()) 00119 { 00120 ty = maxRect.bottom() - c->height(); 00121 if (ty < 0) 00122 ty = 0; 00123 py = maxRect.y(); 00124 } 00125 c->move(tx, ty); 00126 } 00127 00131 void Placement::placeSmart(Client* c, const TQRect& area, Policy /*next*/ ) 00132 { 00133 /* 00134 * SmartPlacement by Cristian Tibirna (tibirna@kde.org) 00135 * adapted for kwm (16-19jan98) and for kwin (16Nov1999) using (with 00136 * permission) ideas from fvwm, authored by 00137 * Anthony Martin (amartin@engr.csulb.edu). 00138 * Xinerama supported added by Balaji Ramani (balaji@yablibli.com) 00139 * with ideas from xfce. 00140 */ 00141 00142 const int none = 0, h_wrong = -1, w_wrong = -2; // overlap types 00143 long int overlap, min_overlap = 0; 00144 int x_optimal, y_optimal; 00145 int possible; 00146 int desktop = c->desktop() == 0 || c->isOnAllDesktops() ? m_WorkspacePtr->currentDesktop() : c->desktop(); 00147 00148 int cxl, cxr, cyt, cyb; //temp coords 00149 int xl, xr, yt, yb; //temp coords 00150 int basket; //temp holder 00151 00152 // get the maximum allowed windows space 00153 const TQRect maxRect = checkArea( c, area ); 00154 int x = maxRect.left(), y = maxRect.top(); 00155 x_optimal = x; y_optimal = y; 00156 00157 //client gabarit 00158 int ch = c->height() - 1; 00159 int cw = c->width() - 1; 00160 00161 bool first_pass = true; //CT lame flag. Don't like it. What else would do? 00162 00163 //loop over possible positions 00164 do 00165 { 00166 //test if enough room in x and y directions 00167 if (y + ch > maxRect.bottom() && ch < maxRect.height()) 00168 overlap = h_wrong; // this throws the algorithm to an exit 00169 else if(x + cw > maxRect.right()) 00170 overlap = w_wrong; 00171 else 00172 { 00173 overlap = none; //initialize 00174 00175 cxl = x; cxr = x + cw; 00176 cyt = y; cyb = y + ch; 00177 ClientList::ConstIterator l; 00178 for(l = m_WorkspacePtr->stackingOrder().begin(); l != m_WorkspacePtr->stackingOrder().end() ; ++l) 00179 { 00180 if((*l)->isOnDesktop(desktop) && 00181 (*l)->isShown( false ) && (*l) != c) 00182 { 00183 00184 xl = (*l)->x(); yt = (*l)->y(); 00185 xr = xl + (*l)->width(); yb = yt + (*l)->height(); 00186 00187 //if windows overlap, calc the overall overlapping 00188 if((cxl < xr) && (cxr > xl) && 00189 (cyt < yb) && (cyb > yt)) 00190 { 00191 xl = QMAX(cxl, xl); xr = QMIN(cxr, xr); 00192 yt = QMAX(cyt, yt); yb = QMIN(cyb, yb); 00193 if((*l)->keepAbove()) 00194 overlap += 16 * (xr - xl) * (yb - yt); 00195 else if((*l)->keepBelow() && !(*l)->isDock()) // ignore KeepBelow windows 00196 overlap += 0; // for placement (see Client::belongsToLayer() for Dock) 00197 else 00198 overlap += (xr - xl) * (yb - yt); 00199 } 00200 } 00201 } 00202 } 00203 00204 //CT first time we get no overlap we stop. 00205 if (overlap == none) 00206 { 00207 x_optimal = x; 00208 y_optimal = y; 00209 break; 00210 } 00211 00212 if (first_pass) 00213 { 00214 first_pass = false; 00215 min_overlap = overlap; 00216 } 00217 //CT save the best position and the minimum overlap up to now 00218 else if (overlap >= none && overlap < min_overlap) 00219 { 00220 min_overlap = overlap; 00221 x_optimal = x; 00222 y_optimal = y; 00223 } 00224 00225 // really need to loop? test if there's any overlap 00226 if (overlap > none) 00227 { 00228 00229 possible = maxRect.right(); 00230 if (possible - cw > x) possible -= cw; 00231 00232 // compare to the position of each client on the same desk 00233 ClientList::ConstIterator l; 00234 for(l = m_WorkspacePtr->stackingOrder().begin(); l != m_WorkspacePtr->stackingOrder().end() ; ++l) 00235 { 00236 00237 if ((*l)->isOnDesktop(desktop) && 00238 (*l)->isShown( false ) && (*l) != c) 00239 { 00240 00241 xl = (*l)->x(); yt = (*l)->y(); 00242 xr = xl + (*l)->width(); yb = yt + (*l)->height(); 00243 00244 // if not enough room above or under the current tested client 00245 // determine the first non-overlapped x position 00246 if((y < yb) && (yt < ch + y)) 00247 { 00248 00249 if((xr > x) && (possible > xr)) possible = xr; 00250 00251 basket = xl - cw; 00252 if((basket > x) && (possible > basket)) possible = basket; 00253 } 00254 } 00255 } 00256 x = possible; 00257 } 00258 00259 // ... else ==> not enough x dimension (overlap was wrong on horizontal) 00260 else if (overlap == w_wrong) 00261 { 00262 x = maxRect.left(); 00263 possible = maxRect.bottom(); 00264 00265 if (possible - ch > y) possible -= ch; 00266 00267 //test the position of each window on the desk 00268 ClientList::ConstIterator l; 00269 for(l = m_WorkspacePtr->stackingOrder().begin(); l != m_WorkspacePtr->stackingOrder().end() ; ++l) 00270 { 00271 if((*l)->isOnDesktop(desktop) && 00272 (*l) != c && c->isShown( false )) 00273 { 00274 00275 xl = (*l)->x(); yt = (*l)->y(); 00276 xr = xl + (*l)->width(); yb = yt + (*l)->height(); 00277 00278 // if not enough room to the left or right of the current tested client 00279 // determine the first non-overlapped y position 00280 if((yb > y) && (possible > yb)) possible = yb; 00281 00282 basket = yt - ch; 00283 if((basket > y) && (possible > basket)) possible = basket; 00284 } 00285 } 00286 y = possible; 00287 } 00288 } 00289 while((overlap != none) && (overlap != h_wrong) && (y < maxRect.bottom())); 00290 00291 if(ch>= maxRect.height()) 00292 y_optimal=maxRect.top(); 00293 00294 // place the window 00295 c->move(x_optimal, y_optimal); 00296 00297 } 00298 00299 void Placement::reinitCascading( int desktop ) 00300 { // desktop == 0 - reinit all 00301 if( desktop == 0 ) 00302 { 00303 cci.clear(); 00304 for( int i = 0; i < m_WorkspacePtr->numberOfDesktops(); i++) 00305 { 00306 DesktopCascadingInfo inf; 00307 inf.pos = TQPoint(-1,-1); 00308 inf.col = 0; 00309 inf.row = 0; 00310 cci.append(inf); 00311 } 00312 } 00313 else 00314 { 00315 cci[desktop - 1].pos = TQPoint(-1, -1); 00316 cci[desktop - 1].col = cci[desktop - 1].row = 0; 00317 } 00318 } 00319 00323 void Placement::placeCascaded (Client* c, TQRect& area, Policy nextPlacement) 00324 { 00325 /* cascadePlacement by Cristian Tibirna (tibirna@kde.org) (30Jan98) 00326 */ 00327 // work coords 00328 int xp, yp; 00329 00330 //CT how do I get from the 'Client' class the size that NW squarish "handle" 00331 const int delta_x = 24; 00332 const int delta_y = 24; 00333 00334 const int dn = c->desktop() == 0 || c->isOnAllDesktops() ? (m_WorkspacePtr->currentDesktop() - 1) : (c->desktop() - 1); 00335 00336 // get the maximum allowed windows space and desk's origin 00337 TQRect maxRect = checkArea( c, area ); 00338 00339 // initialize often used vars: width and height of c; we gain speed 00340 const int ch = c->height(); 00341 const int cw = c->width(); 00342 const int X = maxRect.left(); 00343 const int Y = maxRect.top(); 00344 const int H = maxRect.height(); 00345 const int W = maxRect.width(); 00346 00347 if( nextPlacement == Unknown ) 00348 nextPlacement = Smart; 00349 00350 //initialize if needed 00351 if (cci[dn].pos.x() < 0 || cci[dn].pos.x() < X || cci[dn].pos.y() < Y ) 00352 { 00353 cci[dn].pos = TQPoint(X, Y); 00354 cci[dn].col = cci[dn].row = 0; 00355 } 00356 00357 00358 xp = cci[dn].pos.x(); 00359 yp = cci[dn].pos.y(); 00360 00361 //here to touch in case people vote for resize on placement 00362 if ((yp + ch) > H) yp = Y; 00363 00364 if ((xp + cw) > W) 00365 if (!yp) 00366 { 00367 place(c,area,nextPlacement); 00368 return; 00369 } 00370 else xp = X; 00371 00372 //if this isn't the first window 00373 if (cci[dn].pos.x() != X && cci[dn].pos.y() != Y) 00374 { 00375 /* The following statements cause an internal compiler error with 00376 * egcs-2.91.66 on SuSE Linux 6.3. The equivalent forms compile fine. 00377 * 22-Dec-1999 CS 00378 * 00379 * if (xp != X && yp == Y) xp = delta_x * (++(cci[dn].col)); 00380 * if (yp != Y && xp == X) yp = delta_y * (++(cci[dn].row)); 00381 */ 00382 if (xp != X && yp == Y) 00383 { 00384 ++(cci[dn].col); 00385 xp = delta_x * cci[dn].col; 00386 } 00387 if (yp != Y && xp == X) 00388 { 00389 ++(cci[dn].row); 00390 yp = delta_y * cci[dn].row; 00391 } 00392 00393 // last resort: if still doesn't fit, smart place it 00394 if (((xp + cw) > W - X) || ((yp + ch) > H - Y)) 00395 { 00396 place(c,area,nextPlacement); 00397 return; 00398 } 00399 } 00400 00401 // place the window 00402 c->move(TQPoint(xp, yp)); 00403 00404 // new position 00405 cci[dn].pos = TQPoint(xp + delta_x, yp + delta_y); 00406 } 00407 00411 void Placement::placeCentered (Client* c, const TQRect& area, Policy /*next*/ ) 00412 { 00413 00414 // get the maximum allowed windows space and desk's origin 00415 const TQRect maxRect = checkArea( c, area ); 00416 00417 const int xp = maxRect.left() + (maxRect.width() - c->width()) / 2; 00418 const int yp = maxRect.top() + (maxRect.height() - c->height()) / 2; 00419 00420 // place the window 00421 c->move(TQPoint(xp, yp)); 00422 } 00423 00427 void Placement::placeZeroCornered(Client* c, const TQRect& area, Policy /*next*/ ) 00428 { 00429 // get the maximum allowed windows space and desk's origin 00430 const TQRect maxRect = checkArea( c, area ); 00431 00432 // place the window 00433 c->move(TQPoint(maxRect.left(), maxRect.top())); 00434 } 00435 00436 void Placement::placeUtility(Client* c, TQRect& area, Policy /*next*/ ) 00437 { 00438 // TODO kwin should try to place utility windows next to their mainwindow, 00439 // preferably at the right edge, and going down if there are more of them 00440 // if there's not enough place outside the mainwindow, it should prefer 00441 // top-right corner 00442 // use the default placement for now 00443 place( c, area, Default ); 00444 } 00445 00446 00447 void Placement::placeDialog(Client* c, TQRect& area, Policy nextPlacement ) 00448 { 00449 placeOnMainWindow( c, area, nextPlacement ); 00450 } 00451 00452 void Placement::placeUnderMouse(Client* c, TQRect& area, Policy /*next*/ ) 00453 { 00454 area = checkArea( c, area ); 00455 TQRect geom = c->geometry(); 00456 geom.moveCenter( TQCursor::pos()); 00457 c->move( geom.topLeft()); 00458 c->keepInArea( area ); // make sure it's kept inside workarea 00459 } 00460 00461 void Placement::placeOnMainWindow(Client* c, TQRect& area, Policy nextPlacement ) 00462 { 00463 if( nextPlacement == Unknown ) 00464 nextPlacement = Centered; 00465 if( nextPlacement == Maximizing ) // maximize if needed 00466 placeMaximizing( c, area, NoPlacement ); 00467 area = checkArea( c, area ); 00468 ClientList mainwindows = c->mainClients(); 00469 Client* place_on = NULL; 00470 Client* place_on2 = NULL; 00471 int mains_count = 0; 00472 for( ClientList::ConstIterator it = mainwindows.begin(); 00473 it != mainwindows.end(); 00474 ++it ) 00475 { 00476 if( mainwindows.count() > 1 && (*it)->isSpecialWindow()) 00477 continue; // don't consider toolbars etc when placing 00478 ++mains_count; 00479 place_on2 = *it; 00480 if( (*it)->isOnCurrentDesktop()) 00481 { 00482 if( place_on == NULL ) 00483 place_on = *it; 00484 else 00485 { // two or more on current desktop -> center 00486 // That's the default at least. However, with maximizing placement 00487 // policy as the default, the dialog should be either maximized or 00488 // made as large as its maximum size and then placed centered. 00489 // So the nextPlacement argument allows chaining. In this case, nextPlacement 00490 // is Maximizing and it will call placeCentered(). 00491 place( c, area, Centered ); 00492 return; 00493 } 00494 } 00495 } 00496 if( place_on == NULL ) 00497 { // 'mains_count' is used because it doesn't include ignored mainwindows 00498 if( mains_count != 1 ) 00499 { 00500 place( c, area, Centered ); 00501 return; 00502 } 00503 place_on = place_on2; // use the only window filtered together with 'mains_count' 00504 } 00505 if( place_on->isDesktop()) 00506 { 00507 place( c, area, Centered ); 00508 return; 00509 } 00510 TQRect geom = c->geometry(); 00511 geom.moveCenter( place_on->geometry().center()); 00512 c->move( geom.topLeft()); 00513 // get area again, because the mainwindow may be on different xinerama screen 00514 area = checkArea( c, TQRect()); 00515 c->keepInArea( area ); // make sure it's kept inside workarea 00516 } 00517 00518 void Placement::placeMaximizing(Client* c, TQRect& area, Policy nextPlacement ) 00519 { 00520 if( nextPlacement == Unknown ) 00521 nextPlacement = Smart; 00522 if( c->isMaximizable() && c->maxSize().width() >= area.width() && c->maxSize().height() >= area.height()) 00523 { 00524 if( m_WorkspacePtr->clientArea( MaximizeArea, c ) == area ) 00525 c->maximize( Client::MaximizeFull ); 00526 else // if the geometry doesn't match default maximize area (xinerama case?), 00527 { // it's probably better to use the given area 00528 c->setGeometry( area ); 00529 } 00530 } 00531 else 00532 { 00533 c->resizeWithChecks( c->maxSize().boundedTo( area.size())); 00534 place( c, area, nextPlacement ); 00535 } 00536 } 00537 00538 TQRect Placement::checkArea( const Client* c, const TQRect& area ) 00539 { 00540 if( area.isNull()) 00541 return m_WorkspacePtr->clientArea( PlacementArea, c->geometry().center(), c->desktop()); 00542 return area; 00543 } 00544 00545 #endif 00546 00547 00548 Placement::Policy Placement::policyFromString( const TQString& policy, bool no_special ) 00549 { 00550 if( policy == "NoPlacement" ) 00551 return NoPlacement; 00552 else if( policy == "Default" && !no_special ) 00553 return Default; 00554 else if( policy == "Random" ) 00555 return Random; 00556 else if( policy == "Cascade" ) 00557 return Cascade; 00558 else if( policy == "Centered" ) 00559 return Centered; 00560 else if( policy == "ZeroCornered" ) 00561 return ZeroCornered; 00562 else if( policy == "UnderMouse" && !no_special) 00563 return UnderMouse; 00564 else if( policy == "OnMainWindow" && !no_special) 00565 return OnMainWindow; 00566 else if( policy == "Maximizing" ) 00567 return Maximizing; 00568 else 00569 return Smart; 00570 } 00571 00572 const char* Placement::policyToString( Policy policy ) 00573 { 00574 const char* const policies[] = 00575 { "NoPlacement", "Default", "XXX should never see", "Random", "Smart", "Cascade", "Centered", 00576 "ZeroCornered", "UnderMouse", "OnMainWindow", "Maximizing" }; 00577 assert( policy < int( sizeof( policies ) / sizeof( policies[ 0 ] ))); 00578 return policies[ policy ]; 00579 } 00580 00581 00582 #ifndef KCMRULES 00583 00584 // ******************** 00585 // Workspace 00586 // ******************** 00587 00591 void Workspace::slotWindowPackLeft() 00592 { 00593 if( active_client && active_client->isMovable()) 00594 active_client->move( packPositionLeft( active_client, active_client->geometry().left(), true ), 00595 active_client->y()); 00596 } 00597 00598 void Workspace::slotWindowPackRight() 00599 { 00600 if( active_client && active_client->isMovable()) 00601 active_client->move( 00602 packPositionRight( active_client, active_client->geometry().right(), true ) 00603 - active_client->width() + 1, active_client->y()); 00604 } 00605 00606 void Workspace::slotWindowPackUp() 00607 { 00608 if( active_client && active_client->isMovable()) 00609 active_client->move( active_client->x(), 00610 packPositionUp( active_client, active_client->geometry().top(), true )); 00611 } 00612 00613 void Workspace::slotWindowPackDown() 00614 { 00615 if( active_client && active_client->isMovable()) 00616 active_client->move( active_client->x(), 00617 packPositionDown( active_client, active_client->geometry().bottom(), true ) - active_client->height() + 1 ); 00618 } 00619 00620 void Workspace::slotWindowGrowHorizontal() 00621 { 00622 if( active_client ) 00623 active_client->growHorizontal(); 00624 } 00625 00626 void Client::growHorizontal() 00627 { 00628 if( !isResizable() || isShade()) 00629 return; 00630 TQRect geom = geometry(); 00631 geom.setRight( workspace()->packPositionRight( this, geom.right(), true )); 00632 TQSize adjsize = adjustedSize( geom.size(), SizemodeFixedW ); 00633 if( geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.width_inc > 1 ) // take care of size increments 00634 { 00635 int newright = workspace()->packPositionRight( this, geom.right() + xSizeHint.width_inc - 1, true ); 00636 // check that it hasn't grown outside of the area, due to size increments 00637 // TODO this may be wrong? 00638 if( workspace()->clientArea( MovementArea, 00639 TQPoint(( x() + newright ) / 2, geometry().center().y()), desktop()).right() >= newright ) 00640 geom.setRight( newright ); 00641 } 00642 geom.setSize( adjustedSize( geom.size(), SizemodeFixedW )); 00643 setGeometry( geom ); 00644 } 00645 00646 void Workspace::slotWindowShrinkHorizontal() 00647 { 00648 if( active_client ) 00649 active_client->shrinkHorizontal(); 00650 } 00651 00652 void Client::shrinkHorizontal() 00653 { 00654 if( !isResizable() || isShade()) 00655 return; 00656 TQRect geom = geometry(); 00657 geom.setRight( workspace()->packPositionLeft( this, geom.right(), false )); 00658 if( geom.width() <= 1 ) 00659 return; 00660 geom.setSize( adjustedSize( geom.size(), SizemodeFixedW )); 00661 if( geom.width() > 20 ) 00662 setGeometry( geom ); 00663 } 00664 00665 void Workspace::slotWindowGrowVertical() 00666 { 00667 if( active_client ) 00668 active_client->growVertical(); 00669 } 00670 00671 void Client::growVertical() 00672 { 00673 if( !isResizable() || isShade()) 00674 return; 00675 TQRect geom = geometry(); 00676 geom.setBottom( workspace()->packPositionDown( this, geom.bottom(), true )); 00677 TQSize adjsize = adjustedSize( geom.size(), SizemodeFixedH ); 00678 if( geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.height_inc > 1 ) // take care of size increments 00679 { 00680 int newbottom = workspace()->packPositionDown( this, geom.bottom() + xSizeHint.height_inc - 1, true ); 00681 // check that it hasn't grown outside of the area, due to size increments 00682 if( workspace()->clientArea( MovementArea, 00683 TQPoint( geometry().center().x(), ( y() + newbottom ) / 2 ), desktop()).bottom() >= newbottom ) 00684 geom.setBottom( newbottom ); 00685 } 00686 geom.setSize( adjustedSize( geom.size(), SizemodeFixedH )); 00687 setGeometry( geom ); 00688 } 00689 00690 00691 void Workspace::slotWindowShrinkVertical() 00692 { 00693 if( active_client ) 00694 active_client->shrinkVertical(); 00695 } 00696 00697 void Client::shrinkVertical() 00698 { 00699 if( !isResizable() || isShade()) 00700 return; 00701 TQRect geom = geometry(); 00702 geom.setBottom( workspace()->packPositionUp( this, geom.bottom(), false )); 00703 if( geom.height() <= 1 ) 00704 return; 00705 geom.setSize( adjustedSize( geom.size(), SizemodeFixedH )); 00706 if( geom.height() > 20 ) 00707 setGeometry( geom ); 00708 } 00709 00710 int Workspace::packPositionLeft( const Client* cl, int oldx, bool left_edge ) const 00711 { 00712 int newx = clientArea( MovementArea, cl ).left(); 00713 if( oldx <= newx ) // try another Xinerama screen 00714 newx = clientArea( MovementArea, 00715 TQPoint( cl->geometry().left() - 1, cl->geometry().center().y()), cl->desktop()).left(); 00716 if( oldx <= newx ) 00717 return oldx; 00718 for( ClientList::ConstIterator it = clients.begin(); 00719 it != clients.end(); 00720 ++it) 00721 { 00722 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( active_client->desktop())) 00723 continue; 00724 int x = left_edge ? (*it)->geometry().right() + 1 : (*it)->geometry().left() - 1; 00725 if( x > newx && x < oldx 00726 && !( cl->geometry().top() > (*it)->geometry().bottom() // they overlap in Y direction 00727 || cl->geometry().bottom() < (*it)->geometry().top())) 00728 newx = x; 00729 } 00730 return newx; 00731 } 00732 00733 int Workspace::packPositionRight( const Client* cl, int oldx, bool right_edge ) const 00734 { 00735 int newx = clientArea( MovementArea, cl ).right(); 00736 if( oldx >= newx ) // try another Xinerama screen 00737 newx = clientArea( MovementArea, 00738 TQPoint( cl->geometry().right() + 1, cl->geometry().center().y()), cl->desktop()).right(); 00739 if( oldx >= newx ) 00740 return oldx; 00741 for( ClientList::ConstIterator it = clients.begin(); 00742 it != clients.end(); 00743 ++it) 00744 { 00745 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( cl->desktop())) 00746 continue; 00747 int x = right_edge ? (*it)->geometry().left() - 1 : (*it)->geometry().right() + 1; 00748 if( x < newx && x > oldx 00749 && !( cl->geometry().top() > (*it)->geometry().bottom() 00750 || cl->geometry().bottom() < (*it)->geometry().top())) 00751 newx = x; 00752 } 00753 return newx; 00754 } 00755 00756 int Workspace::packPositionUp( const Client* cl, int oldy, bool top_edge ) const 00757 { 00758 int newy = clientArea( MovementArea, cl ).top(); 00759 if( oldy <= newy ) // try another Xinerama screen 00760 newy = clientArea( MovementArea, 00761 TQPoint( cl->geometry().center().x(), cl->geometry().top() - 1 ), cl->desktop()).top(); 00762 if( oldy <= newy ) 00763 return oldy; 00764 for( ClientList::ConstIterator it = clients.begin(); 00765 it != clients.end(); 00766 ++it) 00767 { 00768 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( cl->desktop())) 00769 continue; 00770 int y = top_edge ? (*it)->geometry().bottom() + 1 : (*it)->geometry().top() - 1; 00771 if( y > newy && y < oldy 00772 && !( cl->geometry().left() > (*it)->geometry().right() // they overlap in X direction 00773 || cl->geometry().right() < (*it)->geometry().left())) 00774 newy = y; 00775 } 00776 return newy; 00777 } 00778 00779 int Workspace::packPositionDown( const Client* cl, int oldy, bool bottom_edge ) const 00780 { 00781 int newy = clientArea( MovementArea, cl ).bottom(); 00782 if( oldy >= newy ) // try another Xinerama screen 00783 newy = clientArea( MovementArea, 00784 TQPoint( cl->geometry().center().x(), cl->geometry().bottom() + 1 ), cl->desktop()).bottom(); 00785 if( oldy >= newy ) 00786 return oldy; 00787 for( ClientList::ConstIterator it = clients.begin(); 00788 it != clients.end(); 00789 ++it) 00790 { 00791 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( cl->desktop())) 00792 continue; 00793 int y = bottom_edge ? (*it)->geometry().top() - 1 : (*it)->geometry().bottom() + 1; 00794 if( y < newy && y > oldy 00795 && !( cl->geometry().left() > (*it)->geometry().right() 00796 || cl->geometry().right() < (*it)->geometry().left())) 00797 newy = y; 00798 } 00799 return newy; 00800 } 00801 00805 void Workspace::place(Client* c, TQRect& area) 00806 { 00807 initPositioning->place( c, area ); 00808 } 00809 00810 void Workspace::placeSmart(Client* c, const TQRect& area) 00811 { 00812 initPositioning->placeSmart( c, area ); 00813 } 00814 00815 #endif 00816 00817 } // namespace