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