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