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