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
01022 QSize Client::sizeForClientSize( const QSize& wsize, Sizemode mode, bool noframe ) const
01023 {
01024 int w = wsize.width();
01025 int h = wsize.height();
01026 if (w<1) w = 1;
01027 if (h<1) h = 1;
01028
01029
01030
01031 QSize min_size = minSize();
01032 QSize max_size = maxSize();
01033 if( decoration != NULL )
01034 {
01035 QSize decominsize = decoration->minimumSize();
01036 QSize border_size( border_left + border_right, border_top + border_bottom );
01037 if( border_size.width() > decominsize.width())
01038 decominsize.setWidth( border_size.width());
01039 if( border_size.height() > decominsize.height())
01040 decominsize.setHeight( border_size.height());
01041 if( decominsize.width() > min_size.width())
01042 min_size.setWidth( decominsize.width());
01043 if( decominsize.height() > min_size.height())
01044 min_size.setHeight( decominsize.height());
01045 }
01046 w = QMIN( max_size.width(), w );
01047 h = QMIN( max_size.height(), h );
01048 w = QMAX( min_size.width(), w );
01049 h = QMAX( min_size.height(), h );
01050
01051 int w1 = w;
01052 int h1 = h;
01053 int width_inc = xSizeHint.width_inc;
01054 int height_inc = xSizeHint.height_inc;
01055 int basew_inc = xSizeHint.min_width;
01056 int baseh_inc = xSizeHint.min_height;
01057 w = int(( w - basew_inc ) / width_inc ) * width_inc + basew_inc;
01058 h = int(( h - baseh_inc ) / height_inc ) * height_inc + baseh_inc;
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074 if( xSizeHint.flags & PAspect )
01075 {
01076 double min_aspect_w = xSizeHint.min_aspect.x;
01077 double min_aspect_h = xSizeHint.min_aspect.y;
01078 double max_aspect_w = xSizeHint.max_aspect.x;
01079 double max_aspect_h = xSizeHint.max_aspect.y;
01080
01081
01082
01083 w -= xSizeHint.base_width;
01084 h -= xSizeHint.base_height;
01085 int max_width = max_size.width() - xSizeHint.base_width;
01086 int min_width = min_size.width() - xSizeHint.base_width;
01087 int max_height = max_size.height() - xSizeHint.base_height;
01088 int min_height = min_size.height() - xSizeHint.base_height;
01089 #define ASPECT_CHECK_GROW_W \
01090 if( min_aspect_w * h > min_aspect_h * w ) \
01091 { \
01092 int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \
01093 if( w + delta <= max_width ) \
01094 w += delta; \
01095 }
01096 #define ASPECT_CHECK_SHRINK_H_GROW_W \
01097 if( min_aspect_w * h > min_aspect_h * w ) \
01098 { \
01099 int delta = int( h - w * min_aspect_h / min_aspect_w ) / height_inc * height_inc; \
01100 if( h - delta >= min_height ) \
01101 h -= delta; \
01102 else \
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 }
01109 #define ASPECT_CHECK_GROW_H \
01110 if( max_aspect_w * h < max_aspect_h * w ) \
01111 { \
01112 int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \
01113 if( h + delta <= max_height ) \
01114 h += delta; \
01115 }
01116 #define ASPECT_CHECK_SHRINK_W_GROW_H \
01117 if( max_aspect_w * h < max_aspect_h * w ) \
01118 { \
01119 int delta = int( w - max_aspect_w * h / max_aspect_h ) / width_inc * width_inc; \
01120 if( w - delta >= min_width ) \
01121 w -= delta; \
01122 else \
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 }
01129 switch( mode )
01130 {
01131 case SizemodeAny:
01132 #if 0 // make SizemodeAny equal to SizemodeFixedW - prefer keeping fixed width,
01133
01134 {
01135 ASPECT_CHECK_SHRINK_H_GROW_W
01136 ASPECT_CHECK_SHRINK_W_GROW_H
01137 ASPECT_CHECK_GROW_H
01138 ASPECT_CHECK_GROW_W
01139 break;
01140 }
01141 #endif
01142 case SizemodeFixedW:
01143 {
01144
01145 ASPECT_CHECK_GROW_H
01146 ASPECT_CHECK_SHRINK_H_GROW_W
01147 ASPECT_CHECK_SHRINK_W_GROW_H
01148 ASPECT_CHECK_GROW_W
01149 break;
01150 }
01151 case SizemodeFixedH:
01152 {
01153 ASPECT_CHECK_GROW_W
01154 ASPECT_CHECK_SHRINK_W_GROW_H
01155 ASPECT_CHECK_SHRINK_H_GROW_W
01156 ASPECT_CHECK_GROW_H
01157 break;
01158 }
01159 case SizemodeMax:
01160 {
01161
01162 ASPECT_CHECK_SHRINK_H_GROW_W
01163 ASPECT_CHECK_SHRINK_W_GROW_H
01164 ASPECT_CHECK_GROW_W
01165 ASPECT_CHECK_GROW_H
01166 break;
01167 }
01168 case SizemodeShaded:
01169 break;
01170 }
01171 #undef ASPECT_CHECK_SHRINK_H_GROW_W
01172 #undef ASPECT_CHECK_SHRINK_W_GROW_H
01173 #undef ASPECT_CHECK_GROW_W
01174 #undef ASPECT_CHECK_GROW_H
01175 w += xSizeHint.base_width;
01176 h += xSizeHint.base_height;
01177 }
01178 if( !rules()->checkStrictGeometry( false ))
01179 {
01180
01181 if( maximizeMode() & MaximizeHorizontal )
01182 w = w1;
01183 if( maximizeMode() & MaximizeVertical )
01184 h = h1;
01185 }
01186
01187 if( !noframe )
01188 {
01189 w += border_left + border_right;
01190 h += border_top + border_bottom;
01191 }
01192 QSize ret = rules()->checkSize( QSize( w, h ));
01193 if ( mode == SizemodeShaded && wsize.height() == 0 )
01194 ret.setHeight( noframe ? 0 : border_top + border_bottom );
01195 return ret;
01196 }
01197
01201 void Client::getWmNormalHints()
01202 {
01203 long msize;
01204 if (XGetWMNormalHints(qt_xdisplay(), window(), &xSizeHint, &msize) == 0 )
01205 xSizeHint.flags = 0;
01206
01207
01208 if( xSizeHint.flags & PBaseSize )
01209 {
01210
01211
01212
01213 if( ! ( xSizeHint.flags & PMinSize ))
01214 {
01215 xSizeHint.min_width = xSizeHint.base_width;
01216 xSizeHint.min_height = xSizeHint.base_height;
01217 }
01218 }
01219 else
01220 xSizeHint.base_width = xSizeHint.base_height = 0;
01221 if( ! ( xSizeHint.flags & PMinSize ))
01222 xSizeHint.min_width = xSizeHint.min_height = 0;
01223 if( ! ( xSizeHint.flags & PMaxSize ))
01224 xSizeHint.max_width = xSizeHint.max_height = INT_MAX;
01225 else
01226 {
01227 xSizeHint.max_width = QMAX( xSizeHint.max_width, 1 );
01228 xSizeHint.max_height = QMAX( xSizeHint.max_height, 1 );
01229 }
01230 if( xSizeHint.flags & PResizeInc )
01231 {
01232 xSizeHint.width_inc = kMax( xSizeHint.width_inc, 1 );
01233 xSizeHint.height_inc = kMax( xSizeHint.height_inc, 1 );
01234 }
01235 else
01236 {
01237 xSizeHint.width_inc = 1;
01238 xSizeHint.height_inc = 1;
01239 }
01240 if( xSizeHint.flags & PAspect )
01241 {
01242 xSizeHint.min_aspect.y = kMax( xSizeHint.min_aspect.y, 1 );
01243 xSizeHint.max_aspect.y = kMax( xSizeHint.max_aspect.y, 1 );
01244 }
01245 else
01246 {
01247 xSizeHint.min_aspect.x = 1;
01248 xSizeHint.min_aspect.y = INT_MAX;
01249 xSizeHint.max_aspect.x = INT_MAX;
01250 xSizeHint.max_aspect.y = 1;
01251 }
01252 if( ! ( xSizeHint.flags & PWinGravity ))
01253 xSizeHint.win_gravity = NorthWestGravity;
01254 if( isManaged())
01255 {
01256 QSize new_size = adjustedSize( size());
01257 if( new_size != size() && !isFullScreen())
01258 resizeWithChecks( new_size );
01259 }
01260 updateAllowedActions();
01261 }
01262
01263 QSize Client::minSize() const
01264 {
01265 return rules()->checkMinSize( QSize( xSizeHint.min_width, xSizeHint.min_height ));
01266 }
01267
01268 QSize Client::maxSize() const
01269 {
01270 return rules()->checkMaxSize( QSize( xSizeHint.max_width, xSizeHint.max_height ));
01271 }
01272
01278 void Client::sendSyntheticConfigureNotify()
01279 {
01280 XConfigureEvent c;
01281 c.type = ConfigureNotify;
01282 c.send_event = True;
01283 c.event = window();
01284 c.window = window();
01285 c.x = x() + clientPos().x();
01286 c.y = y() + clientPos().y();
01287 c.width = clientSize().width();
01288 c.height = clientSize().height();
01289 c.border_width = 0;
01290 c.above = None;
01291 c.override_redirect = 0;
01292 XSendEvent( qt_xdisplay(), c.event, TRUE, StructureNotifyMask, (XEvent*)&c );
01293 }
01294
01295 const QPoint Client::calculateGravitation( bool invert, int gravity ) const
01296 {
01297 int dx, dy;
01298 dx = dy = 0;
01299
01300 if( gravity == 0 )
01301 gravity = xSizeHint.win_gravity;
01302
01303
01304 switch (gravity)
01305 {
01306 case NorthWestGravity:
01307 default:
01308 dx = border_left;
01309 dy = border_top;
01310 break;
01311 case NorthGravity:
01312 dx = 0;
01313 dy = border_top;
01314 break;
01315 case NorthEastGravity:
01316 dx = -border_right;
01317 dy = border_top;
01318 break;
01319 case WestGravity:
01320 dx = border_left;
01321 dy = 0;
01322 break;
01323 case CenterGravity:
01324 break;
01325 case StaticGravity:
01326 dx = 0;
01327 dy = 0;
01328 break;
01329 case EastGravity:
01330 dx = -border_right;
01331 dy = 0;
01332 break;
01333 case SouthWestGravity:
01334 dx = border_left ;
01335 dy = -border_bottom;
01336 break;
01337 case SouthGravity:
01338 dx = 0;
01339 dy = -border_bottom;
01340 break;
01341 case SouthEastGravity:
01342 dx = -border_right;
01343 dy = -border_bottom;
01344 break;
01345 }
01346 if( gravity != CenterGravity )
01347 {
01348 dx -= border_left;
01349 dy -= border_top;
01350 }
01351 else
01352 {
01353 dx = - ( border_left + border_right ) / 2;
01354 dy = - ( border_top + border_bottom ) / 2;
01355 }
01356 if( !invert )
01357 return QPoint( x() + dx, y() + dy );
01358 else
01359 return QPoint( x() - dx, y() - dy );
01360 }
01361
01362 void Client::configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool )
01363 {
01364 if( gravity == 0 )
01365 gravity = xSizeHint.win_gravity;
01366 if( value_mask & ( CWX | CWY ))
01367 {
01368 QPoint new_pos = calculateGravitation( true, gravity );
01369 if ( value_mask & CWX )
01370 new_pos.setX( rx );
01371 if ( value_mask & CWY )
01372 new_pos.setY( ry );
01373
01374
01375
01376
01377
01378 if ( new_pos.x() == x() + clientPos().x() &&
01379 new_pos.y() == y() + clientPos().y() && gravity == NorthWestGravity )
01380 {
01381 new_pos.setX( x());
01382 new_pos.setY( y());
01383 }
01384
01385 int nw = clientSize().width();
01386 int nh = clientSize().height();
01387 if ( value_mask & CWWidth )
01388 nw = rw;
01389 if ( value_mask & CWHeight )
01390 nh = rh;
01391 QSize ns = sizeForClientSize( QSize( nw, nh ) );
01392
01393
01394 if ( maximizeMode() != MaximizeFull
01395 || ns != size())
01396 {
01397 QRect orig_geometry = geometry();
01398 ++block_geometry;
01399 move( new_pos );
01400 plainResize( ns );
01401 setGeometry( QRect( calculateGravitation( false, gravity ), size()));
01402 updateFullScreenHack( QRect( new_pos, QSize( nw, nh )));
01403 QRect area = workspace()->clientArea( WorkArea, this );
01404 if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen()
01405 && area.contains( orig_geometry ))
01406 keepInArea( area );
01407 --block_geometry;
01408 setGeometry( geometry(), ForceGeometrySet );
01409
01410
01411
01412
01413
01414 if (hasStrut ())
01415 workspace() -> updateClientArea ();
01416 }
01417 }
01418
01419 if ( value_mask & (CWWidth | CWHeight )
01420 && ! ( value_mask & ( CWX | CWY )) )
01421 {
01422 int nw = clientSize().width();
01423 int nh = clientSize().height();
01424 if ( value_mask & CWWidth )
01425 nw = rw;
01426 if ( value_mask & CWHeight )
01427 nh = rh;
01428 QSize ns = sizeForClientSize( QSize( nw, nh ) );
01429
01430 if( ns != size())
01431 {
01432 QRect orig_geometry = geometry();
01433 ++block_geometry;
01434 int save_gravity = xSizeHint.win_gravity;
01435 xSizeHint.win_gravity = gravity;
01436 resizeWithChecks( ns );
01437 xSizeHint.win_gravity = save_gravity;
01438 updateFullScreenHack( QRect( calculateGravitation( true, xSizeHint.win_gravity ), QSize( nw, nh )));
01439 QRect area = workspace()->clientArea( WorkArea, this );
01440 if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen()
01441 && area.contains( orig_geometry ))
01442 keepInArea( area );
01443 --block_geometry;
01444 setGeometry( geometry(), ForceGeometrySet );
01445 }
01446 }
01447
01448
01449
01450 }
01451
01452 void Client::resizeWithChecks( int w, int h, ForceGeometry_t force )
01453 {
01454 int newx = x();
01455 int newy = y();
01456 QRect area = workspace()->clientArea( WorkArea, this );
01457
01458 if( w > area.width())
01459 w = area.width();
01460 if( h > area.height())
01461 h = area.height();
01462 QSize tmp = adjustedSize( QSize( w, h ));
01463 w = tmp.width();
01464 h = tmp.height();
01465 switch( xSizeHint.win_gravity )
01466 {
01467 case NorthWestGravity:
01468 default:
01469 break;
01470 case NorthGravity:
01471 newx = ( newx + width() / 2 ) - ( w / 2 );
01472 break;
01473 case NorthEastGravity:
01474 newx = newx + width() - w;
01475 break;
01476 case WestGravity:
01477 newy = ( newy + height() / 2 ) - ( h / 2 );
01478 break;
01479 case CenterGravity:
01480 newx = ( newx + width() / 2 ) - ( w / 2 );
01481 newy = ( newy + height() / 2 ) - ( h / 2 );
01482 break;
01483 case StaticGravity:
01484
01485 break;
01486 case EastGravity:
01487 newx = newx + width() - w;
01488 newy = ( newy + height() / 2 ) - ( h / 2 );
01489 break;
01490 case SouthWestGravity:
01491 newy = newy + height() - h;
01492 break;
01493 case SouthGravity:
01494 newx = ( newx + width() / 2 ) - ( w / 2 );
01495 newy = newy + height() - h;
01496 break;
01497 case SouthEastGravity:
01498 newx = newx + width() - w;
01499 newy = newy + height() - h;
01500 break;
01501 }
01502
01503
01504 if( workarea_diff_x != INT_MIN && w <= area.width())
01505 {
01506 if( newx < area.left())
01507 newx = area.left();
01508 if( newx + w > area.right() + 1 )
01509 newx = area.right() + 1 - w;
01510 assert( newx >= area.left() && newx + w <= area.right() + 1 );
01511 }
01512 if( workarea_diff_y != INT_MIN && h <= area.height())
01513 {
01514 if( newy < area.top())
01515 newy = area.top();
01516 if( newy + h > area.bottom() + 1 )
01517 newy = area.bottom() + 1 - h;
01518 assert( newy >= area.top() && newy + h <= area.bottom() + 1 );
01519 }
01520 setGeometry( newx, newy, w, h, force );
01521 }
01522
01523
01524 void Client::NETMoveResizeWindow( int flags, int x, int y, int width, int height )
01525 {
01526 int gravity = flags & 0xff;
01527 int value_mask = 0;
01528 if( flags & ( 1 << 8 ))
01529 value_mask |= CWX;
01530 if( flags & ( 1 << 9 ))
01531 value_mask |= CWY;
01532 if( flags & ( 1 << 10 ))
01533 value_mask |= CWWidth;
01534 if( flags & ( 1 << 11 ))
01535 value_mask |= CWHeight;
01536 configureRequest( value_mask, x, y, width, height, gravity, true );
01537 }
01538
01543 bool Client::isMovable() const
01544 {
01545 if( !motif_may_move || isFullScreen())
01546 return false;
01547 if( isSpecialWindow() && !isOverride() && !isSplash() && !isToolbar())
01548 return false;
01549 if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01550 return false;
01551 if( rules()->checkPosition( invalidPoint ) != invalidPoint )
01552 return false;
01553 return true;
01554 }
01555
01559 bool Client::isResizable() const
01560 {
01561 if( !motif_may_resize || isFullScreen())
01562 return false;
01563 if(( isSpecialWindow() || isSplash() || isToolbar()) && !isOverride())
01564 return false;
01565 if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01566 return false;
01567 if( rules()->checkSize( QSize()).isValid())
01568 return false;
01569
01570 QSize min = minSize();
01571 QSize max = maxSize();
01572 return min.width() < max.width() || min.height() < max.height();
01573 }
01574
01575
01576
01577
01578 bool Client::isMaximizable() const
01579 {
01580 {
01581
01582 TemporaryAssign< MaximizeMode > tmp( max_mode, MaximizeRestore );
01583 if( !isMovable() || !isResizable() || isToolbar())
01584 return false;
01585 }
01586 if ( maximizeMode() != MaximizeRestore )
01587 return TRUE;
01588 QSize max = maxSize();
01589 #if 0
01590 if( max.width() < 32767 || max.height() < 32767 )
01591 return false;
01592 #else
01593
01594
01595 QSize areasize = workspace()->clientArea( MaximizeArea, this ).size();
01596 if( max.width() < areasize.width() || max.height() < areasize.height())
01597 return false;
01598 #endif
01599 return true;
01600 }
01601
01602
01606 void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
01607 {
01608 if( force == NormalGeometrySet && frame_geometry == QRect( x, y, w, h ))
01609 return;
01610 h = checkShadeGeometry( w, h );
01611 frame_geometry = QRect( x, y, w, h );
01612 if( !isShade())
01613 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01614 else
01615 client_size = QSize( w - border_left - border_right, client_size.height());
01616 updateWorkareaDiffs();
01617 if( block_geometry == 0 )
01618 {
01619 XMoveResizeWindow( qt_xdisplay(), frameId(), x, y, w, h );
01620 resizeDecoration( QSize( w, h ));
01621 if( !isShade())
01622 {
01623 QSize cs = clientSize();
01624 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01625 cs.width(), cs.height());
01626
01627 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01628 }
01629 if( shape())
01630 updateShape();
01631
01632 updateWorkareaDiffs();
01633 sendSyntheticConfigureNotify();
01634 updateWindowRules();
01635 checkMaximizeGeometry();
01636 }
01637 }
01638
01639 void Client::plainResize( int w, int h, ForceGeometry_t force )
01640 {
01641 if( QSize( w, h ) != rules()->checkSize( QSize( w, h )))
01642 {
01643 kdDebug() << "forced size fail:" << QSize( w,h ) << ":" << rules()->checkSize( QSize( w, h )) << endl;
01644 kdDebug() << kdBacktrace() << endl;
01645 }
01646 if( force == NormalGeometrySet && frame_geometry.size() == QSize( w, h ))
01647 return;
01648 h = checkShadeGeometry( w, h );
01649 frame_geometry.setSize( QSize( w, h ));
01650 if( !isShade())
01651 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01652 else
01653 client_size = QSize( w - border_left - border_right, client_size.height());
01654 updateWorkareaDiffs();
01655 if( block_geometry == 0 )
01656 {
01657 XResizeWindow( qt_xdisplay(), frameId(), w, h );
01658 resizeDecoration( QSize( w, h ));
01659 if( !isShade())
01660 {
01661 QSize cs = clientSize();
01662 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01663 cs.width(), cs.height());
01664 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01665 }
01666 if( shape())
01667 updateShape();
01668 updateWorkareaDiffs();
01669 sendSyntheticConfigureNotify();
01670 updateWindowRules();
01671 checkMaximizeGeometry();
01672 }
01673 }
01674
01675
01676
01677
01678
01679 int Client::checkShadeGeometry( int w, int h )
01680 {
01681
01682 if( isShade() && !shade_geometry_change && h != border_top + border_bottom )
01683 {
01684 kdDebug() << "Fixing shaded geometry:" << this << endl;
01685
01686 client_size = adjustedSize( QSize( w, h ));
01687
01688 h = border_top + border_bottom;
01689 }
01690 return h;
01691 }
01692
01696 void Client::move( int x, int y, ForceGeometry_t force )
01697 {
01698 if( force == NormalGeometrySet && frame_geometry.topLeft() == QPoint( x, y ))
01699 return;
01700 frame_geometry.moveTopLeft( QPoint( x, y ));
01701 updateWorkareaDiffs();
01702 if( block_geometry == 0 )
01703 {
01704 XMoveWindow( qt_xdisplay(), frameId(), x, y );
01705 sendSyntheticConfigureNotify();
01706 updateWindowRules();
01707 checkMaximizeGeometry();
01708 }
01709 }
01710
01711
01712 void Client::maximize( MaximizeMode m )
01713 {
01714 setMaximize( m & MaximizeVertical, m & MaximizeHorizontal );
01715 }
01716
01720 void Client::setMaximize( bool vertically, bool horizontally )
01721 {
01722 changeMaximize(
01723 max_mode & MaximizeVertical ? !vertically : vertically,
01724 max_mode & MaximizeHorizontal ? !horizontally : horizontally,
01725 false );
01726 }
01727
01728 void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
01729 {
01730 if( !isMaximizable())
01731 return;
01732
01733 MaximizeMode old_mode = max_mode;
01734
01735 if( !adjust )
01736 {
01737 if( vertical )
01738 max_mode = MaximizeMode( max_mode ^ MaximizeVertical );
01739 if( horizontal )
01740 max_mode = MaximizeMode( max_mode ^ MaximizeHorizontal );
01741 }
01742
01743 max_mode = rules()->checkMaximize( max_mode );
01744 if( !adjust && max_mode == old_mode )
01745 return;
01746
01747 ++block_geometry;
01748
01749
01750 Q_ASSERT( !( vertical && horizontal )
01751 || (( max_mode & MaximizeVertical != 0 ) == ( max_mode & MaximizeHorizontal != 0 )));
01752
01753 QRect clientArea = workspace()->clientArea( MaximizeArea, this );
01754
01755
01756 if( !( y() == clientArea.top() && height() == clientArea.height()))
01757 {
01758 geom_restore.setTop( y());
01759 geom_restore.setHeight( height());
01760 }
01761 if( !( x() == clientArea.left() && width() == clientArea.width()))
01762 {
01763 geom_restore.setLeft( x());
01764 geom_restore.setWidth( width());
01765 }
01766
01767 if( !adjust )
01768 {
01769 if(( vertical && !(old_mode & MaximizeVertical ))
01770 || ( horizontal && !( old_mode & MaximizeHorizontal )))
01771 Notify::raise( Notify::Maximize );
01772 else
01773 Notify::raise( Notify::UnMaximize );
01774 }
01775
01776 if( decoration != NULL )
01777 decoration->borders( border_left, border_right, border_top, border_bottom );
01778
01779 switch (max_mode)
01780 {
01781
01782 case MaximizeVertical:
01783 {
01784 if( old_mode & MaximizeHorizontal )
01785 {
01786 if( geom_restore.width() == 0 )
01787 {
01788 plainResize( adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH ));
01789 workspace()->placeSmart( this, clientArea );
01790 }
01791 else
01792 setGeometry( QRect(QPoint( geom_restore.x(), clientArea.top()),
01793 adjustedSize(QSize( geom_restore.width(), clientArea.height()), SizemodeFixedH )));
01794 }
01795 else
01796 setGeometry( QRect(QPoint(x(), clientArea.top()),
01797 adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH )));
01798 info->setState( NET::MaxVert, NET::Max );
01799 break;
01800 }
01801
01802 case MaximizeHorizontal:
01803 {
01804 if( old_mode & MaximizeVertical )
01805 {
01806 if( geom_restore.height() == 0 )
01807 {
01808 plainResize( adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW ));
01809 workspace()->placeSmart( this, clientArea );
01810 }
01811 else
01812 setGeometry( QRect( QPoint(clientArea.left(), geom_restore.y()),
01813 adjustedSize(QSize(clientArea.width(), geom_restore.height()), SizemodeFixedW )));
01814 }
01815 else
01816 setGeometry( QRect( QPoint(clientArea.left(), y()),
01817 adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW )));
01818 info->setState( NET::MaxHoriz, NET::Max );
01819 break;
01820 }
01821
01822 case MaximizeRestore:
01823 {
01824 QRect restore = geometry();
01825
01826 if( old_mode & MaximizeVertical )
01827 {
01828 restore.setTop( geom_restore.top());
01829 restore.setBottom( geom_restore.bottom());
01830 }
01831 if( old_mode & MaximizeHorizontal )
01832 {
01833 restore.setLeft( geom_restore.left());
01834 restore.setRight( geom_restore.right());
01835 }
01836 if( !restore.isValid())
01837 {
01838 QSize s = QSize( clientArea.width()*2/3, clientArea.height()*2/3 );
01839 if( geom_restore.width() > 0 )
01840 s.setWidth( geom_restore.width());
01841 if( geom_restore.height() > 0 )
01842 s.setHeight( geom_restore.height());
01843 plainResize( adjustedSize( s ));
01844 workspace()->placeSmart( this, clientArea );
01845 restore = geometry();
01846 if( geom_restore.width() > 0 )
01847 restore.moveLeft( geom_restore.x());
01848 if( geom_restore.height() > 0 )
01849 restore.moveTop( geom_restore.y());
01850 }
01851 setGeometry( restore );
01852 info->setState( 0, NET::Max );
01853 break;
01854 }
01855
01856 case MaximizeFull:
01857 {
01858 QSize adjSize = adjustedSize(clientArea.size(), SizemodeMax );
01859 QRect r = QRect(clientArea.topLeft(), adjSize);
01860 setGeometry( r );
01861 info->setState( NET::Max, NET::Max );
01862 break;
01863 }
01864 default:
01865 break;
01866 }
01867
01868 --block_geometry;
01869 setGeometry( geometry(), ForceGeometrySet );
01870
01871 updateAllowedActions();
01872 if( decoration != NULL )
01873 decoration->maximizeChange();
01874 updateWindowRules();
01875 }
01876
01877 void Client::resetMaximize()
01878 {
01879 if( max_mode == MaximizeRestore )
01880 return;
01881 max_mode = MaximizeRestore;
01882 Notify::raise( Notify::UnMaximize );
01883 info->setState( 0, NET::Max );
01884 updateAllowedActions();
01885 if( decoration != NULL )
01886 decoration->borders( border_left, border_right, border_top, border_bottom );
01887 setGeometry( geometry(), ForceGeometrySet );
01888 if( decoration != NULL )
01889 decoration->maximizeChange();
01890 }
01891
01892 void Client::checkMaximizeGeometry()
01893 {
01894
01895
01896 if( isShade())
01897 return;
01898 if( isMove() || isResize())
01899 return;
01900
01901 static int recursion_protection = 0;
01902 if( recursion_protection > 3 )
01903 {
01904 kdWarning( 1212 ) << "Check maximize overflow - you loose!" << endl;
01905 kdWarning( 1212 ) << kdBacktrace() << endl;
01906 return;
01907 }
01908 ++recursion_protection;
01909 QRect max_area = workspace()->clientArea( MaximizeArea, this );
01910 if( geometry() == max_area )
01911 {
01912 if( max_mode != MaximizeFull )
01913 maximize( MaximizeFull );
01914 }
01915 else if( x() == max_area.left() && width() == max_area.width())
01916 {
01917 if( max_mode != MaximizeHorizontal )
01918 maximize( MaximizeHorizontal );
01919 }
01920 else if( y() == max_area.top() && height() == max_area.height())
01921 {
01922 if( max_mode != MaximizeVertical )
01923 maximize( MaximizeVertical );
01924 }
01925 else if( max_mode != MaximizeRestore )
01926 {
01927 resetMaximize();
01928 }
01929 --recursion_protection;
01930 }
01931
01932 bool Client::isFullScreenable( bool fullscreen_hack ) const
01933 {
01934 if( !rules()->checkFullScreen( true ))
01935 return false;
01936 if( fullscreen_hack )
01937 return isNormalWindow() || isOverride();
01938 if( rules()->checkStrictGeometry( false ))
01939 {
01940
01941 QRect fsarea = workspace()->clientArea( FullScreenArea, this );
01942 if( sizeForClientSize( fsarea.size(), SizemodeAny, true ) != fsarea.size())
01943 return false;
01944 }
01945
01946 return !isSpecialWindow();
01947 }
01948
01949 bool Client::userCanSetFullScreen() const
01950 {
01951 if( fullscreen_mode == FullScreenHack )
01952 return false;
01953 if( !isFullScreenable( false ))
01954 return false;
01955
01956 TemporaryAssign< FullScreenMode > tmp( fullscreen_mode, FullScreenNone );
01957 return isNormalWindow() && isMaximizable();
01958 }
01959
01960 void Client::setFullScreen( bool set, bool user )
01961 {
01962 if( !isFullScreen() && !set )
01963 return;
01964 if( fullscreen_mode == FullScreenHack )
01965 return;
01966 if( user && !userCanSetFullScreen())
01967 return;
01968 set = rules()->checkFullScreen( set );
01969 setShade( ShadeNone );
01970 bool was_fs = isFullScreen();
01971 if( !was_fs )
01972 geom_fs_restore = geometry();
01973 fullscreen_mode = set ? FullScreenNormal : FullScreenNone;
01974 if( was_fs == isFullScreen())
01975 return;
01976 StackingUpdatesBlocker blocker( workspace());
01977 workspace()->updateClientLayer( this );
01978 info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen );
01979 updateDecoration( false, false );
01980 if( isFullScreen())
01981 setGeometry( workspace()->clientArea( FullScreenArea, this ));
01982 else
01983 {
01984 if( maximizeMode() != MaximizeRestore )
01985 changeMaximize( false, false, true );
01986 else if( !geom_fs_restore.isNull())
01987 setGeometry( QRect( geom_fs_restore.topLeft(), adjustedSize( geom_fs_restore.size())));
01988
01989 else
01990 {
01991 setGeometry( workspace()->clientArea( MaximizeArea, this ));
01992 }
01993 }
01994 updateWindowRules();
01995 }
01996
01997 bool Client::checkFullScreenHack( const QRect& geom ) const
01998 {
01999
02000 return (( geom.size() == workspace()->clientArea( FullArea, geom.center(), desktop()).size()
02001 || geom.size() == workspace()->clientArea( ScreenArea, geom.center(), desktop()).size())
02002 && noBorder() && !isUserNoBorder() && isFullScreenable( true ));
02003 }
02004
02005 void Client::updateFullScreenHack( const QRect& geom )
02006 {
02007 bool is_hack = checkFullScreenHack( geom );
02008 if( fullscreen_mode == FullScreenNone && is_hack )
02009 {
02010 fullscreen_mode = FullScreenHack;
02011 updateDecoration( false, false );
02012 setGeometry( workspace()->clientArea( FullScreenArea, this ));
02013 }
02014 else if( fullscreen_mode == FullScreenHack && !is_hack )
02015 {
02016 fullscreen_mode = FullScreenNone;
02017 updateDecoration( false, false );
02018
02019 }
02020 StackingUpdatesBlocker blocker( workspace());
02021 workspace()->updateClientLayer( this );
02022 }
02023
02024 static QRect* visible_bound = 0;
02025 static GeometryTip* geometryTip = 0;
02026
02027 void Client::drawbound( const QRect& geom )
02028 {
02029 assert( visible_bound == NULL );
02030 visible_bound = new QRect( geom );
02031 doDrawbound( *visible_bound, false );
02032 }
02033
02034 void Client::clearbound()
02035 {
02036 if( visible_bound == NULL )
02037 return;
02038 doDrawbound( *visible_bound, true );
02039 delete visible_bound;
02040 visible_bound = 0;
02041 }
02042
02043 void Client::doDrawbound( const QRect& geom, bool clear )
02044 {
02045 if( decoration != NULL && decoration->drawbound( geom, clear ))
02046 return;
02047 QPainter p ( workspace()->desktopWidget() );
02048 p.setPen( QPen( Qt::white, 5 ) );
02049 p.setRasterOp( Qt::XorROP );
02050
02051
02052 QRect g = geom;
02053 if( g.width() > 5 )
02054 {
02055 g.setLeft( g.left() + 2 );
02056 g.setRight( g.right() - 2 );
02057 }
02058 if( g.height() > 5 )
02059 {
02060 g.setTop( g.top() + 2 );
02061 g.setBottom( g.bottom() - 2 );
02062 }
02063 p.drawRect( g );
02064 }
02065
02066 void Client::positionGeometryTip()
02067 {
02068 assert( isMove() || isResize());
02069
02070 if (options->showGeometryTip())
02071 {
02072 if( !geometryTip )
02073 {
02074 bool save_under = ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02075 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque );
02076 geometryTip = new GeometryTip( &xSizeHint, save_under );
02077 }
02078 QRect wgeom( moveResizeGeom );
02079 wgeom.setWidth( wgeom.width() - ( width() - clientSize().width()));
02080 wgeom.setHeight( wgeom.height() - ( height() - clientSize().height()));
02081 if( isShade())
02082 wgeom.setHeight( 0 );
02083 geometryTip->setGeometry( wgeom );
02084 if( !geometryTip->isVisible())
02085 {
02086 geometryTip->show();
02087 geometryTip->raise();
02088 }
02089 }
02090 }
02091
02092 class EatAllPaintEvents
02093 : public QObject
02094 {
02095 protected:
02096 virtual bool eventFilter( QObject* o, QEvent* e )
02097 { return e->type() == QEvent::Paint && o != geometryTip; }
02098 };
02099
02100 static EatAllPaintEvents* eater = 0;
02101
02102 bool Client::startMoveResize()
02103 {
02104 assert( !moveResizeMode );
02105 assert( QWidget::keyboardGrabber() == NULL );
02106 assert( QWidget::mouseGrabber() == NULL );
02107 if( QApplication::activePopupWidget() != NULL )
02108 return false;
02109 bool has_grab = false;
02110
02111
02112
02113 XSetWindowAttributes attrs;
02114 QRect r = workspace()->clientArea( FullArea, this );
02115 move_resize_grab_window = XCreateWindow( qt_xdisplay(), workspace()->rootWin(), r.x(), r.y(),
02116 r.width(), r.height(), 0, CopyFromParent, InputOnly, CopyFromParent, 0, &attrs );
02117 XMapRaised( qt_xdisplay(), move_resize_grab_window );
02118 if( XGrabPointer( qt_xdisplay(), move_resize_grab_window, False,
02119 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask,
02120 GrabModeAsync, GrabModeAsync, None, cursor.handle(), qt_x_time ) == Success )
02121 has_grab = true;
02122 if( XGrabKeyboard( qt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, qt_x_time ) == Success )
02123 has_grab = true;
02124 if( !has_grab )
02125 {
02126 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02127 move_resize_grab_window = None;
02128 return false;
02129 }
02130 if ( maximizeMode() != MaximizeRestore )
02131 resetMaximize();
02132 moveResizeMode = true;
02133 workspace()->setClientIsMoving(this);
02134 initialMoveResizeGeom = moveResizeGeom = geometry();
02135 checkUnrestrictedMoveResize();
02136
02137 if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02138 setShadowSize(0);
02139 if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){
02140 savedOpacity_ = opacity_;
02141 setOpacity(options->translucentMovingWindows, options->movingWindowOpacity);
02142 }
02143 if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02144 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02145 {
02146 grabXServer();
02147 kapp->sendPostedEvents();
02148
02149
02150
02151
02152
02153 eater = new EatAllPaintEvents;
02154
02155 }
02156 Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
02157 return true;
02158 }
02159
02160 void Client::finishMoveResize( bool cancel )
02161 {
02162 leaveMoveResize();
02163 if( cancel )
02164 setGeometry( initialMoveResizeGeom );
02165 else
02166 setGeometry( moveResizeGeom );
02167 checkMaximizeGeometry();
02168
02169 Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
02170 }
02171
02172 void Client::leaveMoveResize()
02173 {
02174
02175 if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque)
02176 setOpacity(true, savedOpacity_);
02177 if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02178 updateShadowSize();
02179 clearbound();
02180 if (geometryTip)
02181 {
02182 geometryTip->hide();
02183 delete geometryTip;
02184 geometryTip = NULL;
02185 }
02186 if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02187 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02188 ungrabXServer();
02189 XUngrabKeyboard( qt_xdisplay(), qt_x_time );
02190 XUngrabPointer( qt_xdisplay(), qt_x_time );
02191 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02192 move_resize_grab_window = None;
02193 workspace()->setClientIsMoving(0);
02194 if( move_faked_activity )
02195 workspace()->unfakeActivity( this );
02196 move_faked_activity = false;
02197 moveResizeMode = false;
02198 delete eater;
02199 eater = 0;
02200 }
02201
02202
02203
02204
02205
02206 void Client::checkUnrestrictedMoveResize()
02207 {
02208 if( unrestrictedMoveResize )
02209 return;
02210 QRect desktopArea = workspace()->clientArea( WorkArea, moveResizeGeom.center(), desktop());
02211 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02212
02213
02214 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02215 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02216
02217 titlebar_marge = initialMoveResizeGeom.height();
02218 top_marge = border_bottom;
02219 bottom_marge = border_top;
02220 if( isResize())
02221 {
02222 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02223 unrestrictedMoveResize = true;
02224 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02225 unrestrictedMoveResize = true;
02226 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02227 unrestrictedMoveResize = true;
02228 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02229 unrestrictedMoveResize = true;
02230 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
02231 unrestrictedMoveResize = true;
02232 }
02233 if( isMove())
02234 {
02235 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
02236 unrestrictedMoveResize = true;
02237
02238 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02239 unrestrictedMoveResize = true;
02240 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02241 unrestrictedMoveResize = true;
02242 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02243 unrestrictedMoveResize = true;
02244 }
02245 }
02246
02247 void Client::handleMoveResize( int x, int y, int x_root, int y_root )
02248 {
02249 if(( mode == PositionCenter && !isMovable())
02250 || ( mode != PositionCenter && ( isShade() || !isResizable())))
02251 return;
02252
02253 if ( !moveResizeMode )
02254 {
02255 QPoint p( QPoint( x, y ) - moveOffset );
02256 if (p.manhattanLength() >= 6)
02257 {
02258 if( !startMoveResize())
02259 {
02260 buttonDown = false;
02261 setCursor( mode );
02262 return;
02263 }
02264 }
02265 else
02266 return;
02267 }
02268
02269
02270 if ( mode != PositionCenter && shade_mode != ShadeNone )
02271 setShade( ShadeNone );
02272
02273 QPoint globalPos( x_root, y_root );
02274
02275
02276 QPoint topleft = globalPos - moveOffset;
02277 QPoint bottomright = globalPos + invertedMoveOffset;
02278 QRect previousMoveResizeGeom = moveResizeGeom;
02279
02280
02281
02282
02283
02284 QRect desktopArea = workspace()->clientArea( WorkArea, globalPos, desktop());
02285 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02286 if( unrestrictedMoveResize )
02287 left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5;
02288 else
02289 {
02290
02291 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02292 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02293
02294 titlebar_marge = initialMoveResizeGeom.height();
02295 top_marge = border_bottom;
02296 bottom_marge = border_top;
02297 }
02298
02299 bool update = false;
02300 if( isResize())
02301 {
02302
02303 QRect orig = initialMoveResizeGeom;
02304 Sizemode sizemode = SizemodeAny;
02305 switch ( mode )
02306 {
02307 case PositionTopLeft:
02308 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
02309 break;
02310 case PositionBottomRight:
02311 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
02312 break;
02313 case PositionBottomLeft:
02314 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
02315 break;
02316 case PositionTopRight:
02317 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02318 break;
02319 case PositionTop:
02320 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), orig.bottomRight() ) ;
02321 sizemode = SizemodeFixedH;
02322 break;
02323 case PositionBottom:
02324 moveResizeGeom = QRect( orig.topLeft(), QPoint( orig.right(), bottomright.y() ) ) ;
02325 sizemode = SizemodeFixedH;
02326 break;
02327 case PositionLeft:
02328 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), orig.bottomRight() ) ;
02329 sizemode = SizemodeFixedW;
02330 break;
02331 case PositionRight:
02332 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), orig.bottom() ) ) ;
02333 sizemode = SizemodeFixedW;
02334 break;
02335 case PositionCenter:
02336 default:
02337 assert( false );
02338 break;
02339 }
02340
02341
02342 moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode );
02343
02344
02345 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02346 moveResizeGeom.setBottom( desktopArea.top() + top_marge );
02347 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02348 moveResizeGeom.setTop( desktopArea.bottom() - bottom_marge );
02349 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02350 moveResizeGeom.setRight( desktopArea.left() + left_marge );
02351 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02352 moveResizeGeom.setLeft(desktopArea.right() - right_marge );
02353 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
02354 moveResizeGeom.setTop( desktopArea.top());
02355
02356 QSize size = adjustedSize( moveResizeGeom.size(), sizemode );
02357
02358 topleft = QPoint( moveResizeGeom.right() - size.width() + 1, moveResizeGeom.bottom() - size.height() + 1 );
02359 bottomright = QPoint( moveResizeGeom.left() + size.width() - 1, moveResizeGeom.top() + size.height() - 1 );
02360 orig = moveResizeGeom;
02361 switch ( mode )
02362 {
02363 case PositionTopLeft:
02364 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
02365 break;
02366 case PositionBottomRight:
02367 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
02368 break;
02369 case PositionBottomLeft:
02370 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
02371 break;
02372 case PositionTopRight:
02373 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02374 break;
02375
02376
02377
02378 case PositionTop:
02379 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02380 break;
02381 case PositionBottom:
02382 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
02383 break;
02384 case PositionLeft:
02385 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), QPoint( orig.right(), bottomright.y()));
02386 break;
02387 case PositionRight:
02388 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
02389 break;
02390 case PositionCenter:
02391 default:
02392 assert( false );
02393 break;
02394 }
02395 if( moveResizeGeom.size() != previousMoveResizeGeom.size())
02396 update = true;
02397 }
02398 else if( isMove())
02399 {
02400 assert( mode == PositionCenter );
02401
02402 moveResizeGeom.moveTopLeft( topleft );
02403 moveResizeGeom.moveTopLeft( workspace()->adjustClientPosition( this, moveResizeGeom.topLeft() ) );
02404
02405 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
02406 moveResizeGeom.moveBottom( desktopArea.top() + titlebar_marge - 1 );
02407
02408 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02409 moveResizeGeom.moveTop( desktopArea.bottom() - bottom_marge );
02410 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02411 moveResizeGeom.moveRight( desktopArea.left() + left_marge );
02412 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02413 moveResizeGeom.moveLeft(desktopArea.right() - right_marge );
02414 if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft())
02415 update = true;
02416 }
02417 else
02418 assert( false );
02419
02420 if( update )
02421 {
02422 if( rules()->checkMoveResizeMode
02423 ( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque )
02424 {
02425 setGeometry( moveResizeGeom );
02426 positionGeometryTip();
02427 }
02428 else if( rules()->checkMoveResizeMode
02429 ( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent )
02430 {
02431 clearbound();
02432 positionGeometryTip();
02433 drawbound( moveResizeGeom );
02434 }
02435 }
02436 if ( isMove() )
02437 workspace()->clientMoved(globalPos, qt_x_time);
02438 }
02439
02440
02441 }