00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "client.h"
00020 #include "workspace.h"
00021
00022 #include <kapplication.h>
00023 #include <kglobal.h>
00024 #include <qpainter.h>
00025 #include <kwin.h>
00026
00027 #include "placement.h"
00028 #include "notifications.h"
00029 #include "geometrytip.h"
00030 #include "rules.h"
00031
00032 extern Time qt_x_time;
00033
00034 namespace KWinInternal
00035 {
00036
00037
00038
00039
00040
00044 void Workspace::desktopResized()
00045 {
00046 updateClientArea();
00047 checkElectricBorders( true );
00048 }
00049
00062 void Workspace::updateClientArea( bool force )
00063 {
00064 QDesktopWidget *desktopwidget = KApplication::desktop();
00065 int nscreens = desktopwidget -> numScreens ();
00066
00067 QRect* new_wareas = new QRect[ numberOfDesktops() + 1 ];
00068 QRect** new_sareas = new QRect*[ numberOfDesktops() + 1];
00069 QRect* screens = new QRect [ nscreens ];
00070 QRect desktopArea = desktopwidget -> geometry ();
00071 for( int iS = 0;
00072 iS < nscreens;
00073 iS ++ )
00074 {
00075 screens [iS] = desktopwidget -> screenGeometry (iS);
00076 }
00077 for( int i = 1;
00078 i <= numberOfDesktops();
00079 ++i )
00080 {
00081 new_wareas[ i ] = desktopArea;
00082 new_sareas[ i ] = new QRect [ nscreens ];
00083 for( int iS = 0;
00084 iS < nscreens;
00085 iS ++ )
00086 new_sareas[ i ][ iS ] = screens[ iS ];
00087 }
00088 for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00089 {
00090 QRect r = (*it)->adjustedClientArea( desktopArea, desktopArea );
00091 if( r == desktopArea )
00092 continue;
00093 if( (*it)->isOnAllDesktops())
00094 for( int i = 1;
00095 i <= numberOfDesktops();
00096 ++i )
00097 {
00098 new_wareas[ i ] = new_wareas[ i ].intersect( r );
00099 for( int iS = 0;
00100 iS < nscreens;
00101 iS ++ )
00102 new_sareas[ i ][ iS ] =
00103 new_sareas[ i ][ iS ].intersect(
00104 (*it)->adjustedClientArea( desktopArea, screens[ iS ] )
00105 );
00106 }
00107 else
00108 {
00109 new_wareas[ (*it)->desktop() ] = new_wareas[ (*it)->desktop() ].intersect( r );
00110 for( int iS = 0;
00111 iS < nscreens;
00112 iS ++ )
00113 {
00114
00115 new_sareas[ (*it)->desktop() ][ iS ] =
00116 new_sareas[ (*it)->desktop() ][ iS ].intersect(
00117 (*it)->adjustedClientArea( desktopArea, screens[ iS ] )
00118 );
00119 }
00120 }
00121 }
00122 #if 0
00123 for( int i = 1;
00124 i <= numberOfDesktops();
00125 ++i )
00126 {
00127 for( int iS = 0;
00128 iS < nscreens;
00129 iS ++ )
00130 kdDebug () << "new_sarea: " << new_sareas[ i ][ iS ] << endl;
00131 }
00132 #endif
00133
00134 if( topmenu_space != NULL )
00135 {
00136 QRect topmenu_area = desktopArea;
00137 topmenu_area.setTop( topMenuHeight());
00138 for( int i = 1;
00139 i <= numberOfDesktops();
00140 ++i )
00141 new_wareas[ i ] = new_wareas[ i ].intersect( topmenu_area );
00142 }
00143
00144 bool changed = force;
00145
00146 if (! screenarea)
00147 changed = true;
00148
00149 for( int i = 1;
00150 !changed && i <= numberOfDesktops();
00151 ++i )
00152 {
00153 if( workarea[ i ] != new_wareas[ i ] )
00154 changed = true;
00155 for( int iS = 0;
00156 iS < nscreens;
00157 iS ++ )
00158 if (new_sareas[ i ][ iS ] != screenarea [ i ][ iS ])
00159 changed = true;
00160 }
00161
00162 if ( changed )
00163 {
00164 delete[] workarea;
00165 workarea = new_wareas;
00166 new_wareas = NULL;
00167 delete[] screenarea;
00168 screenarea = new_sareas;
00169 new_sareas = NULL;
00170 NETRect r;
00171 for( int i = 1; i <= numberOfDesktops(); i++)
00172 {
00173 r.pos.x = workarea[ i ].x();
00174 r.pos.y = workarea[ i ].y();
00175 r.size.width = workarea[ i ].width();
00176 r.size.height = workarea[ i ].height();
00177 rootInfo->setWorkArea( i, r );
00178 }
00179
00180 updateTopMenuGeometry();
00181 for( ClientList::ConstIterator it = clients.begin();
00182 it != clients.end();
00183 ++it)
00184 (*it)->checkWorkspacePosition();
00185 for( ClientList::ConstIterator it = desktops.begin();
00186 it != desktops.end();
00187 ++it)
00188 (*it)->checkWorkspacePosition();
00189 }
00190 delete[] screens;
00191 delete[] new_sareas;
00192 delete[] new_wareas;
00193 }
00194
00195 void Workspace::updateClientArea()
00196 {
00197 updateClientArea( false );
00198 }
00199
00200
00208 QRect Workspace::clientArea( clientAreaOption opt, const QPoint& p, int desktop ) const
00209 {
00210 if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 )
00211 desktop = currentDesktop();
00212 QDesktopWidget *desktopwidget = KApplication::desktop();
00213 int screen = desktopwidget->screenNumber( p );
00214 if( screen < 0 )
00215 screen = desktopwidget->primaryScreen();
00216 QRect sarea = screenarea
00217 ? screenarea[ desktop ][ screen ]
00218 : desktopwidget->screenGeometry( screen );
00219 QRect warea = workarea[ desktop ].isNull()
00220 ? QApplication::desktop()->geometry()
00221 : workarea[ desktop ];
00222 switch (opt)
00223 {
00224 case MaximizeArea:
00225 if (options->xineramaMaximizeEnabled)
00226 return sarea;
00227 else
00228 return warea;
00229 case MaximizeFullArea:
00230 if (options->xineramaMaximizeEnabled)
00231 return desktopwidget->screenGeometry( screen );
00232 else
00233 return desktopwidget->geometry();
00234 case FullScreenArea:
00235 if (options->xineramaFullscreenEnabled)
00236 return desktopwidget->screenGeometry( screen );
00237 else
00238 return desktopwidget->geometry();
00239 case PlacementArea:
00240 if (options->xineramaPlacementEnabled)
00241 return sarea;
00242 else
00243 return warea;
00244 case MovementArea:
00245 if (options->xineramaMovementEnabled)
00246 return desktopwidget->screenGeometry( screen );
00247 else
00248 return desktopwidget->geometry();
00249 case WorkArea:
00250 return warea;
00251 case FullXineramaArea:
00252 case FullArea:
00253 return desktopwidget->geometry();
00254 case ScreenArea:
00255 return sarea;
00256 }
00257 assert( false );
00258 return QRect();
00259 }
00260
00261 QRect Workspace::clientArea( clientAreaOption opt, const Client* c ) const
00262 {
00263 return clientArea( opt, c->geometry().center(), c->desktop());
00264 }
00265
00271 QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
00272 {
00273
00274
00275
00276 if (options->windowSnapZone || options->borderSnapZone )
00277 {
00278 const bool sOWO=options->snapOnlyWhenOverlapping;
00279 const QRect maxRect = clientArea(MovementArea, pos+c->rect().center(), c->desktop());
00280 const int xmin = maxRect.left();
00281 const int xmax = maxRect.right()+1;
00282 const int ymin = maxRect.top();
00283 const int ymax = maxRect.bottom()+1;
00284
00285 const int cx(pos.x());
00286 const int cy(pos.y());
00287 const int cw(c->width());
00288 const int ch(c->height());
00289 const int rx(cx+cw);
00290 const int ry(cy+ch);
00291
00292 int nx(cx), ny(cy);
00293 int deltaX(xmax);
00294 int deltaY(ymax);
00295
00296 int lx, ly, lrx, lry;
00297
00298
00299 int snap = options->borderSnapZone;
00300 if (snap)
00301 {
00302 if ((sOWO?(cx<xmin):true) && (QABS(xmin-cx)<snap))
00303 {
00304 deltaX = xmin-cx;
00305 nx = xmin;
00306 }
00307 if ((sOWO?(rx>xmax):true) && (QABS(rx-xmax)<snap) && (QABS(xmax-rx) < deltaX))
00308 {
00309 deltaX = rx-xmax;
00310 nx = xmax - cw;
00311 }
00312
00313 if ((sOWO?(cy<ymin):true) && (QABS(ymin-cy)<snap))
00314 {
00315 deltaY = ymin-cy;
00316 ny = ymin;
00317 }
00318 if ((sOWO?(ry>ymax):true) && (QABS(ry-ymax)<snap) && (QABS(ymax-ry) < deltaY))
00319 {
00320 deltaY =ry-ymax;
00321 ny = ymax - ch;
00322 }
00323 }
00324
00325
00326 snap = options->windowSnapZone;
00327 if (snap)
00328 {
00329 QValueList<Client *>::ConstIterator l;
00330 for (l = clients.begin();l != clients.end();++l )
00331 {
00332 if ((*l)->isOnDesktop(currentDesktop()) &&
00333 !(*l)->isMinimized()
00334 && (*l) != c )
00335 {
00336 lx = (*l)->x();
00337 ly = (*l)->y();
00338 lrx = lx + (*l)->width();
00339 lry = ly + (*l)->height();
00340
00341 if ( (( cy <= lry ) && ( cy >= ly )) ||
00342 (( ry >= ly ) && ( ry <= lry )) ||
00343 (( cy <= ly ) && ( ry >= lry )) )
00344 {
00345 if ((sOWO?(cx<lrx):true) && (QABS(lrx-cx)<snap) && ( QABS(lrx -cx) < deltaX) )
00346 {
00347 deltaX = QABS( lrx - cx );
00348 nx = lrx;
00349 }
00350 if ((sOWO?(rx>lx):true) && (QABS(rx-lx)<snap) && ( QABS( rx - lx )<deltaX) )
00351 {
00352 deltaX = QABS(rx - lx);
00353 nx = lx - cw;
00354 }
00355 }
00356
00357 if ( (( cx <= lrx ) && ( cx >= lx )) ||
00358 (( rx >= lx ) && ( rx <= lrx )) ||
00359 (( cx <= lx ) && ( rx >= lrx )) )
00360 {
00361 if ((sOWO?(cy<lry):true) && (QABS(lry-cy)<snap) && (QABS( lry -cy ) < deltaY))
00362 {
00363 deltaY = QABS( lry - cy );
00364 ny = lry;
00365 }
00366
00367 if ((sOWO?(ry>ly):true) && (QABS(ry-ly)<snap) && (QABS( ry - ly ) < deltaY ))
00368 {
00369 deltaY = QABS( ry - ly );
00370 ny = ly - ch;
00371 }
00372 }
00373 }
00374 }
00375 }
00376 pos = QPoint(nx, ny);
00377 }
00378 return pos;
00379 }
00380
00381 QRect Workspace::adjustClientSize( Client* c, QRect moveResizeGeom, int mode )
00382 {
00383
00384
00385
00386 if ( options->windowSnapZone || options->borderSnapZone )
00387 {
00388 const bool sOWO=options->snapOnlyWhenOverlapping;
00389
00390 const QRect maxRect = clientArea(MovementArea, c->rect().center(), c->desktop());
00391 const int xmin = maxRect.left();
00392 const int xmax = maxRect.right();
00393 const int ymin = maxRect.top();
00394 const int ymax = maxRect.bottom();
00395
00396 const int cx(moveResizeGeom.left());
00397 const int cy(moveResizeGeom.top());
00398 const int rx(moveResizeGeom.right());
00399 const int ry(moveResizeGeom.bottom());
00400
00401 int newcx(cx), newcy(cy);
00402 int newrx(rx), newry(ry);
00403 int deltaX(xmax);
00404 int deltaY(ymax);
00405
00406 int lx, ly, lrx, lry;
00407
00408
00409 int snap = options->borderSnapZone;
00410 if (snap)
00411 {
00412 deltaX = int(snap);
00413 deltaY = int(snap);
00414
00415 #define SNAP_BORDER_TOP \
00416 if ((sOWO?(newcy<ymin):true) && (QABS(ymin-newcy)<deltaY)) \
00417 { \
00418 deltaY = QABS(ymin-newcy); \
00419 newcy = ymin; \
00420 }
00421
00422 #define SNAP_BORDER_BOTTOM \
00423 if ((sOWO?(newry>ymax):true) && (QABS(ymax-newry)<deltaY)) \
00424 { \
00425 deltaY = QABS(ymax-newcy); \
00426 newry = ymax; \
00427 }
00428
00429 #define SNAP_BORDER_LEFT \
00430 if ((sOWO?(newcx<xmin):true) && (QABS(xmin-newcx)<deltaX)) \
00431 { \
00432 deltaX = QABS(xmin-newcx); \
00433 newcx = xmin; \
00434 }
00435
00436 #define SNAP_BORDER_RIGHT \
00437 if ((sOWO?(newrx>xmax):true) && (QABS(xmax-newrx)<deltaX)) \
00438 { \
00439 deltaX = QABS(xmax-newrx); \
00440 newrx = xmax; \
00441 }
00442 switch ( mode )
00443 {
00444 case PositionBottomRight:
00445 SNAP_BORDER_BOTTOM
00446 SNAP_BORDER_RIGHT
00447 break;
00448 case PositionRight:
00449 SNAP_BORDER_RIGHT
00450 break;
00451 case PositionBottom:
00452 SNAP_BORDER_BOTTOM
00453 break;
00454 case PositionTopLeft:
00455 SNAP_BORDER_TOP
00456 SNAP_BORDER_LEFT
00457 break;
00458 case PositionLeft:
00459 SNAP_BORDER_LEFT
00460 break;
00461 case PositionTop:
00462 SNAP_BORDER_TOP
00463 break;
00464 case PositionTopRight:
00465 SNAP_BORDER_TOP
00466 SNAP_BORDER_RIGHT
00467 break;
00468 case PositionBottomLeft:
00469 SNAP_BORDER_BOTTOM
00470 SNAP_BORDER_LEFT
00471 break;
00472 default:
00473 assert( false );
00474 break;
00475 }
00476
00477
00478 }
00479
00480
00481 snap = options->windowSnapZone;
00482 if (snap)
00483 {
00484 deltaX = int(snap);
00485 deltaY = int(snap);
00486 QValueList<Client *>::ConstIterator l;
00487 for (l = clients.begin();l != clients.end();++l )
00488 {
00489 if ((*l)->isOnDesktop(currentDesktop()) &&
00490 !(*l)->isMinimized()
00491 && (*l) != c )
00492 {
00493 lx = (*l)->x()-1;
00494 ly = (*l)->y()-1;
00495 lrx =(*l)->x() + (*l)->width();
00496 lry =(*l)->y() + (*l)->height();
00497
00498 #define WITHIN_HEIGHT ((( newcy <= lry ) && ( newcy >= ly )) || \
00499 (( newry >= ly ) && ( newry <= lry )) || \
00500 (( newcy <= ly ) && ( newry >= lry )) )
00501
00502 #define WITHIN_WIDTH ( (( cx <= lrx ) && ( cx >= lx )) || \
00503 (( rx >= lx ) && ( rx <= lrx )) || \
00504 (( cx <= lx ) && ( rx >= lrx )) )
00505
00506 #define SNAP_WINDOW_TOP if ( (sOWO?(newcy<lry):true) \
00507 && WITHIN_WIDTH \
00508 && (QABS( lry - newcy ) < deltaY) ) { \
00509 deltaY = QABS( lry - newcy ); \
00510 newcy=lry; \
00511 }
00512
00513 #define SNAP_WINDOW_BOTTOM if ( (sOWO?(newry>ly):true) \
00514 && WITHIN_WIDTH \
00515 && (QABS( ly - newry ) < deltaY) ) { \
00516 deltaY = QABS( ly - newry ); \
00517 newry=ly; \
00518 }
00519
00520 #define SNAP_WINDOW_LEFT if ( (sOWO?(newcx<lrx):true) \
00521 && WITHIN_HEIGHT \
00522 && (QABS( lrx - newcx ) < deltaX)) { \
00523 deltaX = QABS( lrx - newcx ); \
00524 newcx=lrx; \
00525 }
00526
00527 #define SNAP_WINDOW_RIGHT if ( (sOWO?(newrx>lx):true) \
00528 && WITHIN_HEIGHT \
00529 && (QABS( lx - newrx ) < deltaX)) \
00530 { \
00531 deltaX = QABS( lx - newrx ); \
00532 newrx=lx; \
00533 }
00534
00535 switch ( mode )
00536 {
00537 case PositionBottomRight:
00538 SNAP_WINDOW_BOTTOM
00539 SNAP_WINDOW_RIGHT
00540 break;
00541 case PositionRight:
00542 SNAP_WINDOW_RIGHT
00543 break;
00544 case PositionBottom:
00545 SNAP_WINDOW_BOTTOM
00546 break;
00547 case PositionTopLeft:
00548 SNAP_WINDOW_TOP
00549 SNAP_WINDOW_LEFT
00550 break;
00551 case PositionLeft:
00552 SNAP_WINDOW_LEFT
00553 break;
00554 case PositionTop:
00555 SNAP_WINDOW_TOP
00556 break;
00557 case PositionTopRight:
00558 SNAP_WINDOW_TOP
00559 SNAP_WINDOW_RIGHT
00560 break;
00561 case PositionBottomLeft:
00562 SNAP_WINDOW_BOTTOM
00563 SNAP_WINDOW_LEFT
00564 break;
00565 default:
00566 assert( false );
00567 break;
00568 }
00569 }
00570 }
00571 }
00572 moveResizeGeom = QRect(QPoint(newcx, newcy), QPoint(newrx, newry));
00573 }
00574 return moveResizeGeom;
00575 }
00576
00580 void Workspace::setClientIsMoving( Client *c )
00581 {
00582 Q_ASSERT(!c || !movingClient);
00583
00584 movingClient = c;
00585 if (movingClient)
00586 ++block_focus;
00587 else
00588 --block_focus;
00589 }
00590
00594 void Workspace::cascadeDesktop()
00595 {
00596
00597 Q_ASSERT( block_stacking_updates == 0 );
00598 ClientList::ConstIterator it(stackingOrder().begin());
00599 initPositioning->reinitCascading( currentDesktop());
00600 QRect area = clientArea( PlacementArea, QPoint( 0, 0 ), currentDesktop());
00601 for (; it != stackingOrder().end(); ++it)
00602 {
00603 if((!(*it)->isOnDesktop(currentDesktop())) ||
00604 ((*it)->isMinimized()) ||
00605 ((*it)->isOnAllDesktops()) ||
00606 (!(*it)->isMovable()) )
00607 continue;
00608 initPositioning->placeCascaded(*it, area);
00609 }
00610 }
00611
00616 void Workspace::unclutterDesktop()
00617 {
00618 ClientList::Iterator it(clients.fromLast());
00619 for (; it != clients.end(); --it)
00620 {
00621 if((!(*it)->isOnDesktop(currentDesktop())) ||
00622 ((*it)->isMinimized()) ||
00623 ((*it)->isOnAllDesktops()) ||
00624 (!(*it)->isMovable()) )
00625 continue;
00626 initPositioning->placeSmart(*it, QRect());
00627 }
00628 }
00629
00630
00631 void Workspace::updateTopMenuGeometry( Client* c )
00632 {
00633 if( !managingTopMenus())
00634 return;
00635 if( c != NULL )
00636 {
00637 XEvent ev;
00638 ev.xclient.display = qt_xdisplay();
00639 ev.xclient.type = ClientMessage;
00640 ev.xclient.window = c->window();
00641 static Atom msg_type_atom = XInternAtom( qt_xdisplay(), "_KDE_TOPMENU_MINSIZE", False );
00642 ev.xclient.message_type = msg_type_atom;
00643 ev.xclient.format = 32;
00644 ev.xclient.data.l[0] = qt_x_time;
00645 ev.xclient.data.l[1] = topmenu_space->width();
00646 ev.xclient.data.l[2] = topmenu_space->height();
00647 ev.xclient.data.l[3] = 0;
00648 ev.xclient.data.l[4] = 0;
00649 XSendEvent( qt_xdisplay(), c->window(), False, NoEventMask, &ev );
00650 KWin::setStrut( c->window(), 0, 0, topmenu_height, 0 );
00651 c->checkWorkspacePosition();
00652 return;
00653 }
00654
00655 QRect area;
00656 area = clientArea( MaximizeFullArea, QPoint( 0, 0 ), 1 );
00657 area.setHeight( topMenuHeight());
00658 topmenu_space->setGeometry( area );
00659 for( ClientList::ConstIterator it = topmenus.begin();
00660 it != topmenus.end();
00661 ++it )
00662 updateTopMenuGeometry( *it );
00663 }
00664
00665
00666
00667
00668
00669
00670 void Client::keepInArea( QRect area, bool partial )
00671 {
00672 if( partial )
00673 {
00674
00675 area.setLeft( QMIN( area.left() - width() + 100, area.left()));
00676 area.setTop( QMIN( area.top() - height() + 100, area.top()));
00677 area.setRight( QMAX( area.right() + width() - 100, area.right()));
00678 area.setBottom( QMAX( area.bottom() + height() - 100, area.bottom()));
00679 }
00680 if ( geometry().right() > area.right() && width() < area.width() )
00681 move( area.right() - width(), y() );
00682 if ( geometry().bottom() > area.bottom() && height() < area.height() )
00683 move( x(), area.bottom() - height() );
00684 if( !area.contains( geometry().topLeft() ))
00685 {
00686 int tx = x();
00687 int ty = y();
00688 if ( tx < area.x() )
00689 tx = area.x();
00690 if ( ty < area.y() )
00691 ty = area.y();
00692 move( tx, ty );
00693 }
00694 }
00695
00701
00702
00703 QRect Client::adjustedClientArea( const QRect &desktopArea, const QRect& area ) const
00704 {
00705 QRect r = area;
00706
00707 if( isTopMenu())
00708 return r;
00709 NETExtendedStrut str = strut();
00710 QRect stareaL = QRect(
00711 0,
00712 str . left_start,
00713 str . left_width,
00714 str . left_end - str . left_start + 1 );
00715 QRect stareaR = QRect (
00716 desktopArea . right () - str . right_width + 1,
00717 str . right_start,
00718 str . right_width,
00719 str . right_end - str . right_start + 1 );
00720 QRect stareaT = QRect (
00721 str . top_start,
00722 0,
00723 str . top_end - str . top_start + 1,
00724 str . top_width);
00725 QRect stareaB = QRect (
00726 str . bottom_start,
00727 desktopArea . bottom () - str . bottom_width + 1,
00728 str . bottom_end - str . bottom_start + 1,
00729 str . bottom_width);
00730
00731 NETExtendedStrut ext = info->extendedStrut();
00732 if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
00733 && ( str.left_width != 0 || str.right_width != 0 || str.top_width != 0 || str.bottom_width != 0 )) {
00734
00735
00736
00737
00738
00739
00740
00741 if (stareaT.top() == geometry().top() && stareaT.bottom() == geometry().bottom()) {
00742 stareaT.setLeft(geometry().left());
00743 stareaT.setRight(geometry().right());
00744
00745 }
00746 if (stareaB.top() == geometry().top() && stareaB.bottom() == geometry().bottom()) {
00747 stareaB.setLeft(geometry().left());
00748 stareaB.setRight(geometry().right());
00749
00750 }
00751 if (stareaL.left() == geometry().left() && stareaL.right() == geometry().right()) {
00752 stareaL.setTop(geometry().top());
00753 stareaL.setBottom(geometry().bottom());
00754
00755 }
00756 if (stareaR.left() == geometry().left() && stareaR.right() == geometry().right()) {
00757 stareaR.setTop(geometry().top());
00758 stareaR.setBottom(geometry().bottom());
00759
00760 }
00761 }
00762 if (stareaL . intersects (area)) {
00763
00764 r . setLeft( stareaL . right() + 1 );
00765 }
00766 if (stareaR . intersects (area)) {
00767
00768 r . setRight( stareaR . left() - 1 );
00769 }
00770 if (stareaT . intersects (area)) {
00771
00772 r . setTop( stareaT . bottom() + 1 );
00773 }
00774 if (stareaB . intersects (area)) {
00775
00776 r . setBottom( stareaB . top() - 1 );
00777 }
00778 return r;
00779 }
00780
00781 NETExtendedStrut Client::strut() const
00782 {
00783 NETExtendedStrut ext = info->extendedStrut();
00784 NETStrut str = info->strut();
00785 if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
00786 && ( str.left != 0 || str.right != 0 || str.top != 0 || str.bottom != 0 ))
00787 {
00788
00789 if( str.left != 0 )
00790 {
00791 ext.left_width = str.left;
00792 ext.left_start = 0;
00793 ext.left_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00794 }
00795 if( str.right != 0 )
00796 {
00797 ext.right_width = str.right;
00798 ext.right_start = 0;
00799 ext.right_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00800 }
00801 if( str.top != 0 )
00802 {
00803 ext.top_width = str.top;
00804 ext.top_start = 0;
00805 ext.top_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00806 }
00807 if( str.bottom != 0 )
00808 {
00809 ext.bottom_width = str.bottom;
00810 ext.bottom_start = 0;
00811 ext.bottom_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00812 }
00813 }
00814 return ext;
00815 }
00816 bool Client::hasStrut() const
00817 {
00818 NETExtendedStrut ext = strut();
00819 if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0 )
00820 {
00821 return false;
00822 }
00823 return true;
00824 }
00825
00826
00827
00828 void Client::updateWorkareaDiffs()
00829 {
00830 QRect area = workspace()->clientArea( WorkArea, this );
00831 QRect geom = geometry();
00832 workarea_diff_x = computeWorkareaDiff( geom.left(), geom.right(), area.left(), area.right());
00833 workarea_diff_y = computeWorkareaDiff( geom.top(), geom.bottom(), area.top(), area.bottom());
00834 }
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844 int Client::computeWorkareaDiff( int left, int right, int a_left, int a_right )
00845 {
00846 int left_diff = left - a_left;
00847 int right_diff = a_right - right;
00848 if( left_diff < 0 || right_diff < 0 )
00849 return INT_MIN;
00850 else
00851 {
00852
00853 int max_diff = ( a_right - a_left ) / 10;
00854 if( left_diff < right_diff )
00855 return left_diff < max_diff ? -left_diff - 1 : INT_MAX;
00856 else if( left_diff > right_diff )
00857 return right_diff < max_diff ? right_diff + 1 : INT_MAX;
00858 return INT_MAX;
00859 }
00860 }
00861
00862 void Client::checkWorkspacePosition()
00863 {
00864 if( isDesktop())
00865 {
00866 QRect area = workspace()->clientArea( FullArea, this );
00867 if( geometry() != area )
00868 setGeometry( area );
00869 return;
00870 }
00871 if( maximizeMode() != MaximizeRestore )
00872
00873 changeMaximize( false, false, true );
00874
00875 if( isFullScreen())
00876 {
00877 QRect area = workspace()->clientArea( FullScreenArea, this );
00878 if( geometry() != area )
00879 setGeometry( area );
00880 return;
00881 }
00882 if( isDock())
00883 return;
00884 if( isTopMenu())
00885 {
00886 if( workspace()->managingTopMenus())
00887 {
00888 QRect area;
00889 ClientList mainclients = mainClients();
00890 if( mainclients.count() == 1 )
00891 area = workspace()->clientArea( MaximizeFullArea, mainclients.first());
00892 else
00893 area = workspace()->clientArea( MaximizeFullArea, QPoint( 0, 0 ), desktop());
00894 area.setHeight( workspace()->topMenuHeight());
00895
00896 setGeometry( area );
00897 }
00898 return;
00899 }
00900
00901 if( !isShade())
00902 {
00903 int old_diff_x = workarea_diff_x;
00904 int old_diff_y = workarea_diff_y;
00905 updateWorkareaDiffs();
00906
00907
00908
00909
00910
00911
00912 if( workspace()->initializing())
00913 return;
00914
00915 QRect area = workspace()->clientArea( WorkArea, this );
00916 QRect new_geom = geometry();
00917 QRect tmp_rect_x( new_geom.left(), 0, new_geom.width(), 0 );
00918 QRect tmp_area_x( area.left(), 0, area.width(), 0 );
00919 checkDirection( workarea_diff_x, old_diff_x, tmp_rect_x, tmp_area_x );
00920
00921 QRect tmp_rect_y( new_geom.top(), 0, new_geom.height(), 0 );
00922 QRect tmp_area_y( area.top(), 0, area.height(), 0 );
00923 checkDirection( workarea_diff_y, old_diff_y, tmp_rect_y, tmp_area_y );
00924 new_geom = QRect( tmp_rect_x.left(), tmp_rect_y.left(), tmp_rect_x.width(), tmp_rect_y.width());
00925 QRect final_geom( new_geom.topLeft(), adjustedSize( new_geom.size()));
00926 if( final_geom != new_geom )
00927 {
00928 if( old_diff_x != INT_MAX && old_diff_x > 0 )
00929 final_geom.moveRight( area.right() - ( old_diff_x - 1 ));
00930 if( old_diff_y != INT_MAX && old_diff_y > 0 )
00931 final_geom.moveBottom( area.bottom() - ( old_diff_y - 1 ));
00932 }
00933 if( final_geom != geometry() )
00934 setGeometry( final_geom );
00935
00936 }
00937 }
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949 void Client::checkDirection( int new_diff, int old_diff, QRect& rect, const QRect& area )
00950 {
00951 if( old_diff != INT_MIN )
00952 {
00953 if( old_diff == INT_MAX )
00954 {
00955 if( new_diff == INT_MIN )
00956 {
00957 rect.setLeft( area.left());
00958 rect.setRight( area.right());
00959 }
00960 return;
00961 }
00962 if( isMovable())
00963 {
00964 if( old_diff < 0 )
00965 rect.moveLeft( area.left() + ( -old_diff - 1 ));
00966 else
00967 rect.moveRight( area.right() - ( old_diff - 1 ));
00968 }
00969 else if( isResizable())
00970 {
00971 if( old_diff < 0 )
00972 rect.setLeft( area.left() + ( -old_diff - 1 ) );
00973 else
00974 rect.setRight( area.right() - ( old_diff - 1 ));
00975 }
00976 if( rect.width() > area.width() && isResizable())
00977 rect.setWidth( area.width());
00978 if( isMovable())
00979 {
00980 if( rect.left() < area.left())
00981 rect.moveLeft( area.left());
00982 else if( rect.right() > area.right())
00983 rect.moveRight( area.right());
00984 }
00985 }
00986 if( rect.right() < area.left() + 5 || rect.left() > area.right() - 5 )
00987 {
00988 if( isMovable())
00989 {
00990 if( rect.left() < area.left() + 5 )
00991 rect.moveRight( area.left() + 5 );
00992 if( rect.right() > area.right() - 5 )
00993 rect.moveLeft( area.right() - 5 );
00994 }
00995 }
00996 }
00997
01001 QSize Client::adjustedSize( const QSize& frame, Sizemode mode ) const
01002 {
01003
01004
01005 QSize wsize( frame.width() - ( border_left + border_right ),
01006 frame.height() - ( border_top + border_bottom ));
01007
01008 return sizeForClientSize( wsize, mode, false );
01009 }
01010
01011
01012
01013 QSize Client::adjustedSize() const
01014 {
01015 return sizeForClientSize( clientSize());
01016 }
01017
01026 QSize Client::sizeForClientSize( const QSize& wsize, Sizemode mode, bool noframe ) const
01027 {
01028 int w = wsize.width();
01029 int h = wsize.height();
01030 if( w < 1 || h < 1 )
01031 {
01032 kdWarning() << "sizeForClientSize() with empty size!" << endl;
01033 kdWarning() << kdBacktrace() << endl;
01034 }
01035 if (w<1) w = 1;
01036 if (h<1) h = 1;
01037
01038
01039
01040 QSize min_size = minSize();
01041 QSize max_size = maxSize();
01042 if( decoration != NULL )
01043 {
01044 QSize decominsize = decoration->minimumSize();
01045 QSize border_size( border_left + border_right, border_top + border_bottom );
01046 if( border_size.width() > decominsize.width())
01047 decominsize.setWidth( border_size.width());
01048 if( border_size.height() > decominsize.height())
01049 decominsize.setHeight( border_size.height());
01050 if( decominsize.width() > min_size.width())
01051 min_size.setWidth( decominsize.width());
01052 if( decominsize.height() > min_size.height())
01053 min_size.setHeight( decominsize.height());
01054 }
01055 w = QMIN( max_size.width(), w );
01056 h = QMIN( max_size.height(), h );
01057 w = QMAX( min_size.width(), w );
01058 h = QMAX( min_size.height(), h );
01059
01060 int w1 = w;
01061 int h1 = h;
01062 int width_inc = xSizeHint.width_inc;
01063 int height_inc = xSizeHint.height_inc;
01064 int basew_inc = xSizeHint.min_width;
01065 int baseh_inc = xSizeHint.min_height;
01066 w = int(( w - basew_inc ) / width_inc ) * width_inc + basew_inc;
01067 h = int(( h - baseh_inc ) / height_inc ) * height_inc + baseh_inc;
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083 if( xSizeHint.flags & PAspect )
01084 {
01085 double min_aspect_w = xSizeHint.min_aspect.x;
01086 double min_aspect_h = xSizeHint.min_aspect.y;
01087 double max_aspect_w = xSizeHint.max_aspect.x;
01088 double max_aspect_h = xSizeHint.max_aspect.y;
01089
01090
01091
01092 w -= xSizeHint.base_width;
01093 h -= xSizeHint.base_height;
01094 int max_width = max_size.width() - xSizeHint.base_width;
01095 int min_width = min_size.width() - xSizeHint.base_width;
01096 int max_height = max_size.height() - xSizeHint.base_height;
01097 int min_height = min_size.height() - xSizeHint.base_height;
01098 #define ASPECT_CHECK_GROW_W \
01099 if( min_aspect_w * h > min_aspect_h * w ) \
01100 { \
01101 int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \
01102 if( w + delta <= max_width ) \
01103 w += delta; \
01104 }
01105 #define ASPECT_CHECK_SHRINK_H_GROW_W \
01106 if( min_aspect_w * h > min_aspect_h * w ) \
01107 { \
01108 int delta = int( h - w * min_aspect_h / min_aspect_w ) / height_inc * height_inc; \
01109 if( h - delta >= min_height ) \
01110 h -= delta; \
01111 else \
01112 { \
01113 int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \
01114 if( w + delta <= max_width ) \
01115 w += delta; \
01116 } \
01117 }
01118 #define ASPECT_CHECK_GROW_H \
01119 if( max_aspect_w * h < max_aspect_h * w ) \
01120 { \
01121 int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \
01122 if( h + delta <= max_height ) \
01123 h += delta; \
01124 }
01125 #define ASPECT_CHECK_SHRINK_W_GROW_H \
01126 if( max_aspect_w * h < max_aspect_h * w ) \
01127 { \
01128 int delta = int( w - max_aspect_w * h / max_aspect_h ) / width_inc * width_inc; \
01129 if( w - delta >= min_width ) \
01130 w -= delta; \
01131 else \
01132 { \
01133 int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \
01134 if( h + delta <= max_height ) \
01135 h += delta; \
01136 } \
01137 }
01138 switch( mode )
01139 {
01140 case SizemodeAny:
01141 #if 0 // make SizemodeAny equal to SizemodeFixedW - prefer keeping fixed width,
01142
01143 {
01144 ASPECT_CHECK_SHRINK_H_GROW_W
01145 ASPECT_CHECK_SHRINK_W_GROW_H
01146 ASPECT_CHECK_GROW_H
01147 ASPECT_CHECK_GROW_W
01148 break;
01149 }
01150 #endif
01151 case SizemodeFixedW:
01152 {
01153
01154 ASPECT_CHECK_GROW_H
01155 ASPECT_CHECK_SHRINK_H_GROW_W
01156 ASPECT_CHECK_SHRINK_W_GROW_H
01157 ASPECT_CHECK_GROW_W
01158 break;
01159 }
01160 case SizemodeFixedH:
01161 {
01162 ASPECT_CHECK_GROW_W
01163 ASPECT_CHECK_SHRINK_W_GROW_H
01164 ASPECT_CHECK_SHRINK_H_GROW_W
01165 ASPECT_CHECK_GROW_H
01166 break;
01167 }
01168 case SizemodeMax:
01169 {
01170
01171 ASPECT_CHECK_SHRINK_H_GROW_W
01172 ASPECT_CHECK_SHRINK_W_GROW_H
01173 ASPECT_CHECK_GROW_W
01174 ASPECT_CHECK_GROW_H
01175 break;
01176 }
01177 }
01178 #undef ASPECT_CHECK_SHRINK_H_GROW_W
01179 #undef ASPECT_CHECK_SHRINK_W_GROW_H
01180 #undef ASPECT_CHECK_GROW_W
01181 #undef ASPECT_CHECK_GROW_H
01182 w += xSizeHint.base_width;
01183 h += xSizeHint.base_height;
01184 }
01185 if( !rules()->checkStrictGeometry( false ))
01186 {
01187
01188 if( maximizeMode() & MaximizeHorizontal )
01189 w = w1;
01190 if( maximizeMode() & MaximizeVertical )
01191 h = h1;
01192 }
01193
01194 if( !noframe )
01195 {
01196 w += border_left + border_right;
01197 h += border_top + border_bottom;
01198 }
01199 return rules()->checkSize( QSize( w, h ));
01200 }
01201
01205 void Client::getWmNormalHints()
01206 {
01207 long msize;
01208 if (XGetWMNormalHints(qt_xdisplay(), window(), &xSizeHint, &msize) == 0 )
01209 xSizeHint.flags = 0;
01210
01211
01212 if( xSizeHint.flags & PBaseSize )
01213 {
01214
01215
01216
01217 if( ! ( xSizeHint.flags & PMinSize ))
01218 {
01219 xSizeHint.min_width = xSizeHint.base_width;
01220 xSizeHint.min_height = xSizeHint.base_height;
01221 }
01222 }
01223 else
01224 xSizeHint.base_width = xSizeHint.base_height = 0;
01225 if( ! ( xSizeHint.flags & PMinSize ))
01226 xSizeHint.min_width = xSizeHint.min_height = 0;
01227 if( ! ( xSizeHint.flags & PMaxSize ))
01228 xSizeHint.max_width = xSizeHint.max_height = INT_MAX;
01229 else
01230 {
01231 xSizeHint.max_width = QMAX( xSizeHint.max_width, 1 );
01232 xSizeHint.max_height = QMAX( xSizeHint.max_height, 1 );
01233 }
01234 if( xSizeHint.flags & PResizeInc )
01235 {
01236 xSizeHint.width_inc = kMax( xSizeHint.width_inc, 1 );
01237 xSizeHint.height_inc = kMax( xSizeHint.height_inc, 1 );
01238 }
01239 else
01240 {
01241 xSizeHint.width_inc = 1;
01242 xSizeHint.height_inc = 1;
01243 }
01244 if( xSizeHint.flags & PAspect )
01245 {
01246 xSizeHint.min_aspect.y = kMax( xSizeHint.min_aspect.y, 1 );
01247 xSizeHint.max_aspect.y = kMax( xSizeHint.max_aspect.y, 1 );
01248 }
01249 else
01250 {
01251 xSizeHint.min_aspect.x = 1;
01252 xSizeHint.min_aspect.y = INT_MAX;
01253 xSizeHint.max_aspect.x = INT_MAX;
01254 xSizeHint.max_aspect.y = 1;
01255 }
01256 if( ! ( xSizeHint.flags & PWinGravity ))
01257 xSizeHint.win_gravity = NorthWestGravity;
01258 if( isManaged())
01259 {
01260 QSize new_size = adjustedSize();
01261 if( new_size != size() && !isFullScreen())
01262 resizeWithChecks( new_size );
01263 }
01264 updateAllowedActions();
01265 }
01266
01267 QSize Client::minSize() const
01268 {
01269 return rules()->checkMinSize( QSize( xSizeHint.min_width, xSizeHint.min_height ));
01270 }
01271
01272 QSize Client::maxSize() const
01273 {
01274 return rules()->checkMaxSize( QSize( xSizeHint.max_width, xSizeHint.max_height ));
01275 }
01276
01282 void Client::sendSyntheticConfigureNotify()
01283 {
01284 XConfigureEvent c;
01285 c.type = ConfigureNotify;
01286 c.send_event = True;
01287 c.event = window();
01288 c.window = window();
01289 c.x = x() + clientPos().x();
01290 c.y = y() + clientPos().y();
01291 c.width = clientSize().width();
01292 c.height = clientSize().height();
01293 c.border_width = 0;
01294 c.above = None;
01295 c.override_redirect = 0;
01296 XSendEvent( qt_xdisplay(), c.event, TRUE, StructureNotifyMask, (XEvent*)&c );
01297 }
01298
01299 const QPoint Client::calculateGravitation( bool invert, int gravity ) const
01300 {
01301 int dx, dy;
01302 dx = dy = 0;
01303
01304 if( gravity == 0 )
01305 gravity = xSizeHint.win_gravity;
01306
01307
01308 switch (gravity)
01309 {
01310 case NorthWestGravity:
01311 default:
01312 dx = border_left;
01313 dy = border_top;
01314 break;
01315 case NorthGravity:
01316 dx = 0;
01317 dy = border_top;
01318 break;
01319 case NorthEastGravity:
01320 dx = -border_right;
01321 dy = border_top;
01322 break;
01323 case WestGravity:
01324 dx = border_left;
01325 dy = 0;
01326 break;
01327 case CenterGravity:
01328 break;
01329 case StaticGravity:
01330 dx = 0;
01331 dy = 0;
01332 break;
01333 case EastGravity:
01334 dx = -border_right;
01335 dy = 0;
01336 break;
01337 case SouthWestGravity:
01338 dx = border_left ;
01339 dy = -border_bottom;
01340 break;
01341 case SouthGravity:
01342 dx = 0;
01343 dy = -border_bottom;
01344 break;
01345 case SouthEastGravity:
01346 dx = -border_right;
01347 dy = -border_bottom;
01348 break;
01349 }
01350 if( gravity != CenterGravity )
01351 {
01352 dx -= border_left;
01353 dy -= border_top;
01354 }
01355 else
01356 {
01357 dx = - ( border_left + border_right ) / 2;
01358 dy = - ( border_top + border_bottom ) / 2;
01359 }
01360 if( !invert )
01361 return QPoint( x() + dx, y() + dy );
01362 else
01363 return QPoint( x() - dx, y() - dy );
01364 }
01365
01366 void Client::configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool )
01367 {
01368 if( gravity == 0 )
01369 gravity = xSizeHint.win_gravity;
01370 if( value_mask & ( CWX | CWY ))
01371 {
01372 QPoint new_pos = calculateGravitation( true, gravity );
01373 if ( value_mask & CWX )
01374 new_pos.setX( rx );
01375 if ( value_mask & CWY )
01376 new_pos.setY( ry );
01377
01378
01379
01380
01381
01382 if ( new_pos.x() == x() + clientPos().x() &&
01383 new_pos.y() == y() + clientPos().y() && gravity == NorthWestGravity )
01384 {
01385 new_pos.setX( x());
01386 new_pos.setY( y());
01387 }
01388
01389 int nw = clientSize().width();
01390 int nh = clientSize().height();
01391 if ( value_mask & CWWidth )
01392 nw = rw;
01393 if ( value_mask & CWHeight )
01394 nh = rh;
01395 QSize ns = sizeForClientSize( QSize( nw, nh ) );
01396
01397
01398 if ( maximizeMode() != MaximizeFull
01399 || ns != size())
01400 {
01401 QRect orig_geometry = geometry();
01402 GeometryUpdatesPostponer blocker( this );
01403 move( new_pos );
01404 plainResize( ns );
01405 setGeometry( QRect( calculateGravitation( false, gravity ), size()));
01406 updateFullScreenHack( QRect( new_pos, QSize( nw, nh )));
01407 QRect area = workspace()->clientArea( WorkArea, this );
01408 if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen()
01409 && area.contains( orig_geometry ))
01410 keepInArea( area );
01411
01412
01413
01414
01415
01416 if (hasStrut ())
01417 workspace() -> updateClientArea ();
01418 }
01419 }
01420
01421 if ( value_mask & (CWWidth | CWHeight )
01422 && ! ( value_mask & ( CWX | CWY )) )
01423 {
01424 int nw = clientSize().width();
01425 int nh = clientSize().height();
01426 if ( value_mask & CWWidth )
01427 nw = rw;
01428 if ( value_mask & CWHeight )
01429 nh = rh;
01430 QSize ns = sizeForClientSize( QSize( nw, nh ) );
01431
01432 if( ns != size())
01433 {
01434 QRect orig_geometry = geometry();
01435 GeometryUpdatesPostponer blocker( this );
01436 int save_gravity = xSizeHint.win_gravity;
01437 xSizeHint.win_gravity = gravity;
01438 resizeWithChecks( ns );
01439 xSizeHint.win_gravity = save_gravity;
01440 updateFullScreenHack( QRect( calculateGravitation( true, xSizeHint.win_gravity ), QSize( nw, nh )));
01441 QRect area = workspace()->clientArea( WorkArea, this );
01442 if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen()
01443 && area.contains( orig_geometry ))
01444 keepInArea( area );
01445 }
01446 }
01447
01448
01449
01450 }
01451
01452 void Client::resizeWithChecks( int w, int h, ForceGeometry_t force )
01453 {
01454 if( shade_geometry_change )
01455 assert( false );
01456 else if( isShade())
01457 {
01458 if( h == border_top + border_bottom )
01459 {
01460 kdWarning() << "Shaded geometry passed for size:" << endl;
01461 kdWarning() << kdBacktrace() << endl;
01462 }
01463 }
01464 int newx = x();
01465 int newy = y();
01466 QRect area = workspace()->clientArea( WorkArea, this );
01467
01468 if( w > area.width())
01469 w = area.width();
01470 if( h > area.height())
01471 h = area.height();
01472 QSize tmp = adjustedSize( QSize( w, h ));
01473 w = tmp.width();
01474 h = tmp.height();
01475 switch( xSizeHint.win_gravity )
01476 {
01477 case NorthWestGravity:
01478 default:
01479 break;
01480 case NorthGravity:
01481 newx = ( newx + width() / 2 ) - ( w / 2 );
01482 break;
01483 case NorthEastGravity:
01484 newx = newx + width() - w;
01485 break;
01486 case WestGravity:
01487 newy = ( newy + height() / 2 ) - ( h / 2 );
01488 break;
01489 case CenterGravity:
01490 newx = ( newx + width() / 2 ) - ( w / 2 );
01491 newy = ( newy + height() / 2 ) - ( h / 2 );
01492 break;
01493 case StaticGravity:
01494
01495 break;
01496 case EastGravity:
01497 newx = newx + width() - w;
01498 newy = ( newy + height() / 2 ) - ( h / 2 );
01499 break;
01500 case SouthWestGravity:
01501 newy = newy + height() - h;
01502 break;
01503 case SouthGravity:
01504 newx = ( newx + width() / 2 ) - ( w / 2 );
01505 newy = newy + height() - h;
01506 break;
01507 case SouthEastGravity:
01508 newx = newx + width() - w;
01509 newy = newy + height() - h;
01510 break;
01511 }
01512
01513
01514 if( workarea_diff_x != INT_MIN && w <= area.width())
01515 {
01516 if( newx < area.left())
01517 newx = area.left();
01518 if( newx + w > area.right() + 1 )
01519 newx = area.right() + 1 - w;
01520 assert( newx >= area.left() && newx + w <= area.right() + 1 );
01521 }
01522 if( workarea_diff_y != INT_MIN && h <= area.height())
01523 {
01524 if( newy < area.top())
01525 newy = area.top();
01526 if( newy + h > area.bottom() + 1 )
01527 newy = area.bottom() + 1 - h;
01528 assert( newy >= area.top() && newy + h <= area.bottom() + 1 );
01529 }
01530 setGeometry( newx, newy, w, h, force );
01531 }
01532
01533
01534 void Client::NETMoveResizeWindow( int flags, int x, int y, int width, int height )
01535 {
01536 int gravity = flags & 0xff;
01537 int value_mask = 0;
01538 if( flags & ( 1 << 8 ))
01539 value_mask |= CWX;
01540 if( flags & ( 1 << 9 ))
01541 value_mask |= CWY;
01542 if( flags & ( 1 << 10 ))
01543 value_mask |= CWWidth;
01544 if( flags & ( 1 << 11 ))
01545 value_mask |= CWHeight;
01546 configureRequest( value_mask, x, y, width, height, gravity, true );
01547 }
01548
01553 bool Client::isMovable() const
01554 {
01555 if( !motif_may_move || isFullScreen())
01556 return false;
01557 if( isSpecialWindow() && !isSplash() && !isToolbar())
01558 return false;
01559 if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01560 return false;
01561 if( rules()->checkPosition( invalidPoint ) != invalidPoint )
01562 return false;
01563 return true;
01564 }
01565
01569 bool Client::isResizable() const
01570 {
01571 if( !motif_may_resize || isFullScreen())
01572 return false;
01573 if( isSpecialWindow() )
01574 return false;
01575 if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01576 return false;
01577 if( rules()->checkSize( QSize()).isValid())
01578 return false;
01579
01580 QSize min = minSize();
01581 QSize max = maxSize();
01582 return min.width() < max.width() || min.height() < max.height();
01583 }
01584
01585
01586
01587
01588 bool Client::isMaximizable() const
01589 {
01590 {
01591
01592 TemporaryAssign< MaximizeMode > tmp( max_mode, MaximizeRestore );
01593 if( !isMovable() || !isResizable() || isToolbar())
01594 return false;
01595 }
01596 if ( maximizeMode() != MaximizeRestore )
01597 return TRUE;
01598 QSize max = maxSize();
01599 #if 0
01600 if( max.width() < 32767 || max.height() < 32767 )
01601 return false;
01602 #else
01603
01604
01605 QSize areasize = workspace()->clientArea( MaximizeArea, this ).size();
01606 if( max.width() < areasize.width() || max.height() < areasize.height())
01607 return false;
01608 #endif
01609 return true;
01610 }
01611
01612
01616 void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
01617 {
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629 if( shade_geometry_change )
01630 ;
01631 else if( isShade())
01632 {
01633 if( h == border_top + border_bottom )
01634 {
01635 kdDebug() << "Shaded geometry passed for size:" << endl;
01636 kdDebug() << kdBacktrace() << endl;
01637 }
01638 else
01639 {
01640 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01641 h = border_top + border_bottom;
01642 }
01643 }
01644 else
01645 {
01646 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01647 }
01648 if( force == NormalGeometrySet && frame_geometry == QRect( x, y, w, h ))
01649 return;
01650 frame_geometry = QRect( x, y, w, h );
01651 updateWorkareaDiffs();
01652 if( postpone_geometry_updates != 0 )
01653 {
01654 pending_geometry_update = true;
01655 return;
01656 }
01657 resizeDecoration( QSize( w, h ));
01658 XMoveResizeWindow( qt_xdisplay(), frameId(), x, y, w, h );
01659
01660 if( !isShade())
01661 {
01662 QSize cs = clientSize();
01663 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01664 cs.width(), cs.height());
01665 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01666 }
01667 if( shape())
01668 updateShape();
01669
01670 updateWorkareaDiffs();
01671 sendSyntheticConfigureNotify();
01672 updateWindowRules();
01673 checkMaximizeGeometry();
01674 }
01675
01676 void Client::plainResize( int w, int h, ForceGeometry_t force )
01677 {
01678
01679 if( shade_geometry_change )
01680 ;
01681 else if( isShade())
01682 {
01683 if( h == border_top + border_bottom )
01684 {
01685 kdDebug() << "Shaded geometry passed for size:" << endl;
01686 kdDebug() << kdBacktrace() << endl;
01687 }
01688 else
01689 {
01690 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01691 h = border_top + border_bottom;
01692 }
01693 }
01694 else
01695 {
01696 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01697 }
01698 if( QSize( w, h ) != rules()->checkSize( QSize( w, h )))
01699 {
01700 kdDebug() << "forced size fail:" << QSize( w,h ) << ":" << rules()->checkSize( QSize( w, h )) << endl;
01701 kdDebug() << kdBacktrace() << endl;
01702 }
01703 if( force == NormalGeometrySet && frame_geometry.size() == QSize( w, h ))
01704 return;
01705 frame_geometry.setSize( QSize( w, h ));
01706 updateWorkareaDiffs();
01707 if( postpone_geometry_updates != 0 )
01708 {
01709 pending_geometry_update = true;
01710 return;
01711 }
01712 resizeDecoration( QSize( w, h ));
01713 XResizeWindow( qt_xdisplay(), frameId(), w, h );
01714
01715 if( !isShade())
01716 {
01717 QSize cs = clientSize();
01718 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01719 cs.width(), cs.height());
01720 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01721 }
01722 if( shape())
01723 updateShape();
01724 updateWorkareaDiffs();
01725 sendSyntheticConfigureNotify();
01726 updateWindowRules();
01727 checkMaximizeGeometry();
01728 }
01729
01733 void Client::move( int x, int y, ForceGeometry_t force )
01734 {
01735 if( force == NormalGeometrySet && frame_geometry.topLeft() == QPoint( x, y ))
01736 return;
01737 frame_geometry.moveTopLeft( QPoint( x, y ));
01738 updateWorkareaDiffs();
01739 if( postpone_geometry_updates != 0 )
01740 {
01741 pending_geometry_update = true;
01742 return;
01743 }
01744 XMoveWindow( qt_xdisplay(), frameId(), x, y );
01745 sendSyntheticConfigureNotify();
01746 updateWindowRules();
01747 checkMaximizeGeometry();
01748 }
01749
01750
01751 void Client::postponeGeometryUpdates( bool postpone )
01752 {
01753 if( postpone )
01754 {
01755 if( postpone_geometry_updates == 0 )
01756 pending_geometry_update = false;
01757 ++postpone_geometry_updates;
01758 }
01759 else
01760 {
01761 if( --postpone_geometry_updates == 0 )
01762 {
01763 if( pending_geometry_update )
01764 {
01765 if( isShade())
01766 setGeometry( QRect( pos(), adjustedSize()), ForceGeometrySet );
01767 else
01768 setGeometry( geometry(), ForceGeometrySet );
01769 pending_geometry_update = false;
01770 }
01771 }
01772 }
01773 }
01774
01775 void Client::maximize( MaximizeMode m )
01776 {
01777 setMaximize( m & MaximizeVertical, m & MaximizeHorizontal );
01778 }
01779
01783 void Client::setMaximize( bool vertically, bool horizontally )
01784 {
01785 changeMaximize(
01786 max_mode & MaximizeVertical ? !vertically : vertically,
01787 max_mode & MaximizeHorizontal ? !horizontally : horizontally,
01788 false );
01789 }
01790
01791 void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
01792 {
01793 if( !isMaximizable())
01794 return;
01795
01796 MaximizeMode old_mode = max_mode;
01797
01798 if( !adjust )
01799 {
01800 if( vertical )
01801 max_mode = MaximizeMode( max_mode ^ MaximizeVertical );
01802 if( horizontal )
01803 max_mode = MaximizeMode( max_mode ^ MaximizeHorizontal );
01804 }
01805
01806 max_mode = rules()->checkMaximize( max_mode );
01807 if( !adjust && max_mode == old_mode )
01808 return;
01809
01810 GeometryUpdatesPostponer blocker( this );
01811
01812
01813 Q_ASSERT( !( vertical && horizontal )
01814 || (( max_mode & MaximizeVertical != 0 ) == ( max_mode & MaximizeHorizontal != 0 )));
01815
01816 QRect clientArea = workspace()->clientArea( MaximizeArea, this );
01817
01818
01819 if( !adjust && !( y() == clientArea.top() && height() == clientArea.height()))
01820 {
01821 geom_restore.setTop( y());
01822 geom_restore.setHeight( height());
01823 }
01824 if( !adjust && !( x() == clientArea.left() && width() == clientArea.width()))
01825 {
01826 geom_restore.setLeft( x());
01827 geom_restore.setWidth( width());
01828 }
01829
01830 if( !adjust )
01831 {
01832 if(( vertical && !(old_mode & MaximizeVertical ))
01833 || ( horizontal && !( old_mode & MaximizeHorizontal )))
01834 Notify::raise( Notify::Maximize );
01835 else
01836 Notify::raise( Notify::UnMaximize );
01837 }
01838
01839 if( decoration != NULL )
01840 decoration->borders( border_left, border_right, border_top, border_bottom );
01841
01842
01843 if ( old_mode==MaximizeFull && max_mode==MaximizeRestore )
01844 {
01845 if ( maximizeModeRestore()==MaximizeVertical )
01846 {
01847 max_mode = MaximizeVertical;
01848 maxmode_restore = MaximizeRestore;
01849 }
01850 if ( maximizeModeRestore()==MaximizeHorizontal )
01851 {
01852 max_mode = MaximizeHorizontal;
01853 maxmode_restore = MaximizeRestore;
01854 }
01855 }
01856
01857 switch (max_mode)
01858 {
01859
01860 case MaximizeVertical:
01861 {
01862 if( old_mode & MaximizeHorizontal )
01863 {
01864 if( geom_restore.width() == 0 )
01865 {
01866 plainResize( adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH ));
01867 workspace()->placeSmart( this, clientArea );
01868 }
01869 else
01870 setGeometry( QRect(QPoint( geom_restore.x(), clientArea.top()),
01871 adjustedSize(QSize( geom_restore.width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet);
01872 }
01873 else
01874 setGeometry( QRect(QPoint(x(), clientArea.top()),
01875 adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet);
01876 info->setState( NET::MaxVert, NET::Max );
01877 break;
01878 }
01879
01880 case MaximizeHorizontal:
01881 {
01882 if( old_mode & MaximizeVertical )
01883 {
01884 if( geom_restore.height() == 0 )
01885 {
01886 plainResize( adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW ));
01887 workspace()->placeSmart( this, clientArea );
01888 }
01889 else
01890 setGeometry( QRect( QPoint(clientArea.left(), geom_restore.y()),
01891 adjustedSize(QSize(clientArea.width(), geom_restore.height()), SizemodeFixedW )), ForceGeometrySet);
01892 }
01893 else
01894 setGeometry( QRect( QPoint(clientArea.left(), y()),
01895 adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW )), ForceGeometrySet);
01896 info->setState( NET::MaxHoriz, NET::Max );
01897 break;
01898 }
01899
01900 case MaximizeRestore:
01901 {
01902 QRect restore = geometry();
01903
01904 if( old_mode & MaximizeVertical )
01905 {
01906 restore.setTop( geom_restore.top());
01907 restore.setBottom( geom_restore.bottom());
01908 }
01909 if( old_mode & MaximizeHorizontal )
01910 {
01911 restore.setLeft( geom_restore.left());
01912 restore.setRight( geom_restore.right());
01913 }
01914 if( !restore.isValid())
01915 {
01916 QSize s = QSize( clientArea.width()*2/3, clientArea.height()*2/3 );
01917 if( geom_restore.width() > 0 )
01918 s.setWidth( geom_restore.width());
01919 if( geom_restore.height() > 0 )
01920 s.setHeight( geom_restore.height());
01921 plainResize( adjustedSize( s ));
01922 workspace()->placeSmart( this, clientArea );
01923 restore = geometry();
01924 if( geom_restore.width() > 0 )
01925 restore.moveLeft( geom_restore.x());
01926 if( geom_restore.height() > 0 )
01927 restore.moveTop( geom_restore.y());
01928 }
01929 setGeometry( restore, ForceGeometrySet );
01930 info->setState( 0, NET::Max );
01931 break;
01932 }
01933
01934 case MaximizeFull:
01935 {
01936 if( !adjust )
01937 {
01938 if( old_mode & MaximizeVertical )
01939 maxmode_restore = MaximizeVertical;
01940 if( old_mode & MaximizeHorizontal )
01941 maxmode_restore = MaximizeHorizontal;
01942 }
01943 QSize adjSize = adjustedSize(clientArea.size(), SizemodeMax );
01944 QRect r = QRect(clientArea.topLeft(), adjSize);
01945 setGeometry( r, ForceGeometrySet );
01946 info->setState( NET::Max, NET::Max );
01947 break;
01948 }
01949 default:
01950 break;
01951 }
01952
01953 updateAllowedActions();
01954 if( decoration != NULL )
01955 decoration->maximizeChange();
01956 updateWindowRules();
01957 }
01958
01959 void Client::resetMaximize()
01960 {
01961 if( max_mode == MaximizeRestore )
01962 return;
01963 max_mode = MaximizeRestore;
01964 Notify::raise( Notify::UnMaximize );
01965 info->setState( 0, NET::Max );
01966 updateAllowedActions();
01967 if( decoration != NULL )
01968 decoration->borders( border_left, border_right, border_top, border_bottom );
01969 if( isShade())
01970 setGeometry( QRect( pos(), sizeForClientSize( clientSize())), ForceGeometrySet );
01971 else
01972 setGeometry( geometry(), ForceGeometrySet );
01973 if( decoration != NULL )
01974 decoration->maximizeChange();
01975 }
01976
01977 void Client::checkMaximizeGeometry()
01978 {
01979
01980
01981 if( isShade())
01982 return;
01983 if( isMove() || isResize())
01984 return;
01985
01986 static int recursion_protection = 0;
01987 if( recursion_protection > 3 )
01988 {
01989 kdWarning( 1212 ) << "Check maximize overflow - you loose!" << endl;
01990 kdWarning( 1212 ) << kdBacktrace() << endl;
01991 return;
01992 }
01993 ++recursion_protection;
01994 QRect max_area = workspace()->clientArea( MaximizeArea, this );
01995 if( geometry() == max_area )
01996 {
01997 if( max_mode != MaximizeFull )
01998 maximize( MaximizeFull );
01999 }
02000 else if( x() == max_area.left() && width() == max_area.width())
02001 {
02002 if( max_mode != MaximizeHorizontal )
02003 maximize( MaximizeHorizontal );
02004 }
02005 else if( y() == max_area.top() && height() == max_area.height())
02006 {
02007 if( max_mode != MaximizeVertical )
02008 maximize( MaximizeVertical );
02009 }
02010 else if( max_mode != MaximizeRestore )
02011 {
02012 resetMaximize();
02013 }
02014 --recursion_protection;
02015 }
02016
02017 bool Client::isFullScreenable( bool fullscreen_hack ) const
02018 {
02019 if( !rules()->checkFullScreen( true ))
02020 return false;
02021 if( fullscreen_hack )
02022 return isNormalWindow();
02023 if( rules()->checkStrictGeometry( false ))
02024 {
02025
02026 QRect fsarea = workspace()->clientArea( FullScreenArea, this );
02027 if( sizeForClientSize( fsarea.size(), SizemodeAny, true ) != fsarea.size())
02028 return false;
02029 }
02030
02031 return !isSpecialWindow();
02032 }
02033
02034 bool Client::userCanSetFullScreen() const
02035 {
02036 if( fullscreen_mode == FullScreenHack )
02037 return false;
02038 if( !isFullScreenable( false ))
02039 return false;
02040
02041 TemporaryAssign< FullScreenMode > tmp( fullscreen_mode, FullScreenNone );
02042 return isNormalWindow() && isMaximizable();
02043 }
02044
02045 void Client::setFullScreen( bool set, bool user )
02046 {
02047 if( !isFullScreen() && !set )
02048 return;
02049 if( fullscreen_mode == FullScreenHack )
02050 return;
02051 if( user && !userCanSetFullScreen())
02052 return;
02053 set = rules()->checkFullScreen( set );
02054 setShade( ShadeNone );
02055 bool was_fs = isFullScreen();
02056 if( !was_fs )
02057 geom_fs_restore = geometry();
02058 fullscreen_mode = set ? FullScreenNormal : FullScreenNone;
02059 if( was_fs == isFullScreen())
02060 return;
02061 StackingUpdatesBlocker blocker1( workspace());
02062 GeometryUpdatesPostponer blocker2( this );
02063 workspace()->updateClientLayer( this );
02064 info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen );
02065 updateDecoration( false, false );
02066
02067 if( isFullScreen() && xSizeHint.width > workspace()->clientArea(FullScreenArea, this).width() )
02068 setGeometry( workspace()->clientArea( FullXineramaArea, this ));
02069 else if( isFullScreen() && xSizeHint.height > workspace()->clientArea(FullScreenArea, this).height() )
02070 setGeometry( workspace()->clientArea( FullXineramaArea, this ));
02071 else if( isFullScreen())
02072 setGeometry( workspace()->clientArea( FullScreenArea, this ));
02073 else
02074 {
02075 if( !geom_fs_restore.isNull())
02076 setGeometry( QRect( geom_fs_restore.topLeft(), adjustedSize( geom_fs_restore.size())));
02077
02078 else
02079 {
02080 setGeometry( workspace()->clientArea( MaximizeArea, this ));
02081 }
02082 }
02083 updateWindowRules();
02084 }
02085
02086 bool Client::checkFullScreenHack( const QRect& geom ) const
02087 {
02088
02089 return (( geom.size() == workspace()->clientArea( FullArea, geom.center(), desktop()).size()
02090 || geom.size() == workspace()->clientArea( ScreenArea, geom.center(), desktop()).size())
02091 && noBorder() && !isUserNoBorder() && isFullScreenable( true ));
02092 }
02093
02094 void Client::updateFullScreenHack( const QRect& geom )
02095 {
02096 bool is_hack = checkFullScreenHack( geom );
02097 if( fullscreen_mode == FullScreenNone && is_hack )
02098 {
02099 fullscreen_mode = FullScreenHack;
02100 updateDecoration( false, false );
02101 setGeometry( workspace()->clientArea( FullScreenArea, this ));
02102 }
02103 else if( fullscreen_mode == FullScreenHack && !is_hack )
02104 {
02105 fullscreen_mode = FullScreenNone;
02106 updateDecoration( false, false );
02107
02108 }
02109 StackingUpdatesBlocker blocker( workspace());
02110 workspace()->updateClientLayer( this );
02111 }
02112
02113 static QRect* visible_bound = 0;
02114 static GeometryTip* geometryTip = 0;
02115
02116 void Client::drawbound( const QRect& geom )
02117 {
02118 assert( visible_bound == NULL );
02119 visible_bound = new QRect( geom );
02120 doDrawbound( *visible_bound, false );
02121 }
02122
02123 void Client::clearbound()
02124 {
02125 if( visible_bound == NULL )
02126 return;
02127 doDrawbound( *visible_bound, true );
02128 delete visible_bound;
02129 visible_bound = 0;
02130 }
02131
02132 void Client::doDrawbound( const QRect& geom, bool clear )
02133 {
02134 if( decoration != NULL && decoration->drawbound( geom, clear ))
02135 return;
02136 QPainter p ( workspace()->desktopWidget() );
02137 p.setPen( QPen( Qt::white, 5 ) );
02138 p.setRasterOp( Qt::XorROP );
02139
02140
02141 QRect g = geom;
02142 if( g.width() > 5 )
02143 {
02144 g.setLeft( g.left() + 2 );
02145 g.setRight( g.right() - 2 );
02146 }
02147 if( g.height() > 5 )
02148 {
02149 g.setTop( g.top() + 2 );
02150 g.setBottom( g.bottom() - 2 );
02151 }
02152 p.drawRect( g );
02153 }
02154
02155 void Client::positionGeometryTip()
02156 {
02157 assert( isMove() || isResize());
02158
02159 if (options->showGeometryTip())
02160 {
02161 if( !geometryTip )
02162 {
02163 bool save_under = ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02164 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque );
02165 geometryTip = new GeometryTip( &xSizeHint, save_under );
02166 }
02167 QRect wgeom( moveResizeGeom );
02168 wgeom.setWidth( wgeom.width() - ( width() - clientSize().width()));
02169 wgeom.setHeight( wgeom.height() - ( height() - clientSize().height()));
02170 if( isShade())
02171 wgeom.setHeight( 0 );
02172 geometryTip->setGeometry( wgeom );
02173 if( !geometryTip->isVisible())
02174 {
02175 geometryTip->show();
02176 geometryTip->raise();
02177 }
02178 }
02179 }
02180
02181 class EatAllPaintEvents
02182 : public QObject
02183 {
02184 protected:
02185 virtual bool eventFilter( QObject* o, QEvent* e )
02186 { return e->type() == QEvent::Paint && o != geometryTip; }
02187 };
02188
02189 static EatAllPaintEvents* eater = 0;
02190
02191 bool Client::startMoveResize()
02192 {
02193 assert( !moveResizeMode );
02194 assert( QWidget::keyboardGrabber() == NULL );
02195 assert( QWidget::mouseGrabber() == NULL );
02196 if( QApplication::activePopupWidget() != NULL )
02197 return false;
02198 bool has_grab = false;
02199
02200
02201
02202 XSetWindowAttributes attrs;
02203 QRect r = workspace()->clientArea( FullArea, this );
02204 move_resize_grab_window = XCreateWindow( qt_xdisplay(), workspace()->rootWin(), r.x(), r.y(),
02205 r.width(), r.height(), 0, CopyFromParent, InputOnly, CopyFromParent, 0, &attrs );
02206 XMapRaised( qt_xdisplay(), move_resize_grab_window );
02207 if( XGrabPointer( qt_xdisplay(), move_resize_grab_window, False,
02208 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask,
02209 GrabModeAsync, GrabModeAsync, None, cursor.handle(), qt_x_time ) == Success )
02210 has_grab = true;
02211 if( XGrabKeyboard( qt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, qt_x_time ) == Success )
02212 has_grab = true;
02213 if( !has_grab )
02214 {
02215 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02216 move_resize_grab_window = None;
02217 return false;
02218 }
02219 if ( maximizeMode() != MaximizeRestore )
02220 resetMaximize();
02221 moveResizeMode = true;
02222 workspace()->setClientIsMoving(this);
02223 initialMoveResizeGeom = moveResizeGeom = geometry();
02224 checkUnrestrictedMoveResize();
02225
02226 if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02227 setShadowSize(0);
02228 if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){
02229 savedOpacity_ = opacity_;
02230 setOpacity(options->translucentMovingWindows, options->movingWindowOpacity);
02231 }
02232 if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02233 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02234 {
02235 grabXServer();
02236 kapp->sendPostedEvents();
02237
02238
02239
02240
02241
02242 eater = new EatAllPaintEvents;
02243
02244 }
02245 Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
02246 return true;
02247 }
02248
02249 void Client::finishMoveResize( bool cancel )
02250 {
02251 leaveMoveResize();
02252 if( cancel )
02253 setGeometry( initialMoveResizeGeom );
02254 else
02255 setGeometry( moveResizeGeom );
02256 checkMaximizeGeometry();
02257
02258 Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
02259 }
02260
02261 void Client::leaveMoveResize()
02262 {
02263
02264 if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque)
02265 setOpacity(true, savedOpacity_);
02266 if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02267 updateShadowSize();
02268 clearbound();
02269 if (geometryTip)
02270 {
02271 geometryTip->hide();
02272 delete geometryTip;
02273 geometryTip = NULL;
02274 }
02275 if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02276 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02277 ungrabXServer();
02278 XUngrabKeyboard( qt_xdisplay(), qt_x_time );
02279 XUngrabPointer( qt_xdisplay(), qt_x_time );
02280 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02281 move_resize_grab_window = None;
02282 workspace()->setClientIsMoving(0);
02283 if( move_faked_activity )
02284 workspace()->unfakeActivity( this );
02285 move_faked_activity = false;
02286 moveResizeMode = false;
02287 delete eater;
02288 eater = 0;
02289 }
02290
02291
02292
02293
02294
02295 void Client::checkUnrestrictedMoveResize()
02296 {
02297 if( unrestrictedMoveResize )
02298 return;
02299 QRect desktopArea = workspace()->clientArea( WorkArea, moveResizeGeom.center(), desktop());
02300 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02301
02302
02303 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02304 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02305
02306 titlebar_marge = initialMoveResizeGeom.height();
02307 top_marge = border_bottom;
02308 bottom_marge = border_top;
02309 if( isResize())
02310 {
02311 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02312 unrestrictedMoveResize = true;
02313 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02314 unrestrictedMoveResize = true;
02315 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02316 unrestrictedMoveResize = true;
02317 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02318 unrestrictedMoveResize = true;
02319 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
02320 unrestrictedMoveResize = true;
02321 }
02322 if( isMove())
02323 {
02324 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
02325 unrestrictedMoveResize = true;
02326
02327 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02328 unrestrictedMoveResize = true;
02329 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02330 unrestrictedMoveResize = true;
02331 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02332 unrestrictedMoveResize = true;
02333 }
02334 }
02335
02336 void Client::handleMoveResize( int x, int y, int x_root, int y_root )
02337 {
02338 if(( mode == PositionCenter && !isMovable())
02339 || ( mode != PositionCenter && ( isShade() || !isResizable())))
02340 return;
02341
02342 if ( !moveResizeMode )
02343 {
02344 QPoint p( QPoint( x, y ) - moveOffset );
02345 if (p.manhattanLength() >= 6)
02346 {
02347 if( !startMoveResize())
02348 {
02349 buttonDown = false;
02350 setCursor( mode );
02351 return;
02352 }
02353 }
02354 else
02355 return;
02356 }
02357
02358
02359 if ( mode != PositionCenter && shade_mode != ShadeNone )
02360 setShade( ShadeNone );
02361
02362 QPoint globalPos( x_root, y_root );
02363
02364
02365 QPoint topleft = globalPos - moveOffset;
02366 QPoint bottomright = globalPos + invertedMoveOffset;
02367 QRect previousMoveResizeGeom = moveResizeGeom;
02368
02369
02370
02371
02372
02373 QRect desktopArea = workspace()->clientArea( WorkArea, globalPos, desktop());
02374 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02375 if( unrestrictedMoveResize )
02376 left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5;
02377 else
02378 {
02379
02380 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02381 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02382
02383 titlebar_marge = initialMoveResizeGeom.height();
02384 top_marge = border_bottom;
02385 bottom_marge = border_top;
02386 }
02387
02388 bool update = false;
02389 if( isResize())
02390 {
02391
02392 QRect orig = initialMoveResizeGeom;
02393 Sizemode sizemode = SizemodeAny;
02394 switch ( mode )
02395 {
02396 case PositionTopLeft:
02397 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
02398 break;
02399 case PositionBottomRight:
02400 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
02401 break;
02402 case PositionBottomLeft:
02403 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
02404 break;
02405 case PositionTopRight:
02406 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02407 break;
02408 case PositionTop:
02409 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), orig.bottomRight() ) ;
02410 sizemode = SizemodeFixedH;
02411 break;
02412 case PositionBottom:
02413 moveResizeGeom = QRect( orig.topLeft(), QPoint( orig.right(), bottomright.y() ) ) ;
02414 sizemode = SizemodeFixedH;
02415 break;
02416 case PositionLeft:
02417 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), orig.bottomRight() ) ;
02418 sizemode = SizemodeFixedW;
02419 break;
02420 case PositionRight:
02421 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), orig.bottom() ) ) ;
02422 sizemode = SizemodeFixedW;
02423 break;
02424 case PositionCenter:
02425 default:
02426 assert( false );
02427 break;
02428 }
02429
02430
02431 moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode );
02432
02433
02434 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02435 moveResizeGeom.setBottom( desktopArea.top() + top_marge );
02436 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02437 moveResizeGeom.setTop( desktopArea.bottom() - bottom_marge );
02438 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02439 moveResizeGeom.setRight( desktopArea.left() + left_marge );
02440 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02441 moveResizeGeom.setLeft(desktopArea.right() - right_marge );
02442 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
02443 moveResizeGeom.setTop( desktopArea.top());
02444
02445 QSize size = adjustedSize( moveResizeGeom.size(), sizemode );
02446
02447 topleft = QPoint( moveResizeGeom.right() - size.width() + 1, moveResizeGeom.bottom() - size.height() + 1 );
02448 bottomright = QPoint( moveResizeGeom.left() + size.width() - 1, moveResizeGeom.top() + size.height() - 1 );
02449 orig = moveResizeGeom;
02450 switch ( mode )
02451 {
02452 case PositionTopLeft:
02453 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
02454 break;
02455 case PositionBottomRight:
02456 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
02457 break;
02458 case PositionBottomLeft:
02459 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
02460 break;
02461 case PositionTopRight:
02462 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02463 break;
02464
02465
02466
02467 case PositionTop:
02468 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02469 break;
02470 case PositionBottom:
02471 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
02472 break;
02473 case PositionLeft:
02474 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), QPoint( orig.right(), bottomright.y()));
02475 break;
02476 case PositionRight:
02477 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
02478 break;
02479 case PositionCenter:
02480 default:
02481 assert( false );
02482 break;
02483 }
02484 if( moveResizeGeom.size() != previousMoveResizeGeom.size())
02485 update = true;
02486 }
02487 else if( isMove())
02488 {
02489 assert( mode == PositionCenter );
02490
02491 moveResizeGeom.moveTopLeft( topleft );
02492 moveResizeGeom.moveTopLeft( workspace()->adjustClientPosition( this, moveResizeGeom.topLeft() ) );
02493
02494 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
02495 moveResizeGeom.moveBottom( desktopArea.top() + titlebar_marge - 1 );
02496
02497 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02498 moveResizeGeom.moveTop( desktopArea.bottom() - bottom_marge );
02499 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02500 moveResizeGeom.moveRight( desktopArea.left() + left_marge );
02501 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02502 moveResizeGeom.moveLeft(desktopArea.right() - right_marge );
02503 if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft())
02504 update = true;
02505 }
02506 else
02507 assert( false );
02508
02509 if( update )
02510 {
02511 if( rules()->checkMoveResizeMode
02512 ( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque )
02513 {
02514 setGeometry( moveResizeGeom );
02515 positionGeometryTip();
02516 }
02517 else if( rules()->checkMoveResizeMode
02518 ( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent )
02519 {
02520 clearbound();
02521 positionGeometryTip();
02522 drawbound( moveResizeGeom );
02523 }
02524 }
02525 if ( isMove() )
02526 workspace()->clientMoved(globalPos, qt_x_time);
02527 }
02528
02529
02530 }