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