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