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 twin (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 = TQMAX(cxl, xl); xr = TQMIN(cxr, xr); 00192 yt = TQMAX(cyt, yt); yb = TQMIN(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 { 00366 if (!yp) 00367 { 00368 place(c,area,nextPlacement); 00369 return; 00370 } 00371 } 00372 else 00373 { 00374 xp = X; 00375 } 00376 00377 //if this isn't the first window 00378 if (cci[dn].pos.x() != X && cci[dn].pos.y() != Y) 00379 { 00380 /* The following statements cause an internal compiler error with 00381 * egcs-2.91.66 on SuSE Linux 6.3. The equivalent forms compile fine. 00382 * 22-Dec-1999 CS 00383 * 00384 * if (xp != X && yp == Y) xp = delta_x * (++(cci[dn].col)); 00385 * if (yp != Y && xp == X) yp = delta_y * (++(cci[dn].row)); 00386 */ 00387 if (xp != X && yp == Y) 00388 { 00389 ++(cci[dn].col); 00390 xp = delta_x * cci[dn].col; 00391 } 00392 if (yp != Y && xp == X) 00393 { 00394 ++(cci[dn].row); 00395 yp = delta_y * cci[dn].row; 00396 } 00397 00398 // last resort: if still doesn't fit, smart place it 00399 if (((xp + cw) > W - X) || ((yp + ch) > H - Y)) 00400 { 00401 place(c,area,nextPlacement); 00402 return; 00403 } 00404 } 00405 00406 // place the window 00407 c->move(TQPoint(xp, yp)); 00408 00409 // new position 00410 cci[dn].pos = TQPoint(xp + delta_x, yp + delta_y); 00411 } 00412 00416 void Placement::placeCentered (Client* c, const TQRect& area, Policy /*next*/ ) 00417 { 00418 00419 // get the maximum allowed windows space and desk's origin 00420 const TQRect maxRect = checkArea( c, area ); 00421 00422 const int xp = maxRect.left() + (maxRect.width() - c->width()) / 2; 00423 const int yp = maxRect.top() + (maxRect.height() - c->height()) / 2; 00424 00425 // place the window 00426 c->move(TQPoint(xp, yp)); 00427 } 00428 00432 void Placement::placeZeroCornered(Client* c, const TQRect& area, Policy /*next*/ ) 00433 { 00434 // get the maximum allowed windows space and desk's origin 00435 const TQRect maxRect = checkArea( c, area ); 00436 00437 // place the window 00438 c->move(TQPoint(maxRect.left(), maxRect.top())); 00439 } 00440 00441 void Placement::placeUtility(Client* c, TQRect& area, Policy /*next*/ ) 00442 { 00443 // TODO twin should try to place utility windows next to their mainwindow, 00444 // preferably at the right edge, and going down if there are more of them 00445 // if there's not enough place outside the mainwindow, it should prefer 00446 // top-right corner 00447 // use the default placement for now 00448 place( c, area, Default ); 00449 } 00450 00451 00452 void Placement::placeDialog(Client* c, TQRect& area, Policy nextPlacement ) 00453 { 00454 placeOnMainWindow( c, area, nextPlacement ); 00455 } 00456 00457 void Placement::placeUnderMouse(Client* c, TQRect& area, Policy /*next*/ ) 00458 { 00459 area = checkArea( c, area ); 00460 TQRect geom = c->geometry(); 00461 geom.moveCenter( TQCursor::pos()); 00462 c->move( geom.topLeft()); 00463 c->keepInArea( area ); // make sure it's kept inside workarea 00464 } 00465 00466 void Placement::placeOnMainWindow(Client* c, TQRect& area, Policy nextPlacement ) 00467 { 00468 if( nextPlacement == Unknown ) 00469 nextPlacement = Centered; 00470 if( nextPlacement == Maximizing ) // maximize if needed 00471 placeMaximizing( c, area, NoPlacement ); 00472 area = checkArea( c, area ); 00473 ClientList mainwindows = c->mainClients(); 00474 Client* place_on = NULL; 00475 Client* place_on2 = NULL; 00476 int mains_count = 0; 00477 for( ClientList::ConstIterator it = mainwindows.begin(); 00478 it != mainwindows.end(); 00479 ++it ) 00480 { 00481 if( mainwindows.count() > 1 && (*it)->isSpecialWindow()) 00482 continue; // don't consider toolbars etc when placing 00483 ++mains_count; 00484 place_on2 = *it; 00485 if( (*it)->isOnCurrentDesktop()) 00486 { 00487 if( place_on == NULL ) 00488 place_on = *it; 00489 else 00490 { // two or more on current desktop -> center 00491 // That's the default at least. However, with maximizing placement 00492 // policy as the default, the dialog should be either maximized or 00493 // made as large as its maximum size and then placed centered. 00494 // So the nextPlacement argument allows chaining. In this case, nextPlacement 00495 // is Maximizing and it will call placeCentered(). 00496 place( c, area, Centered ); 00497 return; 00498 } 00499 } 00500 } 00501 if( place_on == NULL ) 00502 { // 'mains_count' is used because it doesn't include ignored mainwindows 00503 if( mains_count != 1 ) 00504 { 00505 place( c, area, Centered ); 00506 return; 00507 } 00508 place_on = place_on2; // use the only window filtered together with 'mains_count' 00509 } 00510 if( place_on->isDesktop()) 00511 { 00512 place( c, area, Centered ); 00513 return; 00514 } 00515 TQRect geom = c->geometry(); 00516 geom.moveCenter( place_on->geometry().center()); 00517 c->move( geom.topLeft()); 00518 // get area again, because the mainwindow may be on different xinerama screen 00519 area = checkArea( c, TQRect()); 00520 c->keepInArea( area ); // make sure it's kept inside workarea 00521 } 00522 00523 void Placement::placeMaximizing(Client* c, TQRect& area, Policy nextPlacement ) 00524 { 00525 if( nextPlacement == Unknown ) 00526 nextPlacement = Smart; 00527 if( c->isMaximizable() && c->maxSize().width() >= area.width() && c->maxSize().height() >= area.height()) 00528 { 00529 if( m_WorkspacePtr->clientArea( MaximizeArea, c ) == area ) 00530 c->maximize( Client::MaximizeFull ); 00531 else // if the geometry doesn't match default maximize area (xinerama case?), 00532 { // it's probably better to use the given area 00533 c->setGeometry( area ); 00534 } 00535 } 00536 else 00537 { 00538 c->resizeWithChecks( c->maxSize().boundedTo( area.size())); 00539 place( c, area, nextPlacement ); 00540 } 00541 } 00542 00543 TQRect Placement::checkArea( const Client* c, const TQRect& area ) 00544 { 00545 if( area.isNull()) 00546 return m_WorkspacePtr->clientArea( PlacementArea, c->geometry().center(), c->desktop()); 00547 return area; 00548 } 00549 00550 #endif 00551 00552 00553 Placement::Policy Placement::policyFromString( const TQString& policy, bool no_special ) 00554 { 00555 if( policy == "NoPlacement" ) 00556 return NoPlacement; 00557 else if( policy == "Default" && !no_special ) 00558 return Default; 00559 else if( policy == "Random" ) 00560 return Random; 00561 else if( policy == "Cascade" ) 00562 return Cascade; 00563 else if( policy == "Centered" ) 00564 return Centered; 00565 else if( policy == "ZeroCornered" ) 00566 return ZeroCornered; 00567 else if( policy == "UnderMouse" && !no_special) 00568 return UnderMouse; 00569 else if( policy == "OnMainWindow" && !no_special) 00570 return OnMainWindow; 00571 else if( policy == "Maximizing" ) 00572 return Maximizing; 00573 else 00574 return Smart; 00575 } 00576 00577 const char* Placement::policyToString( Policy policy ) 00578 { 00579 const char* const policies[] = 00580 { "NoPlacement", "Default", "XXX should never see", "Random", "Smart", "Cascade", "Centered", 00581 "ZeroCornered", "UnderMouse", "OnMainWindow", "Maximizing" }; 00582 assert( policy < int( sizeof( policies ) / sizeof( policies[ 0 ] ))); 00583 return policies[ policy ]; 00584 } 00585 00586 00587 #ifndef KCMRULES 00588 00589 // ******************** 00590 // Workspace 00591 // ******************** 00592 00596 void Workspace::slotWindowPackLeft() 00597 { 00598 if( active_client && active_client->isMovable()) 00599 active_client->move( packPositionLeft( active_client, active_client->geometry().left(), true ), 00600 active_client->y()); 00601 } 00602 00603 void Workspace::slotWindowPackRight() 00604 { 00605 if( active_client && active_client->isMovable()) 00606 active_client->move( 00607 packPositionRight( active_client, active_client->geometry().right(), true ) 00608 - active_client->width() + 1, active_client->y()); 00609 } 00610 00611 void Workspace::slotWindowPackUp() 00612 { 00613 if( active_client && active_client->isMovable()) 00614 active_client->move( active_client->x(), 00615 packPositionUp( active_client, active_client->geometry().top(), true )); 00616 } 00617 00618 void Workspace::slotWindowPackDown() 00619 { 00620 if( active_client && active_client->isMovable()) 00621 active_client->move( active_client->x(), 00622 packPositionDown( active_client, active_client->geometry().bottom(), true ) - active_client->height() + 1 ); 00623 } 00624 00625 void Workspace::slotWindowGrowHorizontal() 00626 { 00627 if( active_client ) 00628 active_client->growHorizontal(); 00629 } 00630 00631 void Client::growHorizontal() 00632 { 00633 if( !isResizable() || isShade()) 00634 return; 00635 TQRect geom = geometry(); 00636 geom.setRight( workspace()->packPositionRight( this, geom.right(), true )); 00637 TQSize adjsize = adjustedSize( geom.size(), SizemodeFixedW ); 00638 if( geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.width_inc > 1 ) // take care of size increments 00639 { 00640 int newright = workspace()->packPositionRight( this, geom.right() + xSizeHint.width_inc - 1, true ); 00641 // check that it hasn't grown outside of the area, due to size increments 00642 // TODO this may be wrong? 00643 if( workspace()->clientArea( MovementArea, 00644 TQPoint(( x() + newright ) / 2, geometry().center().y()), desktop()).right() >= newright ) 00645 geom.setRight( newright ); 00646 } 00647 geom.setSize( adjustedSize( geom.size(), SizemodeFixedW )); 00648 setGeometry( geom ); 00649 } 00650 00651 void Workspace::slotWindowShrinkHorizontal() 00652 { 00653 if( active_client ) 00654 active_client->shrinkHorizontal(); 00655 } 00656 00657 void Client::shrinkHorizontal() 00658 { 00659 if( !isResizable() || isShade()) 00660 return; 00661 TQRect geom = geometry(); 00662 geom.setRight( workspace()->packPositionLeft( this, geom.right(), false )); 00663 if( geom.width() <= 1 ) 00664 return; 00665 geom.setSize( adjustedSize( geom.size(), SizemodeFixedW )); 00666 if( geom.width() > 20 ) 00667 setGeometry( geom ); 00668 } 00669 00670 void Workspace::slotWindowGrowVertical() 00671 { 00672 if( active_client ) 00673 active_client->growVertical(); 00674 } 00675 00676 void Client::growVertical() 00677 { 00678 if( !isResizable() || isShade()) 00679 return; 00680 TQRect geom = geometry(); 00681 geom.setBottom( workspace()->packPositionDown( this, geom.bottom(), true )); 00682 TQSize adjsize = adjustedSize( geom.size(), SizemodeFixedH ); 00683 if( geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.height_inc > 1 ) // take care of size increments 00684 { 00685 int newbottom = workspace()->packPositionDown( this, geom.bottom() + xSizeHint.height_inc - 1, true ); 00686 // check that it hasn't grown outside of the area, due to size increments 00687 if( workspace()->clientArea( MovementArea, 00688 TQPoint( geometry().center().x(), ( y() + newbottom ) / 2 ), desktop()).bottom() >= newbottom ) 00689 geom.setBottom( newbottom ); 00690 } 00691 geom.setSize( adjustedSize( geom.size(), SizemodeFixedH )); 00692 setGeometry( geom ); 00693 } 00694 00695 00696 void Workspace::slotWindowShrinkVertical() 00697 { 00698 if( active_client ) 00699 active_client->shrinkVertical(); 00700 } 00701 00702 void Client::shrinkVertical() 00703 { 00704 if( !isResizable() || isShade()) 00705 return; 00706 TQRect geom = geometry(); 00707 geom.setBottom( workspace()->packPositionUp( this, geom.bottom(), false )); 00708 if( geom.height() <= 1 ) 00709 return; 00710 geom.setSize( adjustedSize( geom.size(), SizemodeFixedH )); 00711 if( geom.height() > 20 ) 00712 setGeometry( geom ); 00713 } 00714 00715 int Workspace::packPositionLeft( const Client* cl, int oldx, bool left_edge ) const 00716 { 00717 int newx = clientArea( MovementArea, cl ).left(); 00718 if( oldx <= newx ) // try another Xinerama screen 00719 newx = clientArea( MovementArea, 00720 TQPoint( cl->geometry().left() - 1, cl->geometry().center().y()), cl->desktop()).left(); 00721 if( oldx <= newx ) 00722 return oldx; 00723 for( ClientList::ConstIterator it = clients.begin(); 00724 it != clients.end(); 00725 ++it) 00726 { 00727 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( active_client->desktop())) 00728 continue; 00729 int x = left_edge ? (*it)->geometry().right() + 1 : (*it)->geometry().left() - 1; 00730 if( x > newx && x < oldx 00731 && !( cl->geometry().top() > (*it)->geometry().bottom() // they overlap in Y direction 00732 || cl->geometry().bottom() < (*it)->geometry().top())) 00733 newx = x; 00734 } 00735 return newx; 00736 } 00737 00738 int Workspace::packPositionRight( const Client* cl, int oldx, bool right_edge ) const 00739 { 00740 int newx = clientArea( MovementArea, cl ).right(); 00741 if( oldx >= newx ) // try another Xinerama screen 00742 newx = clientArea( MovementArea, 00743 TQPoint( cl->geometry().right() + 1, cl->geometry().center().y()), cl->desktop()).right(); 00744 if( oldx >= newx ) 00745 return oldx; 00746 for( ClientList::ConstIterator it = clients.begin(); 00747 it != clients.end(); 00748 ++it) 00749 { 00750 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( cl->desktop())) 00751 continue; 00752 int x = right_edge ? (*it)->geometry().left() - 1 : (*it)->geometry().right() + 1; 00753 if( x < newx && x > oldx 00754 && !( cl->geometry().top() > (*it)->geometry().bottom() 00755 || cl->geometry().bottom() < (*it)->geometry().top())) 00756 newx = x; 00757 } 00758 return newx; 00759 } 00760 00761 int Workspace::packPositionUp( const Client* cl, int oldy, bool top_edge ) const 00762 { 00763 int newy = clientArea( MovementArea, cl ).top(); 00764 if( oldy <= newy ) // try another Xinerama screen 00765 newy = clientArea( MovementArea, 00766 TQPoint( cl->geometry().center().x(), cl->geometry().top() - 1 ), cl->desktop()).top(); 00767 if( oldy <= newy ) 00768 return oldy; 00769 for( ClientList::ConstIterator it = clients.begin(); 00770 it != clients.end(); 00771 ++it) 00772 { 00773 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( cl->desktop())) 00774 continue; 00775 int y = top_edge ? (*it)->geometry().bottom() + 1 : (*it)->geometry().top() - 1; 00776 if( y > newy && y < oldy 00777 && !( cl->geometry().left() > (*it)->geometry().right() // they overlap in X direction 00778 || cl->geometry().right() < (*it)->geometry().left())) 00779 newy = y; 00780 } 00781 return newy; 00782 } 00783 00784 int Workspace::packPositionDown( const Client* cl, int oldy, bool bottom_edge ) const 00785 { 00786 int newy = clientArea( MovementArea, cl ).bottom(); 00787 if( oldy >= newy ) // try another Xinerama screen 00788 newy = clientArea( MovementArea, 00789 TQPoint( cl->geometry().center().x(), cl->geometry().bottom() + 1 ), cl->desktop()).bottom(); 00790 if( oldy >= newy ) 00791 return oldy; 00792 for( ClientList::ConstIterator it = clients.begin(); 00793 it != clients.end(); 00794 ++it) 00795 { 00796 if( !(*it)->isShown( false ) || !(*it)->isOnDesktop( cl->desktop())) 00797 continue; 00798 int y = bottom_edge ? (*it)->geometry().top() - 1 : (*it)->geometry().bottom() + 1; 00799 if( y < newy && y > oldy 00800 && !( cl->geometry().left() > (*it)->geometry().right() 00801 || cl->geometry().right() < (*it)->geometry().left())) 00802 newy = y; 00803 } 00804 return newy; 00805 } 00806 00810 void Workspace::place(Client* c, TQRect& area) 00811 { 00812 initPositioning->place( c, area ); 00813 } 00814 00815 void Workspace::placeSmart(Client* c, const TQRect& area) 00816 { 00817 initPositioning->placeSmart( c, area ); 00818 } 00819 00820 #endif 00821 00822 } // namespace