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
01441
01442 if ( maximizeMode() != MaximizeFull
01443 || ns != size())
01444 {
01445 QRect orig_geometry = geometry();
01446 GeometryUpdatesPostponer blocker( this );
01447 move( new_pos );
01448 plainResize( ns );
01449 setGeometry( QRect( calculateGravitation( false, gravity ), size()));
01450 updateFullScreenHack( QRect( new_pos, QSize( nw, nh )));
01451 QRect area = workspace()->clientArea( WorkArea, this );
01452 if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen()
01453 && area.contains( orig_geometry ))
01454 keepInArea( area );
01455
01456
01457
01458
01459
01460 if (hasStrut ())
01461 workspace() -> updateClientArea ();
01462 }
01463 }
01464
01465 if ( value_mask & (CWWidth | CWHeight )
01466 && ! ( value_mask & ( CWX | CWY )) )
01467 {
01468 int nw = clientSize().width();
01469 int nh = clientSize().height();
01470 if ( value_mask & CWWidth )
01471 nw = rw;
01472 if ( value_mask & CWHeight )
01473 nh = rh;
01474 QSize ns = sizeForClientSize( QSize( nw, nh ) );
01475
01476 if( ns != size())
01477 {
01478 QRect orig_geometry = geometry();
01479 GeometryUpdatesPostponer blocker( this );
01480 int save_gravity = xSizeHint.win_gravity;
01481 xSizeHint.win_gravity = gravity;
01482 resizeWithChecks( ns );
01483 xSizeHint.win_gravity = save_gravity;
01484 updateFullScreenHack( QRect( calculateGravitation( true, xSizeHint.win_gravity ), QSize( nw, nh )));
01485 if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen())
01486 {
01487
01488
01489 QRect area = workspace()->clientArea( MovementArea, this );
01490 if( area.contains( orig_geometry ))
01491 keepInArea( area );
01492 area = workspace()->clientArea( WorkArea, this );
01493 if( area.contains( orig_geometry ))
01494 keepInArea( area );
01495 }
01496 }
01497 }
01498
01499
01500
01501 }
01502
01503 void Client::resizeWithChecks( int w, int h, ForceGeometry_t force )
01504 {
01505 if( shade_geometry_change )
01506 assert( false );
01507 else if( isShade())
01508 {
01509 if( h == border_top + border_bottom )
01510 {
01511 kdWarning() << "Shaded geometry passed for size:" << endl;
01512 kdWarning() << kdBacktrace() << endl;
01513 }
01514 }
01515 int newx = x();
01516 int newy = y();
01517 QRect area = workspace()->clientArea( WorkArea, this );
01518
01519 if( w > area.width())
01520 w = area.width();
01521 if( h > area.height())
01522 h = area.height();
01523 QSize tmp = adjustedSize( QSize( w, h ));
01524 w = tmp.width();
01525 h = tmp.height();
01526 switch( xSizeHint.win_gravity )
01527 {
01528 case NorthWestGravity:
01529 default:
01530 break;
01531 case NorthGravity:
01532 newx = ( newx + width() / 2 ) - ( w / 2 );
01533 break;
01534 case NorthEastGravity:
01535 newx = newx + width() - w;
01536 break;
01537 case WestGravity:
01538 newy = ( newy + height() / 2 ) - ( h / 2 );
01539 break;
01540 case CenterGravity:
01541 newx = ( newx + width() / 2 ) - ( w / 2 );
01542 newy = ( newy + height() / 2 ) - ( h / 2 );
01543 break;
01544 case StaticGravity:
01545
01546 break;
01547 case EastGravity:
01548 newx = newx + width() - w;
01549 newy = ( newy + height() / 2 ) - ( h / 2 );
01550 break;
01551 case SouthWestGravity:
01552 newy = newy + height() - h;
01553 break;
01554 case SouthGravity:
01555 newx = ( newx + width() / 2 ) - ( w / 2 );
01556 newy = newy + height() - h;
01557 break;
01558 case SouthEastGravity:
01559 newx = newx + width() - w;
01560 newy = newy + height() - h;
01561 break;
01562 }
01563
01564
01565 if( workarea_diff_x != INT_MIN && w <= area.width())
01566 {
01567 if( newx < area.left())
01568 newx = area.left();
01569 if( newx + w > area.right() + 1 )
01570 newx = area.right() + 1 - w;
01571 assert( newx >= area.left() && newx + w <= area.right() + 1 );
01572 }
01573 if( workarea_diff_y != INT_MIN && h <= area.height())
01574 {
01575 if( newy < area.top())
01576 newy = area.top();
01577 if( newy + h > area.bottom() + 1 )
01578 newy = area.bottom() + 1 - h;
01579 assert( newy >= area.top() && newy + h <= area.bottom() + 1 );
01580 }
01581 setGeometry( newx, newy, w, h, force );
01582 }
01583
01584
01585 void Client::NETMoveResizeWindow( int flags, int x, int y, int width, int height )
01586 {
01587 int gravity = flags & 0xff;
01588 int value_mask = 0;
01589 if( flags & ( 1 << 8 ))
01590 value_mask |= CWX;
01591 if( flags & ( 1 << 9 ))
01592 value_mask |= CWY;
01593 if( flags & ( 1 << 10 ))
01594 value_mask |= CWWidth;
01595 if( flags & ( 1 << 11 ))
01596 value_mask |= CWHeight;
01597 configureRequest( value_mask, x, y, width, height, gravity, true );
01598 }
01599
01604 bool Client::isMovable() const
01605 {
01606 if( !motif_may_move || isFullScreen())
01607 return false;
01608 if( isSpecialWindow() && !isSplash() && !isToolbar())
01609 return false;
01610 if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01611 return false;
01612 if( rules()->checkPosition( invalidPoint ) != invalidPoint )
01613 return false;
01614 return true;
01615 }
01616
01620 bool Client::isResizable() const
01621 {
01622 if( !motif_may_resize || isFullScreen())
01623 return false;
01624 if( isSpecialWindow() )
01625 return false;
01626 if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01627 return false;
01628 if( rules()->checkSize( QSize()).isValid())
01629 return false;
01630
01631 QSize min = minSize();
01632 QSize max = maxSize();
01633 return min.width() < max.width() || min.height() < max.height();
01634 }
01635
01636
01637
01638
01639 bool Client::isMaximizable() const
01640 {
01641 {
01642
01643 TemporaryAssign< MaximizeMode > tmp( max_mode, MaximizeRestore );
01644 if( !isMovable() || !isResizable() || isToolbar())
01645 return false;
01646 }
01647 if ( maximizeMode() != MaximizeRestore )
01648 return TRUE;
01649 QSize max = maxSize();
01650 #if 0
01651 if( max.width() < 32767 || max.height() < 32767 )
01652 return false;
01653 #else
01654
01655
01656 QSize areasize = workspace()->clientArea( MaximizeArea, this ).size();
01657 if( max.width() < areasize.width() || max.height() < areasize.height())
01658 return false;
01659 #endif
01660 return true;
01661 }
01662
01663
01667 void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
01668 {
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680 if( shade_geometry_change )
01681 ;
01682 else if( isShade())
01683 {
01684 if( h == border_top + border_bottom )
01685 {
01686 kdDebug() << "Shaded geometry passed for size:" << endl;
01687 kdDebug() << kdBacktrace() << endl;
01688 }
01689 else
01690 {
01691 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01692 h = border_top + border_bottom;
01693 }
01694 }
01695 else
01696 {
01697 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01698 }
01699 if( force == NormalGeometrySet && frame_geometry == QRect( x, y, w, h ))
01700 return;
01701 frame_geometry = QRect( x, y, w, h );
01702 updateWorkareaDiffs();
01703 if( postpone_geometry_updates != 0 )
01704 {
01705 pending_geometry_update = true;
01706 return;
01707 }
01708 resizeDecoration( QSize( w, h ));
01709 XMoveResizeWindow( qt_xdisplay(), frameId(), x, y, w, h );
01710
01711 if( !isShade())
01712 {
01713 QSize cs = clientSize();
01714 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01715 cs.width(), cs.height());
01716 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01717 }
01718 updateShape();
01719
01720 updateWorkareaDiffs();
01721 sendSyntheticConfigureNotify();
01722 updateWindowRules();
01723 checkMaximizeGeometry();
01724 }
01725
01726 void Client::plainResize( int w, int h, ForceGeometry_t force )
01727 {
01728
01729 if( shade_geometry_change )
01730 ;
01731 else if( isShade())
01732 {
01733 if( h == border_top + border_bottom )
01734 {
01735 kdDebug() << "Shaded geometry passed for size:" << endl;
01736 kdDebug() << kdBacktrace() << endl;
01737 }
01738 else
01739 {
01740 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01741 h = border_top + border_bottom;
01742 }
01743 }
01744 else
01745 {
01746 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01747 }
01748 if( QSize( w, h ) != rules()->checkSize( QSize( w, h )))
01749 {
01750 kdDebug() << "forced size fail:" << QSize( w,h ) << ":" << rules()->checkSize( QSize( w, h )) << endl;
01751 kdDebug() << kdBacktrace() << endl;
01752 }
01753 if( force == NormalGeometrySet && frame_geometry.size() == QSize( w, h ))
01754 return;
01755 frame_geometry.setSize( QSize( w, h ));
01756 updateWorkareaDiffs();
01757 if( postpone_geometry_updates != 0 )
01758 {
01759 pending_geometry_update = true;
01760 return;
01761 }
01762 resizeDecoration( QSize( w, h ));
01763 XResizeWindow( qt_xdisplay(), frameId(), w, h );
01764
01765 if( !isShade())
01766 {
01767 QSize cs = clientSize();
01768 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01769 cs.width(), cs.height());
01770 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01771 }
01772 updateShape();
01773 updateWorkareaDiffs();
01774 sendSyntheticConfigureNotify();
01775 updateWindowRules();
01776 checkMaximizeGeometry();
01777 }
01778
01782 void Client::move( int x, int y, ForceGeometry_t force )
01783 {
01784 if( force == NormalGeometrySet && frame_geometry.topLeft() == QPoint( x, y ))
01785 return;
01786 frame_geometry.moveTopLeft( QPoint( x, y ));
01787 updateWorkareaDiffs();
01788 if( postpone_geometry_updates != 0 )
01789 {
01790 pending_geometry_update = true;
01791 return;
01792 }
01793 XMoveWindow( qt_xdisplay(), frameId(), x, y );
01794 sendSyntheticConfigureNotify();
01795 updateWindowRules();
01796 checkMaximizeGeometry();
01797 }
01798
01799
01800 void Client::postponeGeometryUpdates( bool postpone )
01801 {
01802 if( postpone )
01803 {
01804 if( postpone_geometry_updates == 0 )
01805 pending_geometry_update = false;
01806 ++postpone_geometry_updates;
01807 }
01808 else
01809 {
01810 if( --postpone_geometry_updates == 0 )
01811 {
01812 if( pending_geometry_update )
01813 {
01814 if( isShade())
01815 setGeometry( QRect( pos(), adjustedSize()), ForceGeometrySet );
01816 else
01817 setGeometry( geometry(), ForceGeometrySet );
01818 pending_geometry_update = false;
01819 }
01820 }
01821 }
01822 }
01823
01824 void Client::maximize( MaximizeMode m )
01825 {
01826 setMaximize( m & MaximizeVertical, m & MaximizeHorizontal );
01827 }
01828
01832 void Client::setMaximize( bool vertically, bool horizontally )
01833 {
01834 changeMaximize(
01835 max_mode & MaximizeVertical ? !vertically : vertically,
01836 max_mode & MaximizeHorizontal ? !horizontally : horizontally,
01837 false );
01838 }
01839
01840 void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
01841 {
01842 if( !isMaximizable())
01843 return;
01844
01845 MaximizeMode old_mode = max_mode;
01846
01847 if( !adjust )
01848 {
01849 if( vertical )
01850 max_mode = MaximizeMode( max_mode ^ MaximizeVertical );
01851 if( horizontal )
01852 max_mode = MaximizeMode( max_mode ^ MaximizeHorizontal );
01853 }
01854
01855 max_mode = rules()->checkMaximize( max_mode );
01856 if( !adjust && max_mode == old_mode )
01857 return;
01858
01859 GeometryUpdatesPostponer blocker( this );
01860
01861
01862 Q_ASSERT( !( vertical && horizontal )
01863 || ((( max_mode & MaximizeVertical ) != 0 ) == (( max_mode & MaximizeHorizontal ) != 0 )));
01864
01865 QRect clientArea = workspace()->clientArea( MaximizeArea, this );
01866
01867
01868 if( !adjust && !( y() == clientArea.top() && height() == clientArea.height()))
01869 {
01870 geom_restore.setTop( y());
01871 geom_restore.setHeight( height());
01872 }
01873 if( !adjust && !( x() == clientArea.left() && width() == clientArea.width()))
01874 {
01875 geom_restore.setLeft( x());
01876 geom_restore.setWidth( width());
01877 }
01878
01879 if( !adjust )
01880 {
01881 if(( vertical && !(old_mode & MaximizeVertical ))
01882 || ( horizontal && !( old_mode & MaximizeHorizontal )))
01883 Notify::raise( Notify::Maximize );
01884 else
01885 Notify::raise( Notify::UnMaximize );
01886 }
01887
01888 if( decoration != NULL )
01889 decoration->borders( border_left, border_right, border_top, border_bottom );
01890
01891
01892 if ( old_mode==MaximizeFull && max_mode==MaximizeRestore )
01893 {
01894 if ( maximizeModeRestore()==MaximizeVertical )
01895 {
01896 max_mode = MaximizeVertical;
01897 maxmode_restore = MaximizeRestore;
01898 }
01899 if ( maximizeModeRestore()==MaximizeHorizontal )
01900 {
01901 max_mode = MaximizeHorizontal;
01902 maxmode_restore = MaximizeRestore;
01903 }
01904 }
01905
01906 switch (max_mode)
01907 {
01908
01909 case MaximizeVertical:
01910 {
01911 if( old_mode & MaximizeHorizontal )
01912 {
01913 if( geom_restore.width() == 0 )
01914 {
01915 plainResize( adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH ));
01916 workspace()->placeSmart( this, clientArea );
01917 }
01918 else
01919 setGeometry( QRect(QPoint( geom_restore.x(), clientArea.top()),
01920 adjustedSize(QSize( geom_restore.width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet);
01921 }
01922 else
01923 setGeometry( QRect(QPoint(x(), clientArea.top()),
01924 adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet);
01925 info->setState( NET::MaxVert, NET::Max );
01926 break;
01927 }
01928
01929 case MaximizeHorizontal:
01930 {
01931 if( old_mode & MaximizeVertical )
01932 {
01933 if( geom_restore.height() == 0 )
01934 {
01935 plainResize( adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW ));
01936 workspace()->placeSmart( this, clientArea );
01937 }
01938 else
01939 setGeometry( QRect( QPoint(clientArea.left(), geom_restore.y()),
01940 adjustedSize(QSize(clientArea.width(), geom_restore.height()), SizemodeFixedW )), ForceGeometrySet);
01941 }
01942 else
01943 setGeometry( QRect( QPoint(clientArea.left(), y()),
01944 adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW )), ForceGeometrySet);
01945 info->setState( NET::MaxHoriz, NET::Max );
01946 break;
01947 }
01948
01949 case MaximizeRestore:
01950 {
01951 QRect restore = geometry();
01952
01953 if( old_mode & MaximizeVertical )
01954 {
01955 restore.setTop( geom_restore.top());
01956 restore.setBottom( geom_restore.bottom());
01957 }
01958 if( old_mode & MaximizeHorizontal )
01959 {
01960 restore.setLeft( geom_restore.left());
01961 restore.setRight( geom_restore.right());
01962 }
01963 if( !restore.isValid())
01964 {
01965 QSize s = QSize( clientArea.width()*2/3, clientArea.height()*2/3 );
01966 if( geom_restore.width() > 0 )
01967 s.setWidth( geom_restore.width());
01968 if( geom_restore.height() > 0 )
01969 s.setHeight( geom_restore.height());
01970 plainResize( adjustedSize( s ));
01971 workspace()->placeSmart( this, clientArea );
01972 restore = geometry();
01973 if( geom_restore.width() > 0 )
01974 restore.moveLeft( geom_restore.x());
01975 if( geom_restore.height() > 0 )
01976 restore.moveTop( geom_restore.y());
01977 }
01978 setGeometry( restore, ForceGeometrySet );
01979 info->setState( 0, NET::Max );
01980 break;
01981 }
01982
01983 case MaximizeFull:
01984 {
01985 if( !adjust )
01986 {
01987 if( old_mode & MaximizeVertical )
01988 maxmode_restore = MaximizeVertical;
01989 if( old_mode & MaximizeHorizontal )
01990 maxmode_restore = MaximizeHorizontal;
01991 }
01992 QSize adjSize = adjustedSize(clientArea.size(), SizemodeMax );
01993 QRect r = QRect(clientArea.topLeft(), adjSize);
01994 setGeometry( r, ForceGeometrySet );
01995 info->setState( NET::Max, NET::Max );
01996 break;
01997 }
01998 default:
01999 break;
02000 }
02001
02002 updateAllowedActions();
02003 if( decoration != NULL )
02004 decoration->maximizeChange();
02005 updateWindowRules();
02006 }
02007
02008 void Client::resetMaximize()
02009 {
02010 if( max_mode == MaximizeRestore )
02011 return;
02012 max_mode = MaximizeRestore;
02013 Notify::raise( Notify::UnMaximize );
02014 info->setState( 0, NET::Max );
02015 updateAllowedActions();
02016 if( decoration != NULL )
02017 decoration->borders( border_left, border_right, border_top, border_bottom );
02018 if( isShade())
02019 setGeometry( QRect( pos(), sizeForClientSize( clientSize())), ForceGeometrySet );
02020 else
02021 setGeometry( geometry(), ForceGeometrySet );
02022 if( decoration != NULL )
02023 decoration->maximizeChange();
02024 }
02025
02026 void Client::checkMaximizeGeometry()
02027 {
02028
02029
02030 if( isShade())
02031 return;
02032 if( isMove() || isResize())
02033 return;
02034
02035 static int recursion_protection = 0;
02036 if( recursion_protection > 3 )
02037 {
02038 kdWarning( 1212 ) << "Check maximize overflow - you loose!" << endl;
02039 kdWarning( 1212 ) << kdBacktrace() << endl;
02040 return;
02041 }
02042 ++recursion_protection;
02043 QRect max_area = workspace()->clientArea( MaximizeArea, this );
02044 if( geometry() == max_area )
02045 {
02046 if( max_mode != MaximizeFull )
02047 maximize( MaximizeFull );
02048 }
02049 else if( x() == max_area.left() && width() == max_area.width())
02050 {
02051 if( max_mode != MaximizeHorizontal )
02052 maximize( MaximizeHorizontal );
02053 }
02054 else if( y() == max_area.top() && height() == max_area.height())
02055 {
02056 if( max_mode != MaximizeVertical )
02057 maximize( MaximizeVertical );
02058 }
02059 else if( max_mode != MaximizeRestore )
02060 {
02061 resetMaximize();
02062 }
02063 --recursion_protection;
02064 }
02065
02066 bool Client::isFullScreenable( bool fullscreen_hack ) const
02067 {
02068 if( !rules()->checkFullScreen( true ))
02069 return false;
02070 if( fullscreen_hack )
02071 return isNormalWindow();
02072 if( rules()->checkStrictGeometry( false ))
02073 {
02074
02075 QRect fsarea = workspace()->clientArea( FullScreenArea, this );
02076 if( sizeForClientSize( fsarea.size(), SizemodeAny, true ) != fsarea.size())
02077 return false;
02078 }
02079
02080 return !isSpecialWindow();
02081 }
02082
02083 bool Client::userCanSetFullScreen() const
02084 {
02085 if( fullscreen_mode == FullScreenHack )
02086 return false;
02087 if( !isFullScreenable( false ))
02088 return false;
02089
02090 TemporaryAssign< FullScreenMode > tmp( fullscreen_mode, FullScreenNone );
02091 return isNormalWindow() && isMaximizable();
02092 }
02093
02094 void Client::setFullScreen( bool set, bool user )
02095 {
02096 if( !isFullScreen() && !set )
02097 return;
02098 if( fullscreen_mode == FullScreenHack )
02099 return;
02100 if( user && !userCanSetFullScreen())
02101 return;
02102 set = rules()->checkFullScreen( set );
02103 setShade( ShadeNone );
02104 bool was_fs = isFullScreen();
02105 if( !was_fs )
02106 geom_fs_restore = geometry();
02107 fullscreen_mode = set ? FullScreenNormal : FullScreenNone;
02108 if( was_fs == isFullScreen())
02109 return;
02110 StackingUpdatesBlocker blocker1( workspace());
02111 GeometryUpdatesPostponer blocker2( this );
02112 workspace()->updateClientLayer( this );
02113 info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen );
02114 updateDecoration( false, false );
02115 if( isFullScreen())
02116 setGeometry( workspace()->clientArea( FullScreenArea, this ));
02117 else
02118 {
02119 if( !geom_fs_restore.isNull())
02120 setGeometry( QRect( geom_fs_restore.topLeft(), adjustedSize( geom_fs_restore.size())));
02121
02122 else
02123 {
02124 setGeometry( workspace()->clientArea( MaximizeArea, this ));
02125 }
02126 }
02127 updateWindowRules();
02128 }
02129
02130 int Client::checkFullScreenHack( const QRect& geom ) const
02131 {
02132
02133 if( noBorder() && !isUserNoBorder() && isFullScreenable( true ))
02134 {
02135 if( geom.size() == workspace()->clientArea( FullArea, geom.center(), desktop()).size())
02136 return 2;
02137 if( geom.size() == workspace()->clientArea( ScreenArea, geom.center(), desktop()).size())
02138 return 1;
02139 }
02140 return 0;
02141 }
02142
02143 void Client::updateFullScreenHack( const QRect& geom )
02144 {
02145 int type = checkFullScreenHack( geom );
02146 if( fullscreen_mode == FullScreenNone && type != 0 )
02147 {
02148 fullscreen_mode = FullScreenHack;
02149 updateDecoration( false, false );
02150 QRect geom;
02151 if( rules()->checkStrictGeometry( false ))
02152 {
02153 geom = type == 2
02154 ? workspace()->clientArea( FullArea, geom.center(), desktop())
02155 : workspace()->clientArea( ScreenArea, geom.center(), desktop());
02156 }
02157 else
02158 geom = workspace()->clientArea( FullScreenArea, geom.center(), desktop());
02159 setGeometry( geom );
02160 }
02161 else if( fullscreen_mode == FullScreenHack && type == 0 )
02162 {
02163 fullscreen_mode = FullScreenNone;
02164 updateDecoration( false, false );
02165
02166 }
02167 StackingUpdatesBlocker blocker( workspace());
02168 workspace()->updateClientLayer( this );
02169 }
02170
02171 static QRect* visible_bound = 0;
02172 static GeometryTip* geometryTip = 0;
02173
02174 void Client::drawbound( const QRect& geom )
02175 {
02176 assert( visible_bound == NULL );
02177 visible_bound = new QRect( geom );
02178 doDrawbound( *visible_bound, false );
02179 }
02180
02181 void Client::clearbound()
02182 {
02183 if( visible_bound == NULL )
02184 return;
02185 doDrawbound( *visible_bound, true );
02186 delete visible_bound;
02187 visible_bound = 0;
02188 }
02189
02190 void Client::doDrawbound( const QRect& geom, bool clear )
02191 {
02192 if( decoration != NULL && decoration->drawbound( geom, clear ))
02193 return;
02194 QPainter p ( workspace()->desktopWidget() );
02195 p.setPen( QPen( Qt::white, 5 ) );
02196 p.setRasterOp( Qt::XorROP );
02197
02198
02199 QRect g = geom;
02200 if( g.width() > 5 )
02201 {
02202 g.setLeft( g.left() + 2 );
02203 g.setRight( g.right() - 2 );
02204 }
02205 if( g.height() > 5 )
02206 {
02207 g.setTop( g.top() + 2 );
02208 g.setBottom( g.bottom() - 2 );
02209 }
02210 p.drawRect( g );
02211 }
02212
02213 void Client::positionGeometryTip()
02214 {
02215 assert( isMove() || isResize());
02216
02217 if (options->showGeometryTip())
02218 {
02219 if( !geometryTip )
02220 {
02221 bool save_under = ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02222 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque );
02223 geometryTip = new GeometryTip( &xSizeHint, save_under );
02224 }
02225 QRect wgeom( moveResizeGeom );
02226 wgeom.setWidth( wgeom.width() - ( width() - clientSize().width()));
02227 wgeom.setHeight( wgeom.height() - ( height() - clientSize().height()));
02228 if( isShade())
02229 wgeom.setHeight( 0 );
02230 geometryTip->setGeometry( wgeom );
02231 if( !geometryTip->isVisible())
02232 {
02233 geometryTip->show();
02234 geometryTip->raise();
02235 }
02236 }
02237 }
02238
02239 class EatAllPaintEvents
02240 : public QObject
02241 {
02242 protected:
02243 virtual bool eventFilter( QObject* o, QEvent* e )
02244 { return e->type() == QEvent::Paint && o != geometryTip; }
02245 };
02246
02247 static EatAllPaintEvents* eater = 0;
02248
02249 bool Client::startMoveResize()
02250 {
02251 assert( !moveResizeMode );
02252 assert( QWidget::keyboardGrabber() == NULL );
02253 assert( QWidget::mouseGrabber() == NULL );
02254 if( QApplication::activePopupWidget() != NULL )
02255 return false;
02256 bool has_grab = false;
02257
02258
02259
02260 XSetWindowAttributes attrs;
02261 QRect r = workspace()->clientArea( FullArea, this );
02262 move_resize_grab_window = XCreateWindow( qt_xdisplay(), workspace()->rootWin(), r.x(), r.y(),
02263 r.width(), r.height(), 0, CopyFromParent, InputOnly, CopyFromParent, 0, &attrs );
02264 XMapRaised( qt_xdisplay(), move_resize_grab_window );
02265 if( XGrabPointer( qt_xdisplay(), move_resize_grab_window, False,
02266 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask,
02267 GrabModeAsync, GrabModeAsync, move_resize_grab_window, cursor.handle(), qt_x_time ) == Success )
02268 has_grab = true;
02269 if( XGrabKeyboard( qt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, qt_x_time ) == Success )
02270 has_grab = true;
02271 if( !has_grab )
02272 {
02273 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02274 move_resize_grab_window = None;
02275 return false;
02276 }
02277 if ( maximizeMode() != MaximizeRestore )
02278 resetMaximize();
02279 moveResizeMode = true;
02280 workspace()->setClientIsMoving(this);
02281 initialMoveResizeGeom = moveResizeGeom = geometry();
02282 checkUnrestrictedMoveResize();
02283
02284 if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02285 setShadowSize(0);
02286 if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){
02287 savedOpacity_ = opacity_;
02288 setOpacity(options->translucentMovingWindows, options->movingWindowOpacity);
02289 }
02290 if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02291 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02292 {
02293 grabXServer();
02294 kapp->sendPostedEvents();
02295
02296
02297
02298
02299
02300 eater = new EatAllPaintEvents;
02301
02302 }
02303 Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
02304 return true;
02305 }
02306
02307 void Client::finishMoveResize( bool cancel )
02308 {
02309 leaveMoveResize();
02310 if( cancel )
02311 setGeometry( initialMoveResizeGeom );
02312 else
02313 setGeometry( moveResizeGeom );
02314 checkMaximizeGeometry();
02315
02316 Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
02317 }
02318
02319 void Client::leaveMoveResize()
02320 {
02321
02322 if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque)
02323 setOpacity(true, savedOpacity_);
02324 if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02325 updateShadowSize();
02326 clearbound();
02327 if (geometryTip)
02328 {
02329 geometryTip->hide();
02330 delete geometryTip;
02331 geometryTip = NULL;
02332 }
02333 if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02334 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02335 ungrabXServer();
02336 XUngrabKeyboard( qt_xdisplay(), qt_x_time );
02337 XUngrabPointer( qt_xdisplay(), qt_x_time );
02338 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02339 move_resize_grab_window = None;
02340 workspace()->setClientIsMoving(0);
02341 if( move_faked_activity )
02342 workspace()->unfakeActivity( this );
02343 move_faked_activity = false;
02344 moveResizeMode = false;
02345 delete eater;
02346 eater = 0;
02347 }
02348
02349
02350
02351
02352
02353 void Client::checkUnrestrictedMoveResize()
02354 {
02355 if( unrestrictedMoveResize )
02356 return;
02357 QRect desktopArea = workspace()->clientArea( WorkArea, moveResizeGeom.center(), desktop());
02358 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02359
02360
02361 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02362 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02363
02364 titlebar_marge = initialMoveResizeGeom.height();
02365 top_marge = border_bottom;
02366 bottom_marge = border_top;
02367 if( isResize())
02368 {
02369 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02370 unrestrictedMoveResize = true;
02371 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02372 unrestrictedMoveResize = true;
02373 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02374 unrestrictedMoveResize = true;
02375 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02376 unrestrictedMoveResize = true;
02377 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
02378 unrestrictedMoveResize = true;
02379 }
02380 if( isMove())
02381 {
02382 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
02383 unrestrictedMoveResize = true;
02384
02385 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02386 unrestrictedMoveResize = true;
02387 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02388 unrestrictedMoveResize = true;
02389 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02390 unrestrictedMoveResize = true;
02391 }
02392 }
02393
02394 void Client::handleMoveResize( int x, int y, int x_root, int y_root )
02395 {
02396 if(( mode == PositionCenter && !isMovable())
02397 || ( mode != PositionCenter && ( isShade() || !isResizable())))
02398 return;
02399
02400 if ( !moveResizeMode )
02401 {
02402 QPoint p( QPoint( x, y ) - moveOffset );
02403 if (p.manhattanLength() >= 6)
02404 {
02405 if( !startMoveResize())
02406 {
02407 buttonDown = false;
02408 setCursor( mode );
02409 return;
02410 }
02411 }
02412 else
02413 return;
02414 }
02415
02416
02417 if ( mode != PositionCenter && shade_mode != ShadeNone )
02418 setShade( ShadeNone );
02419
02420 QPoint globalPos( x_root, y_root );
02421
02422
02423 QPoint topleft = globalPos - moveOffset;
02424 QPoint bottomright = globalPos + invertedMoveOffset;
02425 QRect previousMoveResizeGeom = moveResizeGeom;
02426
02427
02428
02429
02430
02431 QRect desktopArea = workspace()->clientArea( WorkArea, globalPos, desktop());
02432 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02433 if( unrestrictedMoveResize )
02434 left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5;
02435 else
02436 {
02437
02438 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02439 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02440
02441 titlebar_marge = initialMoveResizeGeom.height();
02442 top_marge = border_bottom;
02443 bottom_marge = border_top;
02444 }
02445
02446 bool update = false;
02447 if( isResize())
02448 {
02449
02450 QRect orig = initialMoveResizeGeom;
02451 Sizemode sizemode = SizemodeAny;
02452 switch ( mode )
02453 {
02454 case PositionTopLeft:
02455 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
02456 break;
02457 case PositionBottomRight:
02458 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
02459 break;
02460 case PositionBottomLeft:
02461 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
02462 break;
02463 case PositionTopRight:
02464 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02465 break;
02466 case PositionTop:
02467 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), orig.bottomRight() ) ;
02468 sizemode = SizemodeFixedH;
02469 break;
02470 case PositionBottom:
02471 moveResizeGeom = QRect( orig.topLeft(), QPoint( orig.right(), bottomright.y() ) ) ;
02472 sizemode = SizemodeFixedH;
02473 break;
02474 case PositionLeft:
02475 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), orig.bottomRight() ) ;
02476 sizemode = SizemodeFixedW;
02477 break;
02478 case PositionRight:
02479 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), orig.bottom() ) ) ;
02480 sizemode = SizemodeFixedW;
02481 break;
02482 case PositionCenter:
02483 default:
02484 assert( false );
02485 break;
02486 }
02487
02488
02489 moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode );
02490
02491
02492 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02493 moveResizeGeom.setBottom( desktopArea.top() + top_marge );
02494 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02495 moveResizeGeom.setTop( desktopArea.bottom() - bottom_marge );
02496 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02497 moveResizeGeom.setRight( desktopArea.left() + left_marge );
02498 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02499 moveResizeGeom.setLeft(desktopArea.right() - right_marge );
02500 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
02501 moveResizeGeom.setTop( desktopArea.top());
02502
02503 QSize size = adjustedSize( moveResizeGeom.size(), sizemode );
02504
02505 topleft = QPoint( moveResizeGeom.right() - size.width() + 1, moveResizeGeom.bottom() - size.height() + 1 );
02506 bottomright = QPoint( moveResizeGeom.left() + size.width() - 1, moveResizeGeom.top() + size.height() - 1 );
02507 orig = moveResizeGeom;
02508 switch ( mode )
02509 {
02510 case PositionTopLeft:
02511 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
02512 break;
02513 case PositionBottomRight:
02514 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
02515 break;
02516 case PositionBottomLeft:
02517 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
02518 break;
02519 case PositionTopRight:
02520 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02521 break;
02522
02523
02524
02525 case PositionTop:
02526 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02527 break;
02528 case PositionBottom:
02529 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
02530 break;
02531 case PositionLeft:
02532 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), QPoint( orig.right(), bottomright.y()));
02533 break;
02534 case PositionRight:
02535 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
02536 break;
02537 case PositionCenter:
02538 default:
02539 assert( false );
02540 break;
02541 }
02542 if( moveResizeGeom.size() != previousMoveResizeGeom.size())
02543 update = true;
02544 }
02545 else if( isMove())
02546 {
02547 assert( mode == PositionCenter );
02548
02549 moveResizeGeom.moveTopLeft( topleft );
02550 moveResizeGeom.moveTopLeft( workspace()->adjustClientPosition( this, moveResizeGeom.topLeft() ) );
02551
02552 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
02553 moveResizeGeom.moveBottom( desktopArea.top() + titlebar_marge - 1 );
02554
02555 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02556 moveResizeGeom.moveTop( desktopArea.bottom() - bottom_marge );
02557 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02558 moveResizeGeom.moveRight( desktopArea.left() + left_marge );
02559 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02560 moveResizeGeom.moveLeft(desktopArea.right() - right_marge );
02561 if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft())
02562 update = true;
02563 }
02564 else
02565 assert( false );
02566
02567 if( update )
02568 {
02569 if( rules()->checkMoveResizeMode
02570 ( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque )
02571 {
02572 setGeometry( moveResizeGeom );
02573 positionGeometryTip();
02574 }
02575 else if( rules()->checkMoveResizeMode
02576 ( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent )
02577 {
02578 clearbound();
02579 positionGeometryTip();
02580 drawbound( moveResizeGeom );
02581 }
02582 }
02583 if ( isMove() )
02584 workspace()->clientMoved(globalPos, qt_x_time);
02585 }
02586
02587
02588 }