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