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 new_pos = rules()->checkPosition( new_pos );
01448
01449
01450 if ( maximizeMode() != MaximizeFull
01451 || ns != size())
01452 {
01453 QRect orig_geometry = geometry();
01454 GeometryUpdatesPostponer blocker( this );
01455 move( new_pos );
01456 plainResize( ns );
01457 setGeometry( QRect( calculateGravitation( false, gravity ), size()));
01458 updateFullScreenHack( QRect( new_pos, QSize( nw, nh )));
01459 QRect area = workspace()->clientArea( WorkArea, this );
01460 if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen()
01461 && area.contains( orig_geometry ))
01462 keepInArea( area );
01463
01464
01465
01466
01467
01468 if (hasStrut ())
01469 workspace() -> updateClientArea ();
01470 }
01471 }
01472
01473 if ( value_mask & (CWWidth | CWHeight )
01474 && ! ( value_mask & ( CWX | CWY )) )
01475 {
01476 int nw = clientSize().width();
01477 int nh = clientSize().height();
01478 if ( value_mask & CWWidth )
01479 nw = rw;
01480 if ( value_mask & CWHeight )
01481 nh = rh;
01482 QSize ns = sizeForClientSize( QSize( nw, nh ) );
01483
01484 if( ns != size())
01485 {
01486 QRect orig_geometry = geometry();
01487 GeometryUpdatesPostponer blocker( this );
01488 int save_gravity = xSizeHint.win_gravity;
01489 xSizeHint.win_gravity = gravity;
01490 resizeWithChecks( ns );
01491 xSizeHint.win_gravity = save_gravity;
01492 updateFullScreenHack( QRect( calculateGravitation( true, xSizeHint.win_gravity ), QSize( nw, nh )));
01493 if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen())
01494 {
01495
01496
01497 QRect area = workspace()->clientArea( MovementArea, this );
01498 if( area.contains( orig_geometry ))
01499 keepInArea( area );
01500 area = workspace()->clientArea( WorkArea, this );
01501 if( area.contains( orig_geometry ))
01502 keepInArea( area );
01503 }
01504 }
01505 }
01506
01507
01508
01509 }
01510
01511 void Client::resizeWithChecks( int w, int h, ForceGeometry_t force )
01512 {
01513 if( shade_geometry_change )
01514 assert( false );
01515 else if( isShade())
01516 {
01517 if( h == border_top + border_bottom )
01518 {
01519 kdWarning() << "Shaded geometry passed for size:" << endl;
01520 kdWarning() << kdBacktrace() << endl;
01521 }
01522 }
01523 int newx = x();
01524 int newy = y();
01525 QRect area = workspace()->clientArea( WorkArea, this );
01526
01527 if( w > area.width())
01528 w = area.width();
01529 if( h > area.height())
01530 h = area.height();
01531 QSize tmp = adjustedSize( QSize( w, h ));
01532 w = tmp.width();
01533 h = tmp.height();
01534 switch( xSizeHint.win_gravity )
01535 {
01536 case NorthWestGravity:
01537 default:
01538 break;
01539 case NorthGravity:
01540 newx = ( newx + width() / 2 ) - ( w / 2 );
01541 break;
01542 case NorthEastGravity:
01543 newx = newx + width() - w;
01544 break;
01545 case WestGravity:
01546 newy = ( newy + height() / 2 ) - ( h / 2 );
01547 break;
01548 case CenterGravity:
01549 newx = ( newx + width() / 2 ) - ( w / 2 );
01550 newy = ( newy + height() / 2 ) - ( h / 2 );
01551 break;
01552 case StaticGravity:
01553
01554 break;
01555 case EastGravity:
01556 newx = newx + width() - w;
01557 newy = ( newy + height() / 2 ) - ( h / 2 );
01558 break;
01559 case SouthWestGravity:
01560 newy = newy + height() - h;
01561 break;
01562 case SouthGravity:
01563 newx = ( newx + width() / 2 ) - ( w / 2 );
01564 newy = newy + height() - h;
01565 break;
01566 case SouthEastGravity:
01567 newx = newx + width() - w;
01568 newy = newy + height() - h;
01569 break;
01570 }
01571
01572
01573 if( workarea_diff_x != INT_MIN && w <= area.width())
01574 {
01575 if( newx < area.left())
01576 newx = area.left();
01577 if( newx + w > area.right() + 1 )
01578 newx = area.right() + 1 - w;
01579 assert( newx >= area.left() && newx + w <= area.right() + 1 );
01580 }
01581 if( workarea_diff_y != INT_MIN && h <= area.height())
01582 {
01583 if( newy < area.top())
01584 newy = area.top();
01585 if( newy + h > area.bottom() + 1 )
01586 newy = area.bottom() + 1 - h;
01587 assert( newy >= area.top() && newy + h <= area.bottom() + 1 );
01588 }
01589 setGeometry( newx, newy, w, h, force );
01590 }
01591
01592
01593 void Client::NETMoveResizeWindow( int flags, int x, int y, int width, int height )
01594 {
01595 int gravity = flags & 0xff;
01596 int value_mask = 0;
01597 if( flags & ( 1 << 8 ))
01598 value_mask |= CWX;
01599 if( flags & ( 1 << 9 ))
01600 value_mask |= CWY;
01601 if( flags & ( 1 << 10 ))
01602 value_mask |= CWWidth;
01603 if( flags & ( 1 << 11 ))
01604 value_mask |= CWHeight;
01605 configureRequest( value_mask, x, y, width, height, gravity, true );
01606 }
01607
01612 bool Client::isMovable() const
01613 {
01614 if( !motif_may_move || isFullScreen())
01615 return false;
01616 if( isSpecialWindow() && !isSplash() && !isToolbar())
01617 return false;
01618 if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01619 return false;
01620 if( rules()->checkPosition( invalidPoint ) != invalidPoint )
01621 return false;
01622 return true;
01623 }
01624
01628 bool Client::isResizable() const
01629 {
01630 if( !motif_may_resize || isFullScreen())
01631 return false;
01632 if( isSpecialWindow() )
01633 return false;
01634 if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01635 return false;
01636 if( rules()->checkSize( QSize()).isValid())
01637 return false;
01638
01639 QSize min = minSize();
01640 QSize max = maxSize();
01641 return min.width() < max.width() || min.height() < max.height();
01642 }
01643
01644
01645
01646
01647 bool Client::isMaximizable() const
01648 {
01649 {
01650
01651 TemporaryAssign< MaximizeMode > tmp( max_mode, MaximizeRestore );
01652 if( !isMovable() || !isResizable() || isToolbar())
01653 return false;
01654 }
01655 if ( maximizeMode() != MaximizeRestore )
01656 return TRUE;
01657 QSize max = maxSize();
01658 #if 0
01659 if( max.width() < 32767 || max.height() < 32767 )
01660 return false;
01661 #else
01662
01663
01664 QSize areasize = workspace()->clientArea( MaximizeArea, this ).size();
01665 if( max.width() < areasize.width() || max.height() < areasize.height())
01666 return false;
01667 #endif
01668 return true;
01669 }
01670
01671
01675 void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
01676 {
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688 if( shade_geometry_change )
01689 ;
01690 else if( isShade())
01691 {
01692 if( h == border_top + border_bottom )
01693 {
01694 kdDebug() << "Shaded geometry passed for size:" << endl;
01695 kdDebug() << kdBacktrace() << endl;
01696 }
01697 else
01698 {
01699 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01700 h = border_top + border_bottom;
01701 }
01702 }
01703 else
01704 {
01705 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01706 }
01707 if( force == NormalGeometrySet && frame_geometry == QRect( x, y, w, h ))
01708 return;
01709 frame_geometry = QRect( x, y, w, h );
01710 updateWorkareaDiffs();
01711 if( postpone_geometry_updates != 0 )
01712 {
01713 pending_geometry_update = true;
01714 return;
01715 }
01716 resizeDecoration( QSize( w, h ));
01717 XMoveResizeWindow( qt_xdisplay(), frameId(), x, y, w, h );
01718
01719 if( !isShade())
01720 {
01721 QSize cs = clientSize();
01722 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01723 cs.width(), cs.height());
01724 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01725 }
01726 updateShape();
01727
01728 updateWorkareaDiffs();
01729 sendSyntheticConfigureNotify();
01730 updateWindowRules();
01731 checkMaximizeGeometry();
01732 workspace()->checkActiveScreen( this );
01733 }
01734
01735 void Client::plainResize( int w, int h, ForceGeometry_t force )
01736 {
01737
01738 if( shade_geometry_change )
01739 ;
01740 else if( isShade())
01741 {
01742 if( h == border_top + border_bottom )
01743 {
01744 kdDebug() << "Shaded geometry passed for size:" << endl;
01745 kdDebug() << kdBacktrace() << endl;
01746 }
01747 else
01748 {
01749 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01750 h = border_top + border_bottom;
01751 }
01752 }
01753 else
01754 {
01755 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01756 }
01757 if( QSize( w, h ) != rules()->checkSize( QSize( w, h )))
01758 {
01759 kdDebug() << "forced size fail:" << QSize( w,h ) << ":" << rules()->checkSize( QSize( w, h )) << endl;
01760 kdDebug() << kdBacktrace() << endl;
01761 }
01762 if( force == NormalGeometrySet && frame_geometry.size() == QSize( w, h ))
01763 return;
01764 frame_geometry.setSize( QSize( w, h ));
01765 updateWorkareaDiffs();
01766 if( postpone_geometry_updates != 0 )
01767 {
01768 pending_geometry_update = true;
01769 return;
01770 }
01771 resizeDecoration( QSize( w, h ));
01772 XResizeWindow( qt_xdisplay(), frameId(), w, h );
01773
01774 if( !isShade())
01775 {
01776 QSize cs = clientSize();
01777 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01778 cs.width(), cs.height());
01779 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01780 }
01781 updateShape();
01782 updateWorkareaDiffs();
01783 sendSyntheticConfigureNotify();
01784 updateWindowRules();
01785 checkMaximizeGeometry();
01786 workspace()->checkActiveScreen( this );
01787 }
01788
01792 void Client::move( int x, int y, ForceGeometry_t force )
01793 {
01794 if( force == NormalGeometrySet && frame_geometry.topLeft() == QPoint( x, y ))
01795 return;
01796 frame_geometry.moveTopLeft( QPoint( x, y ));
01797 updateWorkareaDiffs();
01798 if( postpone_geometry_updates != 0 )
01799 {
01800 pending_geometry_update = true;
01801 return;
01802 }
01803 XMoveWindow( qt_xdisplay(), frameId(), x, y );
01804 sendSyntheticConfigureNotify();
01805 updateWindowRules();
01806 checkMaximizeGeometry();
01807 workspace()->checkActiveScreen( this );
01808 }
01809
01810
01811 void Client::postponeGeometryUpdates( bool postpone )
01812 {
01813 if( postpone )
01814 {
01815 if( postpone_geometry_updates == 0 )
01816 pending_geometry_update = false;
01817 ++postpone_geometry_updates;
01818 }
01819 else
01820 {
01821 if( --postpone_geometry_updates == 0 )
01822 {
01823 if( pending_geometry_update )
01824 {
01825 if( isShade())
01826 setGeometry( QRect( pos(), adjustedSize()), ForceGeometrySet );
01827 else
01828 setGeometry( geometry(), ForceGeometrySet );
01829 pending_geometry_update = false;
01830 }
01831 }
01832 }
01833 }
01834
01835 void Client::maximize( MaximizeMode m )
01836 {
01837 setMaximize( m & MaximizeVertical, m & MaximizeHorizontal );
01838 }
01839
01843 void Client::setMaximize( bool vertically, bool horizontally )
01844 {
01845 changeMaximize(
01846 max_mode & MaximizeVertical ? !vertically : vertically,
01847 max_mode & MaximizeHorizontal ? !horizontally : horizontally,
01848 false );
01849 }
01850
01851 void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
01852 {
01853 if( !isMaximizable())
01854 return;
01855
01856 MaximizeMode old_mode = max_mode;
01857
01858 if( !adjust )
01859 {
01860 if( vertical )
01861 max_mode = MaximizeMode( max_mode ^ MaximizeVertical );
01862 if( horizontal )
01863 max_mode = MaximizeMode( max_mode ^ MaximizeHorizontal );
01864 }
01865
01866 max_mode = rules()->checkMaximize( max_mode );
01867 if( !adjust && max_mode == old_mode )
01868 return;
01869
01870 GeometryUpdatesPostponer blocker( this );
01871
01872
01873 Q_ASSERT( !( vertical && horizontal )
01874 || ((( max_mode & MaximizeVertical ) != 0 ) == (( max_mode & MaximizeHorizontal ) != 0 )));
01875
01876 QRect clientArea = workspace()->clientArea( MaximizeArea, this );
01877
01878
01879 if( !adjust && !( y() == clientArea.top() && height() == clientArea.height()))
01880 {
01881 geom_restore.setTop( y());
01882 geom_restore.setHeight( height());
01883 }
01884 if( !adjust && !( x() == clientArea.left() && width() == clientArea.width()))
01885 {
01886 geom_restore.setLeft( x());
01887 geom_restore.setWidth( width());
01888 }
01889
01890 if( !adjust )
01891 {
01892 if(( vertical && !(old_mode & MaximizeVertical ))
01893 || ( horizontal && !( old_mode & MaximizeHorizontal )))
01894 Notify::raise( Notify::Maximize );
01895 else
01896 Notify::raise( Notify::UnMaximize );
01897 }
01898
01899 if( decoration != NULL )
01900 decoration->borders( border_left, border_right, border_top, border_bottom );
01901
01902
01903 if ( old_mode==MaximizeFull && max_mode==MaximizeRestore )
01904 {
01905 if ( maximizeModeRestore()==MaximizeVertical )
01906 {
01907 max_mode = MaximizeVertical;
01908 maxmode_restore = MaximizeRestore;
01909 }
01910 if ( maximizeModeRestore()==MaximizeHorizontal )
01911 {
01912 max_mode = MaximizeHorizontal;
01913 maxmode_restore = MaximizeRestore;
01914 }
01915 }
01916
01917 switch (max_mode)
01918 {
01919
01920 case MaximizeVertical:
01921 {
01922 if( old_mode & MaximizeHorizontal )
01923 {
01924 if( geom_restore.width() == 0 )
01925 {
01926 plainResize( adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH ));
01927 workspace()->placeSmart( this, clientArea );
01928 }
01929 else
01930 setGeometry( QRect(QPoint( geom_restore.x(), clientArea.top()),
01931 adjustedSize(QSize( geom_restore.width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet);
01932 }
01933 else
01934 setGeometry( QRect(QPoint(x(), clientArea.top()),
01935 adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet);
01936 info->setState( NET::MaxVert, NET::Max );
01937 break;
01938 }
01939
01940 case MaximizeHorizontal:
01941 {
01942 if( old_mode & MaximizeVertical )
01943 {
01944 if( geom_restore.height() == 0 )
01945 {
01946 plainResize( adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW ));
01947 workspace()->placeSmart( this, clientArea );
01948 }
01949 else
01950 setGeometry( QRect( QPoint(clientArea.left(), geom_restore.y()),
01951 adjustedSize(QSize(clientArea.width(), geom_restore.height()), SizemodeFixedW )), ForceGeometrySet);
01952 }
01953 else
01954 setGeometry( QRect( QPoint(clientArea.left(), y()),
01955 adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW )), ForceGeometrySet);
01956 info->setState( NET::MaxHoriz, NET::Max );
01957 break;
01958 }
01959
01960 case MaximizeRestore:
01961 {
01962 QRect restore = geometry();
01963
01964 if( old_mode & MaximizeVertical )
01965 {
01966 restore.setTop( geom_restore.top());
01967 restore.setBottom( geom_restore.bottom());
01968 }
01969 if( old_mode & MaximizeHorizontal )
01970 {
01971 restore.setLeft( geom_restore.left());
01972 restore.setRight( geom_restore.right());
01973 }
01974 if( !restore.isValid())
01975 {
01976 QSize s = QSize( clientArea.width()*2/3, clientArea.height()*2/3 );
01977 if( geom_restore.width() > 0 )
01978 s.setWidth( geom_restore.width());
01979 if( geom_restore.height() > 0 )
01980 s.setHeight( geom_restore.height());
01981 plainResize( adjustedSize( s ));
01982 workspace()->placeSmart( this, clientArea );
01983 restore = geometry();
01984 if( geom_restore.width() > 0 )
01985 restore.moveLeft( geom_restore.x());
01986 if( geom_restore.height() > 0 )
01987 restore.moveTop( geom_restore.y());
01988 }
01989 setGeometry( restore, ForceGeometrySet );
01990 info->setState( 0, NET::Max );
01991 break;
01992 }
01993
01994 case MaximizeFull:
01995 {
01996 if( !adjust )
01997 {
01998 if( old_mode & MaximizeVertical )
01999 maxmode_restore = MaximizeVertical;
02000 if( old_mode & MaximizeHorizontal )
02001 maxmode_restore = MaximizeHorizontal;
02002 }
02003 QSize adjSize = adjustedSize(clientArea.size(), SizemodeMax );
02004 QRect r = QRect(clientArea.topLeft(), adjSize);
02005 setGeometry( r, ForceGeometrySet );
02006 info->setState( NET::Max, NET::Max );
02007 break;
02008 }
02009 default:
02010 break;
02011 }
02012
02013 updateAllowedActions();
02014 if( decoration != NULL )
02015 decoration->maximizeChange();
02016 updateWindowRules();
02017 }
02018
02019 void Client::resetMaximize()
02020 {
02021 if( max_mode == MaximizeRestore )
02022 return;
02023 max_mode = MaximizeRestore;
02024 Notify::raise( Notify::UnMaximize );
02025 info->setState( 0, NET::Max );
02026 updateAllowedActions();
02027 if( decoration != NULL )
02028 decoration->borders( border_left, border_right, border_top, border_bottom );
02029 if( isShade())
02030 setGeometry( QRect( pos(), sizeForClientSize( clientSize())), ForceGeometrySet );
02031 else
02032 setGeometry( geometry(), ForceGeometrySet );
02033 if( decoration != NULL )
02034 decoration->maximizeChange();
02035 }
02036
02037 void Client::checkMaximizeGeometry()
02038 {
02039
02040
02041 if( isShade())
02042 return;
02043 if( isMove() || isResize())
02044 return;
02045
02046 static int recursion_protection = 0;
02047 if( recursion_protection > 3 )
02048 {
02049 kdWarning( 1212 ) << "Check maximize overflow - you loose!" << endl;
02050 kdWarning( 1212 ) << kdBacktrace() << endl;
02051 return;
02052 }
02053 ++recursion_protection;
02054 QRect max_area = workspace()->clientArea( MaximizeArea, this );
02055 if( geometry() == max_area )
02056 {
02057 if( max_mode != MaximizeFull )
02058 maximize( MaximizeFull );
02059 }
02060 else if( x() == max_area.left() && width() == max_area.width())
02061 {
02062 if( max_mode != MaximizeHorizontal )
02063 maximize( MaximizeHorizontal );
02064 }
02065 else if( y() == max_area.top() && height() == max_area.height())
02066 {
02067 if( max_mode != MaximizeVertical )
02068 maximize( MaximizeVertical );
02069 }
02070 else if( max_mode != MaximizeRestore )
02071 {
02072 resetMaximize();
02073 }
02074 --recursion_protection;
02075 }
02076
02077 bool Client::isFullScreenable( bool fullscreen_hack ) const
02078 {
02079 if( !rules()->checkFullScreen( true ))
02080 return false;
02081 if( fullscreen_hack )
02082 return isNormalWindow();
02083 if( rules()->checkStrictGeometry( false ))
02084 {
02085
02086 QRect fsarea = workspace()->clientArea( FullScreenArea, this );
02087 if( sizeForClientSize( fsarea.size(), SizemodeAny, true ) != fsarea.size())
02088 return false;
02089 }
02090
02091 return !isSpecialWindow();
02092 }
02093
02094 bool Client::userCanSetFullScreen() const
02095 {
02096 if( fullscreen_mode == FullScreenHack )
02097 return false;
02098 if( !isFullScreenable( false ))
02099 return false;
02100
02101 TemporaryAssign< FullScreenMode > tmp( fullscreen_mode, FullScreenNone );
02102 return isNormalWindow() && isMaximizable();
02103 }
02104
02105 void Client::setFullScreen( bool set, bool user )
02106 {
02107 if( !isFullScreen() && !set )
02108 return;
02109 if( fullscreen_mode == FullScreenHack )
02110 return;
02111 if( user && !userCanSetFullScreen())
02112 return;
02113 set = rules()->checkFullScreen( set );
02114 setShade( ShadeNone );
02115 bool was_fs = isFullScreen();
02116 if( !was_fs )
02117 geom_fs_restore = geometry();
02118 fullscreen_mode = set ? FullScreenNormal : FullScreenNone;
02119 if( was_fs == isFullScreen())
02120 return;
02121 StackingUpdatesBlocker blocker1( workspace());
02122 GeometryUpdatesPostponer blocker2( this );
02123 workspace()->updateClientLayer( this );
02124 info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen );
02125 updateDecoration( false, false );
02126 if( isFullScreen())
02127 setGeometry( workspace()->clientArea( FullScreenArea, this ));
02128 else
02129 {
02130 if( !geom_fs_restore.isNull())
02131 setGeometry( QRect( geom_fs_restore.topLeft(), adjustedSize( geom_fs_restore.size())));
02132
02133 else
02134 {
02135 setGeometry( workspace()->clientArea( MaximizeArea, this ));
02136 }
02137 }
02138 updateWindowRules();
02139 }
02140
02141 int Client::checkFullScreenHack( const QRect& geom ) const
02142 {
02143
02144 if( noBorder() && !isUserNoBorder() && isFullScreenable( true ))
02145 {
02146 if( geom.size() == workspace()->clientArea( FullArea, geom.center(), desktop()).size())
02147 return 2;
02148 if( geom.size() == workspace()->clientArea( ScreenArea, geom.center(), desktop()).size())
02149 return 1;
02150 }
02151 return 0;
02152 }
02153
02154 void Client::updateFullScreenHack( const QRect& geom )
02155 {
02156 int type = checkFullScreenHack( geom );
02157 if( fullscreen_mode == FullScreenNone && type != 0 )
02158 {
02159 fullscreen_mode = FullScreenHack;
02160 updateDecoration( false, false );
02161 QRect geom;
02162 if( rules()->checkStrictGeometry( false ))
02163 {
02164 geom = type == 2
02165 ? workspace()->clientArea( FullArea, geom.center(), desktop())
02166 : workspace()->clientArea( ScreenArea, geom.center(), desktop());
02167 }
02168 else
02169 geom = workspace()->clientArea( FullScreenArea, geom.center(), desktop());
02170 setGeometry( geom );
02171 }
02172 else if( fullscreen_mode == FullScreenHack && type == 0 )
02173 {
02174 fullscreen_mode = FullScreenNone;
02175 updateDecoration( false, false );
02176
02177 }
02178 StackingUpdatesBlocker blocker( workspace());
02179 workspace()->updateClientLayer( this );
02180 }
02181
02182 static QRect* visible_bound = 0;
02183 static GeometryTip* geometryTip = 0;
02184
02185 void Client::drawbound( const QRect& geom )
02186 {
02187 assert( visible_bound == NULL );
02188 visible_bound = new QRect( geom );
02189 doDrawbound( *visible_bound, false );
02190 }
02191
02192 void Client::clearbound()
02193 {
02194 if( visible_bound == NULL )
02195 return;
02196 doDrawbound( *visible_bound, true );
02197 delete visible_bound;
02198 visible_bound = 0;
02199 }
02200
02201 void Client::doDrawbound( const QRect& geom, bool clear )
02202 {
02203 if( decoration != NULL && decoration->drawbound( geom, clear ))
02204 return;
02205 QPainter p ( workspace()->desktopWidget() );
02206 p.setPen( QPen( Qt::white, 5 ) );
02207 p.setRasterOp( Qt::XorROP );
02208
02209
02210 QRect g = geom;
02211 if( g.width() > 5 )
02212 {
02213 g.setLeft( g.left() + 2 );
02214 g.setRight( g.right() - 2 );
02215 }
02216 if( g.height() > 5 )
02217 {
02218 g.setTop( g.top() + 2 );
02219 g.setBottom( g.bottom() - 2 );
02220 }
02221 p.drawRect( g );
02222 }
02223
02224 void Client::positionGeometryTip()
02225 {
02226 assert( isMove() || isResize());
02227
02228 if (options->showGeometryTip())
02229 {
02230 if( !geometryTip )
02231 {
02232 bool save_under = ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02233 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque );
02234 geometryTip = new GeometryTip( &xSizeHint, save_under );
02235 }
02236 QRect wgeom( moveResizeGeom );
02237 wgeom.setWidth( wgeom.width() - ( width() - clientSize().width()));
02238 wgeom.setHeight( wgeom.height() - ( height() - clientSize().height()));
02239 if( isShade())
02240 wgeom.setHeight( 0 );
02241 geometryTip->setGeometry( wgeom );
02242 if( !geometryTip->isVisible())
02243 {
02244 geometryTip->show();
02245 geometryTip->raise();
02246 }
02247 }
02248 }
02249
02250 class EatAllPaintEvents
02251 : public QObject
02252 {
02253 protected:
02254 virtual bool eventFilter( QObject* o, QEvent* e )
02255 { return e->type() == QEvent::Paint && o != geometryTip; }
02256 };
02257
02258 static EatAllPaintEvents* eater = 0;
02259
02260 bool Client::startMoveResize()
02261 {
02262 assert( !moveResizeMode );
02263 assert( QWidget::keyboardGrabber() == NULL );
02264 assert( QWidget::mouseGrabber() == NULL );
02265 if( QApplication::activePopupWidget() != NULL )
02266 return false;
02267 bool has_grab = false;
02268
02269
02270
02271 XSetWindowAttributes attrs;
02272 QRect r = workspace()->clientArea( FullArea, this );
02273 move_resize_grab_window = XCreateWindow( qt_xdisplay(), workspace()->rootWin(), r.x(), r.y(),
02274 r.width(), r.height(), 0, CopyFromParent, InputOnly, CopyFromParent, 0, &attrs );
02275 XMapRaised( qt_xdisplay(), move_resize_grab_window );
02276 if( XGrabPointer( qt_xdisplay(), move_resize_grab_window, False,
02277 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask,
02278 GrabModeAsync, GrabModeAsync, move_resize_grab_window, cursor.handle(), qt_x_time ) == Success )
02279 has_grab = true;
02280 if( XGrabKeyboard( qt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, qt_x_time ) == Success )
02281 has_grab = true;
02282 if( !has_grab )
02283 {
02284 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02285 move_resize_grab_window = None;
02286 return false;
02287 }
02288 if ( maximizeMode() != MaximizeRestore )
02289 resetMaximize();
02290 moveResizeMode = true;
02291 workspace()->setClientIsMoving(this);
02292 initialMoveResizeGeom = moveResizeGeom = geometry();
02293 checkUnrestrictedMoveResize();
02294
02295 if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02296 setShadowSize(0);
02297 if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){
02298 savedOpacity_ = opacity_;
02299 setOpacity(options->translucentMovingWindows, options->movingWindowOpacity);
02300 }
02301 if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02302 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02303 {
02304 grabXServer();
02305 kapp->sendPostedEvents();
02306
02307
02308
02309
02310
02311 eater = new EatAllPaintEvents;
02312
02313 }
02314 Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
02315 return true;
02316 }
02317
02318 void Client::finishMoveResize( bool cancel )
02319 {
02320 leaveMoveResize();
02321 if( cancel )
02322 setGeometry( initialMoveResizeGeom );
02323 else
02324 setGeometry( moveResizeGeom );
02325 checkMaximizeGeometry();
02326
02327 Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
02328 }
02329
02330 void Client::leaveMoveResize()
02331 {
02332
02333 if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque)
02334 setOpacity(true, savedOpacity_);
02335 if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02336 updateShadowSize();
02337 clearbound();
02338 if (geometryTip)
02339 {
02340 geometryTip->hide();
02341 delete geometryTip;
02342 geometryTip = NULL;
02343 }
02344 if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02345 || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02346 ungrabXServer();
02347 XUngrabKeyboard( qt_xdisplay(), qt_x_time );
02348 XUngrabPointer( qt_xdisplay(), qt_x_time );
02349 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02350 move_resize_grab_window = None;
02351 workspace()->setClientIsMoving(0);
02352 if( move_faked_activity )
02353 workspace()->unfakeActivity( this );
02354 move_faked_activity = false;
02355 moveResizeMode = false;
02356 delete eater;
02357 eater = 0;
02358 }
02359
02360
02361
02362
02363
02364 void Client::checkUnrestrictedMoveResize()
02365 {
02366 if( unrestrictedMoveResize )
02367 return;
02368 QRect desktopArea = workspace()->clientArea( WorkArea, moveResizeGeom.center(), desktop());
02369 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02370
02371
02372 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02373 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02374
02375 titlebar_marge = initialMoveResizeGeom.height();
02376 top_marge = border_bottom;
02377 bottom_marge = border_top;
02378 if( isResize())
02379 {
02380 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02381 unrestrictedMoveResize = true;
02382 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02383 unrestrictedMoveResize = true;
02384 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02385 unrestrictedMoveResize = true;
02386 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02387 unrestrictedMoveResize = true;
02388 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
02389 unrestrictedMoveResize = true;
02390 }
02391 if( isMove())
02392 {
02393 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
02394 unrestrictedMoveResize = true;
02395
02396 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02397 unrestrictedMoveResize = true;
02398 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02399 unrestrictedMoveResize = true;
02400 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02401 unrestrictedMoveResize = true;
02402 }
02403 }
02404
02405 void Client::handleMoveResize( int x, int y, int x_root, int y_root )
02406 {
02407 if(( mode == PositionCenter && !isMovable())
02408 || ( mode != PositionCenter && ( isShade() || !isResizable())))
02409 return;
02410
02411 if ( !moveResizeMode )
02412 {
02413 QPoint p( QPoint( x, y ) - moveOffset );
02414 if (p.manhattanLength() >= 6)
02415 {
02416 if( !startMoveResize())
02417 {
02418 buttonDown = false;
02419 setCursor( mode );
02420 return;
02421 }
02422 }
02423 else
02424 return;
02425 }
02426
02427
02428 if ( mode != PositionCenter && shade_mode != ShadeNone )
02429 setShade( ShadeNone );
02430
02431 QPoint globalPos( x_root, y_root );
02432
02433
02434 QPoint topleft = globalPos - moveOffset;
02435 QPoint bottomright = globalPos + invertedMoveOffset;
02436 QRect previousMoveResizeGeom = moveResizeGeom;
02437
02438
02439
02440
02441
02442 QRect desktopArea = workspace()->clientArea( WorkArea, globalPos, desktop());
02443 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02444 if( unrestrictedMoveResize )
02445 left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5;
02446 else
02447 {
02448
02449 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02450 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02451
02452 titlebar_marge = initialMoveResizeGeom.height();
02453 top_marge = border_bottom;
02454 bottom_marge = border_top;
02455 }
02456
02457 bool update = false;
02458 if( isResize())
02459 {
02460
02461 QRect orig = initialMoveResizeGeom;
02462 Sizemode sizemode = SizemodeAny;
02463 switch ( mode )
02464 {
02465 case PositionTopLeft:
02466 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
02467 break;
02468 case PositionBottomRight:
02469 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
02470 break;
02471 case PositionBottomLeft:
02472 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
02473 break;
02474 case PositionTopRight:
02475 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02476 break;
02477 case PositionTop:
02478 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), orig.bottomRight() ) ;
02479 sizemode = SizemodeFixedH;
02480 break;
02481 case PositionBottom:
02482 moveResizeGeom = QRect( orig.topLeft(), QPoint( orig.right(), bottomright.y() ) ) ;
02483 sizemode = SizemodeFixedH;
02484 break;
02485 case PositionLeft:
02486 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), orig.bottomRight() ) ;
02487 sizemode = SizemodeFixedW;
02488 break;
02489 case PositionRight:
02490 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), orig.bottom() ) ) ;
02491 sizemode = SizemodeFixedW;
02492 break;
02493 case PositionCenter:
02494 default:
02495 assert( false );
02496 break;
02497 }
02498
02499
02500 moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode );
02501
02502
02503 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02504 moveResizeGeom.setBottom( desktopArea.top() + top_marge );
02505 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02506 moveResizeGeom.setTop( desktopArea.bottom() - bottom_marge );
02507 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02508 moveResizeGeom.setRight( desktopArea.left() + left_marge );
02509 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02510 moveResizeGeom.setLeft(desktopArea.right() - right_marge );
02511 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
02512 moveResizeGeom.setTop( desktopArea.top());
02513
02514 QSize size = adjustedSize( moveResizeGeom.size(), sizemode );
02515
02516 topleft = QPoint( moveResizeGeom.right() - size.width() + 1, moveResizeGeom.bottom() - size.height() + 1 );
02517 bottomright = QPoint( moveResizeGeom.left() + size.width() - 1, moveResizeGeom.top() + size.height() - 1 );
02518 orig = moveResizeGeom;
02519 switch ( mode )
02520 {
02521 case PositionTopLeft:
02522 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
02523 break;
02524 case PositionBottomRight:
02525 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
02526 break;
02527 case PositionBottomLeft:
02528 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
02529 break;
02530 case PositionTopRight:
02531 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02532 break;
02533
02534
02535
02536 case PositionTop:
02537 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
02538 break;
02539 case PositionBottom:
02540 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
02541 break;
02542 case PositionLeft:
02543 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), QPoint( orig.right(), bottomright.y()));
02544 break;
02545 case PositionRight:
02546 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
02547 break;
02548 case PositionCenter:
02549 default:
02550 assert( false );
02551 break;
02552 }
02553 if( moveResizeGeom.size() != previousMoveResizeGeom.size())
02554 update = true;
02555 }
02556 else if( isMove())
02557 {
02558 assert( mode == PositionCenter );
02559
02560 moveResizeGeom.moveTopLeft( topleft );
02561 moveResizeGeom.moveTopLeft( workspace()->adjustClientPosition( this, moveResizeGeom.topLeft() ) );
02562
02563 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
02564 moveResizeGeom.moveBottom( desktopArea.top() + titlebar_marge - 1 );
02565
02566 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02567 moveResizeGeom.moveTop( desktopArea.bottom() - bottom_marge );
02568 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02569 moveResizeGeom.moveRight( desktopArea.left() + left_marge );
02570 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02571 moveResizeGeom.moveLeft(desktopArea.right() - right_marge );
02572 if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft())
02573 update = true;
02574 }
02575 else
02576 assert( false );
02577
02578 if( update )
02579 {
02580 if( rules()->checkMoveResizeMode
02581 ( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque )
02582 {
02583 setGeometry( moveResizeGeom );
02584 positionGeometryTip();
02585 }
02586 else if( rules()->checkMoveResizeMode
02587 ( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent )
02588 {
02589 clearbound();
02590 positionGeometryTip();
02591 drawbound( moveResizeGeom );
02592 }
02593 }
02594 if ( isMove() )
02595 workspace()->clientMoved(globalPos, qt_x_time);
02596 }
02597
02598
02599 }