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