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