• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kwin
 

kwin

geometry.cpp

00001 /*****************************************************************
00002  KWin - the KDE window manager
00003  This file is part of the KDE project.
00004 
00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
00007 
00008 You can Freely distribute this program under the GNU General Public
00009 License. See the file "COPYING" for the exact licensing terms.
00010 ******************************************************************/
00011 
00012 /*
00013 
00014  This file contains things relevant to geometry, i.e. workspace size,
00015  window positions and window sizes.
00016 
00017 */
00018 
00019 #include "client.h"
00020 #include "workspace.h"
00021 
00022 #include <kapplication.h>
00023 #include <kglobal.h>
00024 #include <tqpainter.h>
00025 #include <kwin.h>
00026 
00027 #include "placement.h"
00028 #include "notifications.h"
00029 #include "geometrytip.h"
00030 #include "rules.h"
00031 
00032 namespace KWinInternal
00033 {
00034 
00035 //********************************************
00036 // Workspace
00037 //********************************************
00038 
00042 void Workspace::desktopResized()
00043     {
00044     //printf("Workspace::desktopResized()\n");
00045     TQRect geom = KApplication::desktop()->geometry();
00046     NETSize desktop_geometry;
00047     desktop_geometry.width = geom.width();
00048     desktop_geometry.height = geom.height();
00049     rootInfo->setDesktopGeometry( -1, desktop_geometry );
00050 
00051     updateClientArea( true );
00052     checkElectricBorders( true );
00053     }
00054 
00058 void Workspace::kDestopResized()
00059     {
00060     //printf("Workspace::kDesktopResized()\n");
00061     TQRect geom = KApplication::desktop()->geometry();
00062     NETSize desktop_geometry;
00063     desktop_geometry.width = geom.width();
00064     desktop_geometry.height = geom.height();
00065     rootInfo->setDesktopGeometry( -1, desktop_geometry );
00066 
00067     updateClientArea( true );
00068     checkElectricBorders( true );
00069     }
00070 
00083 void Workspace::updateClientArea( bool force )
00084     {
00085     TQDesktopWidget *desktopwidget = KApplication::desktop();
00086     int nscreens = desktopwidget -> numScreens ();
00087 //    kdDebug () << "screens: " << nscreens << endl;
00088     TQRect* new_wareas = new TQRect[ numberOfDesktops() + 1 ];
00089     TQRect** new_sareas = new TQRect*[ numberOfDesktops() + 1];
00090     TQRect* screens = new TQRect [ nscreens ];
00091     TQRect desktopArea = desktopwidget -> geometry ();
00092     for( int iS = 0;
00093             iS < nscreens;
00094             iS ++ )
00095         {
00096             screens [iS] = desktopwidget -> screenGeometry (iS);
00097         }
00098     for( int i = 1;
00099             i <= numberOfDesktops();
00100             ++i )
00101         {
00102             new_wareas[ i ] = desktopArea;
00103             new_sareas[ i ] = new TQRect [ nscreens ];
00104             for( int iS = 0;
00105                     iS < nscreens;
00106                     iS ++ )
00107                 new_sareas[ i ][ iS ] = screens[ iS ];
00108         }
00109     for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00110         {
00111             if( !(*it)->hasStrut())
00112                 continue;
00113             TQRect r = (*it)->adjustedClientArea( desktopArea, desktopArea );
00114             if( (*it)->isOnAllDesktops())
00115                 for( int i = 1;
00116                         i <= numberOfDesktops();
00117                         ++i )
00118                     {
00119                         new_wareas[ i ] = new_wareas[ i ].intersect( r );
00120                         for( int iS = 0;
00121                                 iS < nscreens;
00122                                 iS ++ )
00123                             new_sareas[ i ][ iS ] =
00124                                 new_sareas[ i ][ iS ].intersect(
00125                                         (*it)->adjustedClientArea( desktopArea, screens[ iS ] )
00126                                     );
00127                     }
00128             else
00129                 {
00130                     new_wareas[ (*it)->desktop() ] = new_wareas[ (*it)->desktop() ].intersect( r );
00131                     for( int iS = 0;
00132                             iS < nscreens;
00133                             iS ++ )
00134                         {
00135 //                            kdDebug () << "adjusting new_sarea: " << screens[ iS ] << endl;
00136                             new_sareas[ (*it)->desktop() ][ iS ] =
00137                                 new_sareas[ (*it)->desktop() ][ iS ].intersect(
00138                                         (*it)->adjustedClientArea( desktopArea, screens[ iS ] )
00139                                         );
00140                         }
00141                 }
00142         }
00143 #if 0
00144     for( int i = 1;
00145             i <= numberOfDesktops();
00146             ++i )
00147         {
00148             for( int iS = 0;
00149                     iS < nscreens;
00150                     iS ++ )
00151                 kdDebug () << "new_sarea: " << new_sareas[ i ][ iS ] << endl;
00152         }
00153 #endif
00154     // TODO topmenu update for screenarea changes?
00155     if( topmenu_space != NULL )
00156         {
00157         TQRect topmenu_area = desktopArea;
00158         topmenu_area.setTop( topMenuHeight());
00159         for( int i = 1;
00160              i <= numberOfDesktops();
00161              ++i )
00162             new_wareas[ i ] = new_wareas[ i ].intersect( topmenu_area );
00163         }
00164 
00165     bool changed = force;
00166 
00167     if (! screenarea)
00168         changed = true;
00169 
00170     for( int i = 1;
00171          !changed && i <= numberOfDesktops();
00172          ++i )
00173         {
00174             if( workarea[ i ] != new_wareas[ i ] )
00175                 changed = true;
00176             for( int iS = 0;
00177                     iS < nscreens;
00178                     iS ++ )
00179                 if (new_sareas[ i ][ iS ] != screenarea [ i ][ iS ])
00180                     changed = true;
00181         }
00182 
00183     if ( changed )
00184         {
00185         delete[] workarea;
00186         workarea = new_wareas;
00187         new_wareas = NULL;
00188         delete[] screenarea;
00189         screenarea = new_sareas;
00190         new_sareas = NULL;
00191         NETRect r;
00192         for( int i = 1; i <= numberOfDesktops(); i++)
00193             {
00194             r.pos.x = workarea[ i ].x();
00195             r.pos.y = workarea[ i ].y();
00196             r.size.width = workarea[ i ].width();
00197             r.size.height = workarea[ i ].height();
00198             rootInfo->setWorkArea( i, r );
00199             }
00200 
00201         updateTopMenuGeometry();
00202         for( ClientList::ConstIterator it = clients.begin();
00203              it != clients.end();
00204              ++it)
00205             (*it)->checkWorkspacePosition();
00206         for( ClientList::ConstIterator it = desktops.begin();
00207              it != desktops.end();
00208              ++it)
00209             (*it)->checkWorkspacePosition();
00210         }
00211     delete[] screens;
00212     delete[] new_sareas;
00213     delete[] new_wareas;
00214     }
00215 
00216 void Workspace::updateClientArea()
00217     {
00218     updateClientArea( false );
00219     }
00220 
00221 
00229 TQRect Workspace::clientArea( clientAreaOption opt, int screen, int desktop ) const
00230     {
00231     if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 )
00232         desktop = currentDesktop();
00233     TQDesktopWidget *desktopwidget = kapp->desktop();
00234     TQRect sarea = screenarea // may be NULL during KWin initialization
00235         ? screenarea[ desktop ][ screen ]
00236         : desktopwidget->screenGeometry( screen );
00237     TQRect warea = workarea[ desktop ].isNull()
00238         ? kapp->desktop()->geometry()
00239         : workarea[ desktop ];
00240     switch (opt)
00241         {
00242         case MaximizeArea:
00243             if (options->xineramaMaximizeEnabled)
00244                 if (desktopwidget->numScreens() < 2)
00245                     return warea;
00246                 else
00247                     return sarea;
00248             else
00249                 return warea;
00250         case MaximizeFullArea:
00251             if (options->xineramaMaximizeEnabled)
00252                 if (desktopwidget->numScreens() < 2)
00253                     return desktopwidget->geometry();
00254                 else
00255                     return desktopwidget->screenGeometry( screen );
00256             else
00257                 return desktopwidget->geometry();
00258         case FullScreenArea:
00259             if (options->xineramaFullscreenEnabled)
00260                 if (desktopwidget->numScreens() < 2)
00261                     return desktopwidget->geometry();
00262                 else
00263                     return desktopwidget->screenGeometry( screen );
00264             else
00265                 return desktopwidget->geometry();
00266         case PlacementArea:
00267             if (options->xineramaPlacementEnabled)
00268                 if (desktopwidget->numScreens() < 2)
00269                     return warea;
00270                 else
00271                     return sarea;
00272             else
00273                 return warea;
00274         case MovementArea:
00275             if (options->xineramaMovementEnabled)
00276                 if (desktopwidget->numScreens() < 2)
00277                     return desktopwidget->geometry();
00278                 else
00279                     return desktopwidget->screenGeometry( screen );
00280             else
00281                 return desktopwidget->geometry();
00282         case WorkArea:
00283             return warea;
00284         case FullArea:
00285             return desktopwidget->geometry();
00286         case ScreenArea:
00287             if (desktopwidget->numScreens() < 2)
00288                 return desktopwidget->geometry();
00289             else
00290                 return desktopwidget->screenGeometry( screen );
00291         }
00292     assert( false );
00293     return TQRect();
00294     }
00295 
00296 TQRect Workspace::clientArea( clientAreaOption opt, const TQPoint& p, int desktop ) const
00297     {
00298     TQDesktopWidget *desktopwidget = KApplication::desktop();
00299     int screen = desktopwidget->screenNumber( p );
00300     if( screen < 0 )
00301         screen = desktopwidget->primaryScreen();
00302     return clientArea( opt, screen, desktop );
00303     }
00304 
00305 TQRect Workspace::clientArea( clientAreaOption opt, const Client* c ) const
00306     {
00307     return clientArea( opt, c->geometry().center(), c->desktop());
00308     }
00309 
00310 
00316 TQPoint Workspace::adjustClientPosition( Client* c, TQPoint pos )
00317     {
00318    //CT 16mar98, 27May98 - magics: BorderSnapZone, WindowSnapZone
00319    //CT adapted for kwin on 25Nov1999
00320    //aleXXX 02Nov2000 added second snapping mode
00321     if (options->windowSnapZone || options->borderSnapZone )
00322         {
00323         const bool sOWO=options->snapOnlyWhenOverlapping;
00324         const TQRect maxRect = clientArea(MovementArea, pos+c->rect().center(), c->desktop());
00325         const int xmin = maxRect.left();
00326         const int xmax = maxRect.right()+1;               //desk size
00327         const int ymin = maxRect.top();
00328         const int ymax = maxRect.bottom()+1;
00329 
00330         const int cx(pos.x());
00331         const int cy(pos.y());
00332         const int cw(c->width());
00333         const int ch(c->height());
00334         const int rx(cx+cw);
00335         const int ry(cy+ch);                 //these don't change
00336 
00337         int nx(cx), ny(cy);                         //buffers
00338         int deltaX(xmax);
00339         int deltaY(ymax);   //minimum distance to other clients
00340 
00341         int lx, ly, lrx, lry; //coords and size for the comparison client, l
00342 
00343       // border snap
00344         int snap = options->borderSnapZone; //snap trigger
00345         if (snap)
00346             {
00347             if ((sOWO?(cx<xmin):true) && (QABS(xmin-cx)<snap))
00348                 {
00349                 deltaX = xmin-cx;
00350                 nx = xmin;
00351                 }
00352             if ((sOWO?(rx>xmax):true) && (QABS(rx-xmax)<snap) && (QABS(xmax-rx) < deltaX))
00353                 {
00354                 deltaX = rx-xmax;
00355                 nx = xmax - cw;
00356                 }
00357 
00358             if ((sOWO?(cy<ymin):true) && (QABS(ymin-cy)<snap))
00359                 {
00360                 deltaY = ymin-cy;
00361                 ny = ymin;
00362                 }
00363             if ((sOWO?(ry>ymax):true) && (QABS(ry-ymax)<snap) && (QABS(ymax-ry) < deltaY))
00364                 {
00365                 deltaY =ry-ymax;
00366                 ny = ymax - ch;
00367                 }
00368             }
00369 
00370       // windows snap
00371         snap = options->windowSnapZone;
00372         if (snap)
00373             {
00374             TQValueList<Client *>::ConstIterator l;
00375             for (l = clients.begin();l != clients.end();++l )
00376                 {
00377                 if ((*l)->isOnDesktop(currentDesktop()) &&
00378                    !(*l)->isMinimized()
00379                     && (*l) != c )
00380                     {
00381                     lx = (*l)->x();
00382                     ly = (*l)->y();
00383                     lrx = lx + (*l)->width();
00384                     lry = ly + (*l)->height();
00385 
00386                     if ( (( cy <= lry ) && ( cy  >= ly  ))  ||
00387                          (( ry >= ly  ) && ( ry  <= lry ))  ||
00388                          (( cy <= ly  ) && ( ry >= lry  )) )
00389                         {
00390                         if ((sOWO?(cx<lrx):true) && (QABS(lrx-cx)<snap) && ( QABS(lrx -cx) < deltaX) )
00391                             {
00392                             deltaX = QABS( lrx - cx );
00393                             nx = lrx;
00394                             }
00395                         if ((sOWO?(rx>lx):true) && (QABS(rx-lx)<snap) && ( QABS( rx - lx )<deltaX) )
00396                             {
00397                             deltaX = QABS(rx - lx);
00398                             nx = lx - cw;
00399                             }
00400                         }
00401 
00402                     if ( (( cx <= lrx ) && ( cx  >= lx  ))  ||
00403                          (( rx >= lx  ) && ( rx  <= lrx ))  ||
00404                          (( cx <= lx  ) && ( rx >= lrx  )) )
00405                         {
00406                         if ((sOWO?(cy<lry):true) && (QABS(lry-cy)<snap) && (QABS( lry -cy ) < deltaY))
00407                             {
00408                             deltaY = QABS( lry - cy );
00409                             ny = lry;
00410                             }
00411                   //if ( (QABS( ry-ly ) < snap) && (QABS( ry - ly ) < deltaY ))
00412                         if ((sOWO?(ry>ly):true) && (QABS(ry-ly)<snap) && (QABS( ry - ly ) < deltaY ))
00413                             {
00414                             deltaY = QABS( ry - ly );
00415                             ny = ly - ch;
00416                             }
00417                         }
00418                     }
00419                 }
00420             }
00421         pos = TQPoint(nx, ny);
00422         }
00423     return pos;
00424     }
00425 
00426 TQRect Workspace::adjustClientSize( Client* c, TQRect moveResizeGeom, int mode )
00427     {
00428    //adapted from adjustClientPosition on 29May2004
00429    //this function is called when resizing a window and will modify
00430    //the new dimensions to snap to other windows/borders if appropriate
00431     if ( options->windowSnapZone || options->borderSnapZone  )
00432         {
00433         const bool sOWO=options->snapOnlyWhenOverlapping;
00434 
00435         const TQRect maxRect = clientArea(MovementArea, c->rect().center(), c->desktop());
00436         const int xmin = maxRect.left();
00437         const int xmax = maxRect.right();               //desk size
00438         const int ymin = maxRect.top();
00439         const int ymax = maxRect.bottom();
00440 
00441         const int cx(moveResizeGeom.left());
00442         const int cy(moveResizeGeom.top());
00443         const int rx(moveResizeGeom.right());
00444         const int ry(moveResizeGeom.bottom());
00445 
00446         int newcx(cx), newcy(cy);                         //buffers
00447         int newrx(rx), newry(ry);
00448         int deltaX(xmax);
00449         int deltaY(ymax);   //minimum distance to other clients
00450 
00451         int lx, ly, lrx, lry; //coords and size for the comparison client, l
00452 
00453       // border snap
00454         int snap = options->borderSnapZone; //snap trigger
00455         if (snap)
00456             {
00457             deltaX = int(snap);
00458             deltaY = int(snap);
00459 
00460 #define SNAP_BORDER_TOP \
00461             if ((sOWO?(newcy<ymin):true) && (QABS(ymin-newcy)<deltaY)) \
00462               { \
00463                 deltaY = QABS(ymin-newcy); \
00464                 newcy = ymin; \
00465                }
00466 
00467 #define SNAP_BORDER_BOTTOM \
00468             if ((sOWO?(newry>ymax):true) && (QABS(ymax-newry)<deltaY)) \
00469               { \
00470                 deltaY = QABS(ymax-newcy); \
00471                 newry = ymax; \
00472                }
00473 
00474 #define SNAP_BORDER_LEFT \
00475             if ((sOWO?(newcx<xmin):true) && (QABS(xmin-newcx)<deltaX)) \
00476               { \
00477                 deltaX = QABS(xmin-newcx); \
00478                 newcx = xmin; \
00479                }
00480 
00481 #define SNAP_BORDER_RIGHT \
00482             if ((sOWO?(newrx>xmax):true) && (QABS(xmax-newrx)<deltaX)) \
00483               { \
00484                 deltaX = QABS(xmax-newrx); \
00485                 newrx = xmax; \
00486                }
00487                      switch ( mode )
00488                       {
00489                       case PositionBottomRight:
00490                         SNAP_BORDER_BOTTOM
00491                         SNAP_BORDER_RIGHT
00492                         break;
00493                       case PositionRight:
00494                         SNAP_BORDER_RIGHT
00495                         break;
00496                       case PositionBottom:
00497                         SNAP_BORDER_BOTTOM
00498                         break;
00499                       case PositionTopLeft:
00500                         SNAP_BORDER_TOP
00501                         SNAP_BORDER_LEFT
00502                         break;
00503                       case PositionLeft:
00504                         SNAP_BORDER_LEFT
00505                         break;
00506                       case PositionTop:
00507                         SNAP_BORDER_TOP
00508                         break;
00509                       case PositionTopRight:
00510                         SNAP_BORDER_TOP
00511                         SNAP_BORDER_RIGHT
00512                         break;
00513                       case PositionBottomLeft:
00514                         SNAP_BORDER_BOTTOM
00515                         SNAP_BORDER_LEFT
00516                         break;
00517                       default:
00518                         assert( false );
00519                         break;
00520                       }
00521 
00522 
00523             }
00524 
00525       // windows snap
00526         snap = options->windowSnapZone;
00527         if (snap)
00528             {
00529             deltaX = int(snap);
00530             deltaY = int(snap);
00531             TQValueList<Client *>::ConstIterator l;
00532             for (l = clients.begin();l != clients.end();++l )
00533                 {
00534                 if ((*l)->isOnDesktop(currentDesktop()) &&
00535                    !(*l)->isMinimized()
00536                     && (*l) != c )
00537                     {
00538                     lx = (*l)->x()-1;
00539                     ly = (*l)->y()-1;
00540                     lrx =(*l)->x() + (*l)->width();
00541                     lry =(*l)->y() + (*l)->height();
00542 
00543 #define WITHIN_HEIGHT ((( newcy <= lry ) && ( newcy  >= ly  ))  || \
00544                          (( newry >= ly  ) && ( newry  <= lry ))  || \
00545                          (( newcy <= ly  ) && ( newry >= lry  )) )
00546 
00547 #define WITHIN_WIDTH  ( (( cx <= lrx ) && ( cx  >= lx  ))  || \
00548                          (( rx >= lx  ) && ( rx  <= lrx ))  || \
00549                          (( cx <= lx  ) && ( rx >= lrx  )) )
00550 
00551 #define SNAP_WINDOW_TOP  if ( (sOWO?(newcy<lry):true) \
00552                   && WITHIN_WIDTH  \
00553                   && (QABS( lry - newcy ) < deltaY) ) {  \
00554                   deltaY = QABS( lry - newcy ); \
00555                   newcy=lry; \
00556                   }
00557 
00558 #define SNAP_WINDOW_BOTTOM  if ( (sOWO?(newry>ly):true)  \
00559                      && WITHIN_WIDTH  \
00560                      && (QABS( ly - newry ) < deltaY) ) {  \
00561                      deltaY = QABS( ly - newry );  \
00562                      newry=ly;  \
00563                      }
00564 
00565 #define SNAP_WINDOW_LEFT  if ( (sOWO?(newcx<lrx):true)  \
00566                    && WITHIN_HEIGHT  \
00567                    && (QABS( lrx - newcx ) < deltaX)) {  \
00568                    deltaX = QABS( lrx - newcx );  \
00569                    newcx=lrx;  \
00570                    }
00571 
00572 #define SNAP_WINDOW_RIGHT  if ( (sOWO?(newrx>lx):true)  \
00573                     && WITHIN_HEIGHT  \
00574                     && (QABS( lx - newrx ) < deltaX))  \
00575                     {  \
00576                     deltaX = QABS( lx - newrx );  \
00577                     newrx=lx;  \
00578                     }
00579 
00580                     switch ( mode )
00581                       {
00582                       case PositionBottomRight:
00583                         SNAP_WINDOW_BOTTOM
00584                         SNAP_WINDOW_RIGHT
00585                         break;
00586                       case PositionRight:
00587                         SNAP_WINDOW_RIGHT
00588                         break;
00589                       case PositionBottom:
00590                         SNAP_WINDOW_BOTTOM
00591                         break;
00592                       case PositionTopLeft:
00593                         SNAP_WINDOW_TOP
00594                         SNAP_WINDOW_LEFT
00595                         break;
00596                       case PositionLeft:
00597                         SNAP_WINDOW_LEFT
00598                         break;
00599                       case PositionTop:
00600                         SNAP_WINDOW_TOP
00601                         break;
00602                       case PositionTopRight:
00603                         SNAP_WINDOW_TOP
00604                         SNAP_WINDOW_RIGHT
00605                         break;
00606                       case PositionBottomLeft:
00607                         SNAP_WINDOW_BOTTOM
00608                         SNAP_WINDOW_LEFT
00609                         break;
00610                       default:
00611                         assert( false );
00612                         break;
00613                       }
00614                     }
00615                 }
00616             }
00617        moveResizeGeom = TQRect(TQPoint(newcx, newcy), TQPoint(newrx, newry));
00618        }
00619     return moveResizeGeom;
00620     }
00621 
00625 void Workspace::setClientIsMoving( Client *c )
00626     {
00627     Q_ASSERT(!c || !movingClient); // Catch attempts to move a second
00628     // window while still moving the first one.
00629     movingClient = c;
00630     if (movingClient)
00631         ++block_focus;
00632     else
00633         --block_focus;
00634     }
00635 
00639 void Workspace::cascadeDesktop()
00640     {
00641 // TODO XINERAMA this probably is not right for xinerama
00642     Q_ASSERT( block_stacking_updates == 0 );
00643     ClientList::ConstIterator it(stackingOrder().begin());
00644     initPositioning->reinitCascading( currentDesktop());
00645     TQRect area = clientArea( PlacementArea, TQPoint( 0, 0 ), currentDesktop());
00646     for (; it != stackingOrder().end(); ++it)
00647         {
00648         if((!(*it)->isOnDesktop(currentDesktop())) ||
00649            ((*it)->isMinimized())                  ||
00650            ((*it)->isOnAllDesktops())              ||
00651            (!(*it)->isMovable()) )
00652             continue;
00653         initPositioning->placeCascaded(*it, area);
00654         }
00655     }
00656 
00661 void Workspace::unclutterDesktop()
00662     {
00663     ClientList::Iterator it(clients.fromLast());
00664     for (; it != clients.end(); --it)
00665         {
00666         if((!(*it)->isOnDesktop(currentDesktop())) ||
00667            ((*it)->isMinimized())                  ||
00668            ((*it)->isOnAllDesktops())              ||
00669            (!(*it)->isMovable()) )
00670             continue;
00671         initPositioning->placeSmart(*it, TQRect());
00672         }
00673     }
00674 
00675 
00676 void Workspace::updateTopMenuGeometry( Client* c )
00677     {
00678     if( !managingTopMenus())
00679         return;
00680     if( c != NULL )
00681         {
00682         XEvent ev;
00683         ev.xclient.display = qt_xdisplay();
00684         ev.xclient.type = ClientMessage;
00685         ev.xclient.window = c->window();
00686         static Atom msg_type_atom = XInternAtom( qt_xdisplay(), "_KDE_TOPMENU_MINSIZE", False );
00687         ev.xclient.message_type = msg_type_atom;
00688         ev.xclient.format = 32;
00689         ev.xclient.data.l[0] = GET_QT_X_TIME();
00690         ev.xclient.data.l[1] = topmenu_space->width();
00691         ev.xclient.data.l[2] = topmenu_space->height();
00692         ev.xclient.data.l[3] = 0;
00693         ev.xclient.data.l[4] = 0;
00694         XSendEvent( qt_xdisplay(), c->window(), False, NoEventMask, &ev );
00695         KWin::setStrut( c->window(), 0, 0, topmenu_height, 0 ); // so that kicker etc. know
00696         c->checkWorkspacePosition();
00697         return;
00698         }
00699     // c == NULL - update all, including topmenu_space
00700     TQRect area;
00701     area = clientArea( MaximizeFullArea, TQPoint( 0, 0 ), 1 ); // HACK desktop ?
00702     area.setHeight( topMenuHeight());
00703     topmenu_space->setGeometry( area );
00704     for( ClientList::ConstIterator it = topmenus.begin();
00705          it != topmenus.end();
00706          ++it )
00707         updateTopMenuGeometry( *it );
00708     }
00709 
00710 //********************************************
00711 // Client
00712 //********************************************
00713 
00714 
00715 void Client::keepInArea( TQRect area, bool partial )
00716     {
00717     if( partial )
00718         {
00719         // increase the area so that can have only 100 pixels in the area
00720         area.setLeft( QMIN( area.left() - width() + 100, area.left()));
00721         area.setTop( QMIN( area.top() - height() + 100, area.top()));
00722         area.setRight( QMAX( area.right() + width() - 100, area.right()));
00723         area.setBottom( QMAX( area.bottom() + height() - 100, area.bottom()));
00724         }
00725     if ( geometry().right() > area.right() && width() < area.width() )
00726         move( area.right() - width(), y() );
00727     if ( geometry().bottom() > area.bottom() && height() < area.height() )
00728         move( x(), area.bottom() - height() );
00729     if( !area.contains( geometry().topLeft() ))
00730         {
00731         int tx = x();
00732         int ty = y();
00733         if ( tx < area.x() )
00734             tx = area.x();
00735         if ( ty < area.y() )
00736             ty = area.y();
00737         move( tx, ty );
00738         }
00739     }
00740 
00746 // TODO move to Workspace?
00747 
00748 TQRect Client::adjustedClientArea( const TQRect &desktopArea, const TQRect& area ) const
00749     {
00750     TQRect r = area;
00751     // topmenu area is reserved in updateClientArea()
00752     if( isTopMenu())
00753         return r;
00754     NETExtendedStrut str = strut();
00755     TQRect stareaL = TQRect(
00756             0,
00757             str . left_start,
00758             str . left_width,
00759             str . left_end - str . left_start + 1 );
00760     TQRect stareaR = TQRect (
00761             desktopArea . right () - str . right_width + 1,
00762             str . right_start,
00763             str . right_width,
00764             str . right_end - str . right_start + 1 );
00765     TQRect stareaT = TQRect (
00766             str . top_start,
00767             0,
00768             str . top_end - str . top_start + 1,
00769             str . top_width);
00770     TQRect stareaB = TQRect (
00771             str . bottom_start,
00772             desktopArea . bottom () - str . bottom_width + 1,
00773             str . bottom_end - str . bottom_start + 1,
00774             str . bottom_width);
00775 
00776     NETExtendedStrut ext = info->extendedStrut();
00777     if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
00778         && ( str.left_width != 0 || str.right_width != 0 || str.top_width != 0 || str.bottom_width != 0 )) {
00779 
00780         // hack, might cause problems... this tries to guess the start/end of a
00781         // non-extended strut; only works on windows that have exact same
00782         // geometry as their strut (ie, if the geometry fits the width
00783         // exactly, we will adjust length of strut to match the geometry as well;
00784         // otherwise we use the full-edge strut)
00785 
00786         if (stareaT.top() == geometry().top() && stareaT.bottom() == geometry().bottom()) {
00787             stareaT.setLeft(geometry().left());
00788             stareaT.setRight(geometry().right());
00789 //            kdDebug () << "Trimming top-strut to geometry() to: " << stareaT << endl;
00790         }
00791         if (stareaB.top() == geometry().top() && stareaB.bottom() == geometry().bottom()) {
00792             stareaB.setLeft(geometry().left());
00793             stareaB.setRight(geometry().right());
00794 //            kdDebug () << "Trimming bottom-strut to geometry(): " << stareaB << endl;
00795         }
00796         if (stareaL.left() == geometry().left() && stareaL.right() == geometry().right()) {
00797             stareaL.setTop(geometry().top());
00798             stareaL.setBottom(geometry().bottom());
00799 //            kdDebug () << "Trimming left-strut to geometry(): " << stareaL << endl;
00800         }
00801         if (stareaR.left() == geometry().left() && stareaR.right() == geometry().right()) {
00802             stareaR.setTop(geometry().top());
00803             stareaR.setBottom(geometry().bottom());
00804 //            kdDebug () << "Trimming right-strut to geometry(): " << stareaR << endl;
00805         }
00806     }
00807 
00808     TQRect screenarea = workspace()->clientArea( ScreenArea, this );
00809     // HACK: workarea handling is not xinerama aware, so if this strut
00810     // reserves place at a xinerama edge that's inside the virtual screen,
00811     // ignore the strut for workspace setting.
00812     if( area == kapp->desktop()->geometry())
00813         {
00814         if( stareaL.left() < screenarea.left())
00815             stareaL = TQRect();
00816         if( stareaR.right() > screenarea.right())
00817             stareaR = TQRect();
00818         if( stareaT.top() < screenarea.top())
00819             stareaT = TQRect();
00820         if( stareaB.bottom() < screenarea.bottom())
00821             stareaB = TQRect();
00822         }
00823     // Handle struts at xinerama edges that are inside the virtual screen.
00824     // They're given in virtual screen coordinates, make them affect only
00825     // their xinerama screen.
00826     stareaL.setLeft( KMAX( stareaL.left(), screenarea.left()));
00827     stareaR.setRight( KMIN( stareaR.right(), screenarea.right()));
00828     stareaT.setTop( KMAX( stareaT.top(), screenarea.top()));
00829     stareaB.setBottom( KMIN( stareaB.bottom(), screenarea.bottom()));
00830 
00831     if (stareaL . intersects (area)) {
00832 //        kdDebug () << "Moving left of: " << r << " to " << stareaL.right() + 1 << endl;
00833         r . setLeft( stareaL . right() + 1 );
00834     }
00835     if (stareaR . intersects (area)) {
00836 //        kdDebug () << "Moving right of: " << r << " to " << stareaR.left() - 1 << endl;
00837         r . setRight( stareaR . left() - 1 );
00838     }
00839     if (stareaT . intersects (area)) {
00840 //        kdDebug () << "Moving top of: " << r << " to " << stareaT.bottom() + 1 << endl;
00841         r . setTop( stareaT . bottom() + 1 );
00842     }
00843     if (stareaB . intersects (area)) {
00844 //        kdDebug () << "Moving bottom of: " << r << " to " << stareaB.top() - 1 << endl;
00845         r . setBottom( stareaB . top() - 1 );
00846     }
00847     return r;
00848     }
00849 
00850 NETExtendedStrut Client::strut() const
00851     {
00852     NETExtendedStrut ext = info->extendedStrut();
00853     NETStrut str = info->strut();
00854     if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
00855         && ( str.left != 0 || str.right != 0 || str.top != 0 || str.bottom != 0 ))
00856         {
00857         // build extended from simple
00858         if( str.left != 0 )
00859             {
00860             ext.left_width = str.left;
00861             ext.left_start = 0;
00862             ext.left_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00863             }
00864         if( str.right != 0 )
00865             {
00866             ext.right_width = str.right;
00867             ext.right_start = 0;
00868             ext.right_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00869             }
00870         if( str.top != 0 )
00871             {
00872             ext.top_width = str.top;
00873             ext.top_start = 0;
00874             ext.top_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00875             }
00876         if( str.bottom != 0 )
00877             {
00878             ext.bottom_width = str.bottom;
00879             ext.bottom_start = 0;
00880             ext.bottom_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00881             }
00882         }
00883     return ext;
00884     }
00885 
00886 bool Client::hasStrut() const
00887     {
00888     NETExtendedStrut ext = strut();
00889     if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0 )
00890         return false;
00891     return true;
00892     }
00893 
00894 
00895 // updates differences to workarea edges for all directions
00896 void Client::updateWorkareaDiffs()
00897     {
00898     TQRect area = workspace()->clientArea( WorkArea, this );
00899     TQRect geom = geometry();
00900     workarea_diff_x = computeWorkareaDiff( geom.left(), geom.right(), area.left(), area.right());
00901     workarea_diff_y = computeWorkareaDiff( geom.top(), geom.bottom(), area.top(), area.bottom());
00902     }
00903 
00904 // If the client was inside workarea in the x direction, and if it was close to the left/right
00905 // edge, return the distance from the left/right edge (negative for left, positive for right)
00906 // INT_MIN means 'not inside workarea', INT_MAX means 'not near edge'.
00907 // In order to recognize 'at the left workarea edge' from 'at the right workarea edge'
00908 // (i.e. negative vs positive zero), the distances are one larger in absolute value than they
00909 // really are (i.e. 5 pixels from the left edge is -6, not -5). A bit hacky, but I'm lazy
00910 // to rewrite it just to make it nicer. If this will ever get touched again, perhaps then.
00911 // the y direction is done the same, just the values will be rotated: top->left, bottom->right
00912 int Client::computeWorkareaDiff( int left, int right, int a_left, int a_right )
00913     {
00914     int left_diff = left - a_left;
00915     int right_diff = a_right - right;
00916     if( left_diff < 0 || right_diff < 0 )
00917         return INT_MIN;
00918     else // fully inside workarea in this direction direction
00919         {
00920         // max distance from edge where it's still considered to be close and is kept at that distance
00921         int max_diff = ( a_right - a_left ) / 10;
00922         if( left_diff < right_diff )
00923             return left_diff < max_diff ? -left_diff - 1 : INT_MAX;
00924         else if( left_diff > right_diff )
00925             return right_diff < max_diff ? right_diff + 1 : INT_MAX;
00926         return INT_MAX; // not close to workarea edge
00927         }
00928     }
00929 
00930 void Client::checkWorkspacePosition()
00931     {
00932     if( isDesktop())
00933         {
00934         TQRect area = workspace()->clientArea( FullArea, this );
00935         if( geometry() != area )
00936             setGeometry( area );
00937         return;
00938         }
00939     if( isFullScreen())
00940         {
00941         TQRect area = workspace()->clientArea( FullScreenArea, this );
00942         if( geometry() != area )
00943             setGeometry( area );
00944         return;
00945         }
00946     if( isDock())
00947         return;
00948     if( isTopMenu())
00949         {
00950         if( workspace()->managingTopMenus())
00951             {
00952             TQRect area;
00953             ClientList mainclients = mainClients();
00954             if( mainclients.count() == 1 )
00955                 area = workspace()->clientArea( MaximizeFullArea, mainclients.first());
00956             else
00957                 area = workspace()->clientArea( MaximizeFullArea, TQPoint( 0, 0 ), desktop());
00958             area.setHeight( workspace()->topMenuHeight());
00959 //            kdDebug() << "TOPMENU size adjust: " << area << ":" << this << endl;
00960             setGeometry( area );
00961             }
00962         return;
00963         }
00964 
00965     if( maximizeMode() != MaximizeRestore )
00966     // TODO update geom_restore?
00967         changeMaximize( false, false, true ); // adjust size
00968 
00969     if( !isShade()) // TODO
00970         {
00971         int old_diff_x = workarea_diff_x;
00972         int old_diff_y = workarea_diff_y;
00973         updateWorkareaDiffs();
00974 
00975         // this can be true only if this window was mapped before KWin
00976         // was started - in such case, don't adjust position to workarea,
00977         // because the window already had its position, and if a window
00978         // with a strut altering the workarea would be managed in initialization
00979         // after this one, this window would be moved
00980         if( workspace()->initializing())
00981             return;
00982 
00983         TQRect area = workspace()->clientArea( WorkArea, this );
00984         TQRect new_geom = geometry();
00985         TQRect tmp_rect_x( new_geom.left(), 0, new_geom.width(), 0 );
00986         TQRect tmp_area_x( area.left(), 0, area.width(), 0 );
00987         checkDirection( workarea_diff_x, old_diff_x, tmp_rect_x, tmp_area_x );
00988         // the x<->y swapping
00989         TQRect tmp_rect_y( new_geom.top(), 0, new_geom.height(), 0 );
00990         TQRect tmp_area_y( area.top(), 0, area.height(), 0 );
00991         checkDirection( workarea_diff_y, old_diff_y, tmp_rect_y, tmp_area_y );
00992         new_geom = TQRect( tmp_rect_x.left(), tmp_rect_y.left(), tmp_rect_x.width(), tmp_rect_y.width());
00993         TQRect final_geom( new_geom.topLeft(), adjustedSize( new_geom.size()));
00994         if( final_geom != new_geom ) // size increments, or size restrictions
00995             { // adjusted size differing matters only for right and bottom edge
00996             if( old_diff_x != INT_MAX && old_diff_x > 0 )
00997                 final_geom.moveRight( area.right() - ( old_diff_x - 1 ));
00998             if( old_diff_y != INT_MAX && old_diff_y > 0 )
00999                 final_geom.moveBottom( area.bottom() - ( old_diff_y - 1 ));
01000             }
01001         if( final_geom != geometry() )
01002             setGeometry( final_geom );
01003         //    updateWorkareaDiffs(); done already by setGeometry()
01004         }
01005     }
01006 
01007 // Try to be smart about keeping the clients visible.
01008 // If the client was fully inside the workspace before, try to keep
01009 // it still inside the workarea, possibly moving it or making it smaller if possible,
01010 // and try to keep the distance from the nearest workarea edge.
01011 // On the other hand, it it was partially moved outside of the workspace in some direction,
01012 // don't do anything with that direction if it's still at least partially visible. If it's
01013 // not visible anymore at all, make sure it's visible at least partially
01014 // again (not fully, as that could(?) be potentionally annoying) by
01015 // moving it slightly inside the workarea (those '+ 5').
01016 // Again, this is done for the x direction, y direction will be done by x<->y swapping
01017 void Client::checkDirection( int new_diff, int old_diff, TQRect& rect, const TQRect& area )
01018     {
01019     if( old_diff != INT_MIN ) // was inside workarea
01020         {
01021         if( old_diff == INT_MAX ) // was in workarea, but far from edge
01022             {
01023             if( new_diff == INT_MIN )  // is not anymore fully in workarea
01024                 {
01025                 rect.setLeft( area.left());
01026                 rect.setRight( area.right());
01027                 }
01028             return;
01029             }
01030         if( isMovable())
01031             {
01032             if( old_diff < 0 ) // was in left third, keep distance from left edge
01033                 rect.moveLeft( area.left() + ( -old_diff - 1 ));
01034             else // old_diff > 0 // was in right third, keep distance from right edge
01035                 rect.moveRight( area.right() - ( old_diff - 1 ));
01036             }
01037         else if( isResizable())
01038             {
01039             if( old_diff < 0 )
01040                 rect.setLeft( area.left() + ( -old_diff - 1 ) );
01041             else // old_diff > 0
01042                 rect.setRight( area.right() - ( old_diff - 1 ));
01043             }
01044         if( rect.width() > area.width() && isResizable())
01045             rect.setWidth( area.width());
01046         if( isMovable())
01047             {
01048             if( rect.left() < area.left())
01049                 rect.moveLeft( area.left());
01050             else if( rect.right() > area.right())
01051                 rect.moveRight( area.right());
01052             }
01053         }
01054     if( rect.right() < area.left() + 5 || rect.left() > area.right() - 5 )
01055         { // not visible (almost) at all - try to make it at least partially visible
01056         if( isMovable())
01057             {
01058             if( rect.left() < area.left() + 5 )
01059                 rect.moveRight( area.left() + 5 );
01060             if( rect.right() > area.right() - 5 )
01061                 rect.moveLeft( area.right() - 5 );
01062             }
01063         }
01064     if (!moveResizeMode && options->shadowEnabled(isActive()))
01065         {
01066         // If the user is manually resizing, let Client::leaveMoveResize()
01067         // decide when to redraw the shadow
01068         removeShadow();
01069         drawIntersectingShadows();
01070         if (options->shadowEnabled(isActive()))
01071             drawDelayedShadow();
01072         }
01073     }
01074 
01078 TQSize Client::adjustedSize( const TQSize& frame, Sizemode mode ) const
01079     {
01080     // first, get the window size for the given frame size s
01081 
01082     TQSize wsize( frame.width() - ( border_left + border_right ),
01083              frame.height() - ( border_top + border_bottom ));
01084     if( wsize.isEmpty())
01085         wsize = TQSize( 1, 1 );
01086 
01087     return sizeForClientSize( wsize, mode, false );
01088     }
01089 
01090 // this helper returns proper size even if the window is shaded
01091 // see also the comment in Client::setGeometry()
01092 TQSize Client::adjustedSize() const
01093     {
01094     return sizeForClientSize( clientSize());
01095     }
01096 
01105 TQSize Client::sizeForClientSize( const TQSize& wsize, Sizemode mode, bool noframe ) const
01106     {
01107     int w = wsize.width();
01108     int h = wsize.height();
01109     if( w < 1 || h < 1 )
01110         {
01111         kdWarning() << "sizeForClientSize() with empty size!" << endl;
01112         kdWarning() << kdBacktrace() << endl;
01113         }
01114     if (w<1) w = 1;
01115     if (h<1) h = 1;
01116 
01117     // basesize, minsize, maxsize, paspect and resizeinc have all values defined,
01118     // even if they're not set in flags - see getWmNormalHints()
01119     TQSize min_size = minSize();
01120     TQSize max_size = maxSize();
01121     if( decoration != NULL )
01122         {
01123         TQSize decominsize = decoration->minimumSize();
01124         TQSize border_size( border_left + border_right, border_top + border_bottom );
01125         if( border_size.width() > decominsize.width()) // just in case
01126             decominsize.setWidth( border_size.width());
01127         if( border_size.height() > decominsize.height())
01128             decominsize.setHeight( border_size.height());
01129         if( decominsize.width() > min_size.width())
01130                 min_size.setWidth( decominsize.width());
01131         if( decominsize.height() > min_size.height())
01132                 min_size.setHeight( decominsize.height());
01133         }
01134     w = QMIN( max_size.width(), w );
01135     h = QMIN( max_size.height(), h );
01136     w = QMAX( min_size.width(), w );
01137     h = QMAX( min_size.height(), h );
01138 
01139     int w1 = w;
01140     int h1 = h;
01141     int width_inc = xSizeHint.width_inc;
01142     int height_inc = xSizeHint.height_inc;
01143     int basew_inc = xSizeHint.min_width; // see getWmNormalHints()
01144     int baseh_inc = xSizeHint.min_height;
01145     w = int(( w - basew_inc ) / width_inc ) * width_inc + basew_inc;
01146     h = int(( h - baseh_inc ) / height_inc ) * height_inc + baseh_inc;
01147 // code for aspect ratios based on code from FVWM
01148     /*
01149      * The math looks like this:
01150      *
01151      * minAspectX    dwidth     maxAspectX
01152      * ---------- <= ------- <= ----------
01153      * minAspectY    dheight    maxAspectY
01154      *
01155      * If that is multiplied out, then the width and height are
01156      * invalid in the following situations:
01157      *
01158      * minAspectX * dheight > minAspectY * dwidth
01159      * maxAspectX * dheight < maxAspectY * dwidth
01160      *
01161      */
01162     if( xSizeHint.flags & PAspect )
01163         {
01164         double min_aspect_w = xSizeHint.min_aspect.x; // use doubles, because the values can be MAX_INT
01165         double min_aspect_h = xSizeHint.min_aspect.y; // and multiplying would go wrong otherwise
01166         double max_aspect_w = xSizeHint.max_aspect.x;
01167         double max_aspect_h = xSizeHint.max_aspect.y;
01168         // According to ICCCM 4.1.2.3 PMinSize should be a fallback for PBaseSize for size increments,
01169         // but not for aspect ratio. Since this code comes from FVWM, handles both at the same time,
01170         // and I have no idea how it works, let's hope nobody relies on that.
01171         w -= xSizeHint.base_width;
01172         h -= xSizeHint.base_height;
01173         int max_width = max_size.width() - xSizeHint.base_width;
01174         int min_width = min_size.width() - xSizeHint.base_width;
01175         int max_height = max_size.height() - xSizeHint.base_height;
01176         int min_height = min_size.height() - xSizeHint.base_height;
01177 #define ASPECT_CHECK_GROW_W \
01178         if( min_aspect_w * h > min_aspect_h * w ) \
01179             { \
01180             int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \
01181             if( w + delta <= max_width ) \
01182                 w += delta; \
01183             }
01184 #define ASPECT_CHECK_SHRINK_H_GROW_W \
01185         if( min_aspect_w * h > min_aspect_h * w ) \
01186             { \
01187             int delta = int( h - w * min_aspect_h / min_aspect_w ) / height_inc * height_inc; \
01188             if( h - delta >= min_height ) \
01189                 h -= delta; \
01190             else \
01191                 { \
01192                 int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \
01193                 if( w + delta <= max_width ) \
01194                     w += delta; \
01195                 } \
01196             }
01197 #define ASPECT_CHECK_GROW_H \
01198         if( max_aspect_w * h < max_aspect_h * w ) \
01199             { \
01200             int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \
01201             if( h + delta <= max_height ) \
01202                 h += delta; \
01203             }
01204 #define ASPECT_CHECK_SHRINK_W_GROW_H \
01205         if( max_aspect_w * h < max_aspect_h * w ) \
01206             { \
01207             int delta = int( w - max_aspect_w * h / max_aspect_h ) / width_inc * width_inc; \
01208             if( w - delta >= min_width ) \
01209                 w -= delta; \
01210             else \
01211                 { \
01212                 int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \
01213                 if( h + delta <= max_height ) \
01214                     h += delta; \
01215                 } \
01216             }
01217         switch( mode )
01218             {
01219             case SizemodeAny:
01220 #if 0 // make SizemodeAny equal to SizemodeFixedW - prefer keeping fixed width,
01221       // so that changing aspect ratio to a different value and back keeps the same size (#87298)
01222                 {
01223                 ASPECT_CHECK_SHRINK_H_GROW_W
01224                 ASPECT_CHECK_SHRINK_W_GROW_H
01225                 ASPECT_CHECK_GROW_H
01226                 ASPECT_CHECK_GROW_W
01227                 break;
01228                 }
01229 #endif
01230             case SizemodeFixedW:
01231                 {
01232                 // the checks are order so that attempts to modify height are first
01233                 ASPECT_CHECK_GROW_H
01234                 ASPECT_CHECK_SHRINK_H_GROW_W
01235                 ASPECT_CHECK_SHRINK_W_GROW_H
01236                 ASPECT_CHECK_GROW_W
01237                 break;
01238                 }
01239             case SizemodeFixedH:
01240                 {
01241                 ASPECT_CHECK_GROW_W
01242                 ASPECT_CHECK_SHRINK_W_GROW_H
01243                 ASPECT_CHECK_SHRINK_H_GROW_W
01244                 ASPECT_CHECK_GROW_H
01245                 break;
01246                 }
01247             case SizemodeMax:
01248                 {
01249                 // first checks that try to shrink
01250                 ASPECT_CHECK_SHRINK_H_GROW_W
01251                 ASPECT_CHECK_SHRINK_W_GROW_H
01252                 ASPECT_CHECK_GROW_W
01253                 ASPECT_CHECK_GROW_H
01254                 break;
01255                 }
01256             }
01257 #undef ASPECT_CHECK_SHRINK_H_GROW_W
01258 #undef ASPECT_CHECK_SHRINK_W_GROW_H
01259 #undef ASPECT_CHECK_GROW_W
01260 #undef ASPECT_CHECK_GROW_H
01261         w += xSizeHint.base_width;
01262         h += xSizeHint.base_height;
01263         }
01264     if( !rules()->checkStrictGeometry( false ))
01265         {
01266         // disobey increments and aspect when maximized
01267         if( maximizeMode() & MaximizeHorizontal )
01268             w = w1;
01269         if( maximizeMode() & MaximizeVertical )
01270             h = h1;
01271         }
01272 
01273     if( !noframe )
01274         {
01275         w += border_left + border_right;
01276         h += border_top + border_bottom;
01277         }
01278     return rules()->checkSize( TQSize( w, h ));
01279     }
01280 
01284 void Client::getWmNormalHints()
01285     {
01286     long msize;
01287     if (XGetWMNormalHints(qt_xdisplay(), window(), &xSizeHint, &msize) == 0 )
01288         xSizeHint.flags = 0;
01289     // set defined values for the fields, even if they're not in flags
01290 
01291     if( ! ( xSizeHint.flags & PMinSize ))
01292         xSizeHint.min_width = xSizeHint.min_height = 0;
01293     if( xSizeHint.flags & PBaseSize )
01294         {
01295         // PBaseSize is a fallback for PMinSize according to ICCCM 4.1.2.3
01296         // The other way around PMinSize is not a complete fallback for PBaseSize,
01297         // so that's not handled here.
01298         if( ! ( xSizeHint.flags & PMinSize ))
01299             {
01300             xSizeHint.min_width = xSizeHint.base_width;
01301             xSizeHint.min_height = xSizeHint.base_height;
01302             }
01303         }
01304     else
01305         xSizeHint.base_width = xSizeHint.base_height = 0;
01306     if( ! ( xSizeHint.flags & PMaxSize ))
01307         xSizeHint.max_width = xSizeHint.max_height = INT_MAX;
01308     else
01309         {
01310         xSizeHint.max_width = QMAX( xSizeHint.max_width, 1 );
01311         xSizeHint.max_height = QMAX( xSizeHint.max_height, 1 );
01312         }
01313     if( xSizeHint.flags & PResizeInc )
01314         {
01315         xSizeHint.width_inc = kMax( xSizeHint.width_inc, 1 );
01316         xSizeHint.height_inc = kMax( xSizeHint.height_inc, 1 );
01317         }
01318     else
01319         {
01320         xSizeHint.width_inc = 1;
01321         xSizeHint.height_inc = 1;
01322         }
01323     if( xSizeHint.flags & PAspect )
01324         { // no dividing by zero
01325         xSizeHint.min_aspect.y = kMax( xSizeHint.min_aspect.y, 1 );
01326         xSizeHint.max_aspect.y = kMax( xSizeHint.max_aspect.y, 1 );
01327         }
01328     else
01329         {
01330         xSizeHint.min_aspect.x = 1;
01331         xSizeHint.min_aspect.y = INT_MAX;
01332         xSizeHint.max_aspect.x = INT_MAX;
01333         xSizeHint.max_aspect.y = 1;
01334         }
01335     if( ! ( xSizeHint.flags & PWinGravity ))
01336         xSizeHint.win_gravity = NorthWestGravity;
01337     if( isManaged())
01338         { // update to match restrictions
01339         TQSize new_size = adjustedSize();
01340         if( new_size != size() && !isFullScreen())
01341             {
01342             TQRect orig_geometry = geometry();
01343             resizeWithChecks( new_size );
01344             if( ( !isSpecialWindow() || isToolbar()) && !isFullScreen())
01345                 {
01346                 // try to keep the window in its xinerama screen if possible,
01347                 // if that fails at least keep it visible somewhere
01348                 TQRect area = workspace()->clientArea( MovementArea, this );
01349                 if( area.contains( orig_geometry ))
01350                     keepInArea( area );
01351                 area = workspace()->clientArea( WorkArea, this );
01352                 if( area.contains( orig_geometry ))
01353                     keepInArea( area );
01354                 }
01355             }
01356         }
01357     updateAllowedActions(); // affects isResizeable()
01358     }
01359 
01360 TQSize Client::minSize() const
01361     {
01362     return rules()->checkMinSize( TQSize( xSizeHint.min_width, xSizeHint.min_height ));
01363     }
01364 
01365 TQSize Client::maxSize() const
01366     {
01367     return rules()->checkMaxSize( TQSize( xSizeHint.max_width, xSizeHint.max_height ));
01368     }
01369 
01375 void Client::sendSyntheticConfigureNotify()
01376     {
01377     XConfigureEvent c;
01378     c.type = ConfigureNotify;
01379     c.send_event = True;
01380     c.event = window();
01381     c.window = window();
01382     c.x = x() + clientPos().x();
01383     c.y = y() + clientPos().y();
01384     c.width = clientSize().width();
01385     c.height = clientSize().height();
01386     c.border_width = 0;
01387     c.above = None;
01388     c.override_redirect = 0;
01389     XSendEvent( qt_xdisplay(), c.event, TRUE, StructureNotifyMask, (XEvent*)&c );
01390     }
01391 
01392 const TQPoint Client::calculateGravitation( bool invert, int gravity ) const
01393     {
01394     int dx, dy;
01395     dx = dy = 0;
01396 
01397     if( gravity == 0 ) // default (nonsense) value for the argument
01398         gravity = xSizeHint.win_gravity;
01399 
01400 // dx, dy specify how the client window moves to make space for the frame
01401     switch (gravity)
01402         {
01403         case NorthWestGravity: // move down right
01404         default:
01405             dx = border_left;
01406             dy = border_top;
01407             break;
01408         case NorthGravity: // move right
01409             dx = 0;
01410             dy = border_top;
01411             break;
01412         case NorthEastGravity: // move down left
01413             dx = -border_right;
01414             dy = border_top;
01415             break;
01416         case WestGravity: // move right
01417             dx = border_left;
01418             dy = 0;
01419             break;
01420         case CenterGravity:
01421             break; // will be handled specially
01422         case StaticGravity: // don't move
01423             dx = 0;
01424             dy = 0;
01425             break;
01426         case EastGravity: // move left
01427             dx = -border_right;
01428             dy = 0;
01429             break;
01430         case SouthWestGravity: // move up right
01431             dx = border_left ;
01432             dy = -border_bottom;
01433             break;
01434         case SouthGravity: // move up
01435             dx = 0;
01436             dy = -border_bottom;
01437             break;
01438         case SouthEastGravity: // move up left
01439             dx = -border_right;
01440             dy = -border_bottom;
01441             break;
01442         }
01443     if( gravity != CenterGravity )
01444         { // translate from client movement to frame movement
01445         dx -= border_left;
01446         dy -= border_top;
01447         }
01448     else
01449         { // center of the frame will be at the same position client center without frame would be
01450         dx = - ( border_left + border_right ) / 2;
01451         dy = - ( border_top + border_bottom ) / 2;
01452         }
01453     if( !invert )
01454         return TQPoint( x() + dx, y() + dy );
01455     else
01456         return TQPoint( x() - dx, y() - dy );
01457     }
01458 
01459 void Client::configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool )
01460     {
01461     if( gravity == 0 ) // default (nonsense) value for the argument
01462         gravity = xSizeHint.win_gravity;
01463     if( value_mask & ( CWX | CWY ))
01464         {
01465         TQPoint new_pos = calculateGravitation( true, gravity ); // undo gravitation
01466         if ( value_mask & CWX )
01467             new_pos.setX( rx );
01468         if ( value_mask & CWY )
01469             new_pos.setY( ry );
01470 
01471         // clever(?) workaround for applications like xv that want to set
01472         // the location to the current location but miscalculate the
01473         // frame size due to kwin being a double-reparenting window
01474         // manager
01475         if ( new_pos.x() == x() + clientPos().x() && new_pos.y() == y() + clientPos().y()
01476             && gravity == NorthWestGravity && !from_tool )
01477             {
01478             new_pos.setX( x());
01479             new_pos.setY( y());
01480             }
01481 
01482         int nw = clientSize().width();
01483         int nh = clientSize().height();
01484         if ( value_mask & CWWidth )
01485             nw = rw;
01486         if ( value_mask & CWHeight )
01487             nh = rh;
01488         TQSize ns = sizeForClientSize( TQSize( nw, nh ) );
01489         new_pos = rules()->checkPosition( new_pos );
01490 
01491         // TODO what to do with maximized windows?
01492         if ( maximizeMode() != MaximizeFull
01493             || ns != size())
01494             {
01495             TQRect orig_geometry = geometry();
01496             GeometryUpdatesPostponer blocker( this );
01497             move( new_pos );
01498             plainResize( ns );
01499             setGeometry( TQRect( calculateGravitation( false, gravity ), size()));
01500             updateFullScreenHack( TQRect( new_pos, TQSize( nw, nh )));
01501             TQRect area = workspace()->clientArea( WorkArea, this );
01502             if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen()
01503                 && area.contains( orig_geometry ))
01504                 keepInArea( area );
01505 
01506             // this is part of the kicker-xinerama-hack... it should be
01507             // safe to remove when kicker gets proper ExtendedStrut support;
01508             // see Workspace::updateClientArea() and
01509             // Client::adjustedClientArea()
01510             if (hasStrut ())
01511                 workspace() -> updateClientArea ();
01512             }
01513         }
01514 
01515     if ( value_mask & (CWWidth | CWHeight )
01516         && ! ( value_mask & ( CWX | CWY )) )  // pure resize
01517         {
01518         int nw = clientSize().width();
01519         int nh = clientSize().height();
01520         if ( value_mask & CWWidth )
01521             nw = rw;
01522         if ( value_mask & CWHeight )
01523             nh = rh;
01524         TQSize ns = sizeForClientSize( TQSize( nw, nh ) );
01525 
01526         if( ns != size())  // don't restore if some app sets its own size again
01527             {
01528             TQRect orig_geometry = geometry();
01529             GeometryUpdatesPostponer blocker( this );
01530             int save_gravity = xSizeHint.win_gravity;
01531             xSizeHint.win_gravity = gravity;
01532             resizeWithChecks( ns );
01533             xSizeHint.win_gravity = save_gravity;
01534             updateFullScreenHack( TQRect( calculateGravitation( true, xSizeHint.win_gravity ), TQSize( nw, nh )));
01535             if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen())
01536                 {
01537                 // try to keep the window in its xinerama screen if possible,
01538                 // if that fails at least keep it visible somewhere
01539                 TQRect area = workspace()->clientArea( MovementArea, this );
01540                 if( area.contains( orig_geometry ))
01541                     keepInArea( area );
01542                 area = workspace()->clientArea( WorkArea, this );
01543                 if( area.contains( orig_geometry ))
01544                     keepInArea( area );
01545                 }
01546             }
01547         }
01548     // No need to send synthetic configure notify event here, either it's sent together
01549     // with geometry change, or there's no need to send it.
01550     // Handling of the real ConfigureRequest event forces sending it, as there it's necessary.
01551     }
01552 
01553 void Client::resizeWithChecks( int w, int h, ForceGeometry_t force )
01554     {
01555     if( shade_geometry_change )
01556         assert( false );
01557     else if( isShade())
01558         {
01559         if( h == border_top + border_bottom )
01560             {
01561             kdWarning() << "Shaded geometry passed for size:" << endl;
01562             kdWarning() << kdBacktrace() << endl;
01563             }
01564         }
01565     int newx = x();
01566     int newy = y();
01567     TQRect area = workspace()->clientArea( WorkArea, this );
01568     // don't allow growing larger than workarea
01569     if( w > area.width())
01570         w = area.width();
01571     if( h > area.height())
01572         h = area.height();
01573     TQSize tmp = adjustedSize( TQSize( w, h )); // checks size constraints, including min/max size
01574     w = tmp.width();
01575     h = tmp.height();
01576     switch( xSizeHint.win_gravity )
01577         {
01578         case NorthWestGravity: // top left corner doesn't move
01579         default:
01580             break;
01581         case NorthGravity: // middle of top border doesn't move
01582             newx = ( newx + width() / 2 ) - ( w / 2 );
01583             break;
01584         case NorthEastGravity: // top right corner doesn't move
01585             newx = newx + width() - w;
01586             break;
01587         case WestGravity: // middle of left border doesn't move
01588             newy = ( newy + height() / 2 ) - ( h / 2 );
01589             break;
01590         case CenterGravity: // middle point doesn't move
01591             newx = ( newx + width() / 2 ) - ( w / 2 );
01592             newy = ( newy + height() / 2 ) - ( h / 2 );
01593             break;
01594         case StaticGravity: // top left corner of _client_ window doesn't move
01595             // since decoration doesn't change, equal to NorthWestGravity
01596             break;
01597         case EastGravity: // // middle of right border doesn't move
01598             newx = newx + width() - w;
01599             newy = ( newy + height() / 2 ) - ( h / 2 );
01600             break;
01601         case SouthWestGravity: // bottom left corner doesn't move
01602             newy = newy + height() - h;
01603             break;
01604         case SouthGravity: // middle of bottom border doesn't move
01605             newx = ( newx + width() / 2 ) - ( w / 2 );
01606             newy = newy + height() - h;
01607             break;
01608         case SouthEastGravity: // bottom right corner doesn't move
01609             newx = newx + width() - w;
01610             newy = newy + height() - h;
01611             break;
01612         }
01613     // if it would be moved outside of workarea, keep it inside,
01614     // see also Client::computeWorkareaDiff()
01615     if( workarea_diff_x != INT_MIN && w <= area.width()) // was inside and can still fit
01616         {
01617         if( newx < area.left())
01618             newx = area.left();
01619         if( newx + w > area.right() + 1 )
01620             newx = area.right() + 1 - w;
01621         assert( newx >= area.left() && newx + w <= area.right() + 1 ); // width was checked above
01622         }
01623     if( workarea_diff_y != INT_MIN && h <= area.height()) // was inside and can still fit
01624         {
01625         if( newy < area.top())
01626             newy = area.top();
01627         if( newy + h > area.bottom() + 1 )
01628             newy = area.bottom() + 1 - h;
01629         assert( newy >= area.top() && newy + h <= area.bottom() + 1 ); // height was checked above
01630         }
01631     setGeometry( newx, newy, w, h, force );
01632     }
01633 
01634 // _NET_MOVERESIZE_WINDOW
01635 void Client::NETMoveResizeWindow( int flags, int x, int y, int width, int height )
01636     {
01637     int gravity = flags & 0xff;
01638     int value_mask = 0;
01639     if( flags & ( 1 << 8 ))
01640         value_mask |= CWX;
01641     if( flags & ( 1 << 9 ))
01642         value_mask |= CWY;
01643     if( flags & ( 1 << 10 ))
01644         value_mask |= CWWidth;
01645     if( flags & ( 1 << 11 ))
01646         value_mask |= CWHeight;
01647     configureRequest( value_mask, x, y, width, height, gravity, true );
01648     }
01649 
01654 bool Client::isMovable() const
01655     {
01656     if( !motif_may_move || isFullScreen())
01657         return false;
01658     if( isSpecialWindow() && !isSplash() && !isToolbar()) // allow moving of splashscreens :)
01659         return false;
01660     if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01661         return false;
01662     if( rules()->checkPosition( invalidPoint ) != invalidPoint ) // forced position
01663         return false;
01664     return true;
01665     }
01666 
01670 bool Client::isResizable() const
01671     {
01672     if( !motif_may_resize || isFullScreen())
01673         return false;
01674     if( isSpecialWindow() )
01675         return false;
01676     if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01677         return false;
01678     if( rules()->checkSize( TQSize()).isValid()) // forced size
01679         return false;
01680 
01681     TQSize min = minSize();
01682     TQSize max = maxSize();
01683     return min.width() < max.width() || min.height() < max.height();
01684     }
01685 
01686 /*
01687   Returns whether the window is maximizable or not
01688  */
01689 bool Client::isMaximizable() const
01690     {
01691     if( isModalSystemNotification())
01692         return false;
01693         { // isMovable() and isResizable() may be false for maximized windows
01694           // with moving/resizing maximized windows disabled
01695         TemporaryAssign< MaximizeMode > tmp( max_mode, MaximizeRestore );
01696         if( !isMovable() || !isResizable() || isToolbar()) // SELI isToolbar() ?
01697             return false;
01698         }
01699     if ( maximizeMode() != MaximizeRestore )
01700         return TRUE;
01701     TQSize max = maxSize();
01702 #if 0
01703     if( max.width() < 32767 || max.height() < 32767 ) // sizes are 16bit with X
01704         return false;
01705 #else
01706     // apparently there are enough apps which specify some arbitrary value
01707     // for their maximum size just for the fun of it
01708     TQSize areasize = workspace()->clientArea( MaximizeArea, this ).size();
01709     if( max.width() < areasize.width() || max.height() < areasize.height())
01710         return false;
01711 #endif
01712     return true;
01713     }
01714 
01715 
01719 void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
01720     {
01721     // this code is also duplicated in Client::plainResize()
01722     // Ok, the shading geometry stuff. Generally, code doesn't care about shaded geometry,
01723     // simply because there are too many places dealing with geometry. Those places
01724     // ignore shaded state and use normal geometry, which they usually should get
01725     // from adjustedSize(). Such geometry comes here, and if the window is shaded,
01726     // the geometry is used only for client_size, since that one is not used when
01727     // shading. Then the frame geometry is adjusted for the shaded geometry.
01728     // This gets more complicated in the case the code does only something like
01729     // setGeometry( geometry()) - geometry() will return the shaded frame geometry.
01730     // Such code is wrong and should be changed to handle the case when the window is shaded,
01731     // for example using Client::clientSize().
01732     if( shade_geometry_change )
01733         ; // nothing
01734     else if( isShade())
01735         {
01736         if( h == border_top + border_bottom )
01737             {
01738             kdDebug() << "Shaded geometry passed for size:" << endl;
01739             kdDebug() << kdBacktrace() << endl;
01740             }
01741         else
01742             {
01743             client_size = TQSize( w - border_left - border_right, h - border_top - border_bottom );
01744             h = border_top + border_bottom;
01745             }
01746         }
01747     else
01748         {
01749         client_size = TQSize( w - border_left - border_right, h - border_top - border_bottom );
01750         }
01751     if( force == NormalGeometrySet && frame_geometry == TQRect( x, y, w, h ))
01752         return;
01753     frame_geometry = TQRect( x, y, w, h );
01754     updateWorkareaDiffs();
01755     if( postpone_geometry_updates != 0 )
01756         {
01757         pending_geometry_update = true;
01758         return;
01759         }
01760     resizeDecoration( TQSize( w, h ));
01761     XMoveResizeWindow( qt_xdisplay(), frameId(), x, y, w, h );
01762 //     resizeDecoration( TQSize( w, h ));
01763     if( !isShade())
01764         {
01765         TQSize cs = clientSize();
01766         XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01767             cs.width(), cs.height());
01768         XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01769         }
01770     updateShape();
01771     // SELI TODO won't this be too expensive?
01772     updateWorkareaDiffs();
01773     sendSyntheticConfigureNotify();
01774     updateWindowRules();
01775     checkMaximizeGeometry();
01776     workspace()->checkActiveScreen( this );
01777     }
01778 
01779 void Client::plainResize( int w, int h, ForceGeometry_t force )
01780     {
01781     // this code is also duplicated in Client::setGeometry(), and it's also commented there
01782     if( shade_geometry_change )
01783         ; // nothing
01784     else if( isShade())
01785         {
01786         if( h == border_top + border_bottom )
01787             {
01788             kdDebug() << "Shaded geometry passed for size:" << endl;
01789             kdDebug() << kdBacktrace() << endl;
01790             }
01791         else
01792             {
01793             client_size = TQSize( w - border_left - border_right, h - border_top - border_bottom );
01794             h = border_top + border_bottom;
01795             }
01796         }
01797     else
01798         {
01799         client_size = TQSize( w - border_left - border_right, h - border_top - border_bottom );
01800         }
01801     if( TQSize( w, h ) != rules()->checkSize( TQSize( w, h )))
01802         {
01803         kdDebug() << "forced size fail:" << TQSize( w,h ) << ":" << rules()->checkSize( TQSize( w, h )) << endl;
01804         kdDebug() << kdBacktrace() << endl;
01805         }
01806     if( force == NormalGeometrySet && frame_geometry.size() == TQSize( w, h ))
01807         return;
01808     frame_geometry.setSize( TQSize( w, h ));
01809     updateWorkareaDiffs();
01810     if( postpone_geometry_updates != 0 )
01811         {
01812         pending_geometry_update = true;
01813         return;
01814         }
01815     resizeDecoration( TQSize( w, h ));
01816     XResizeWindow( qt_xdisplay(), frameId(), w, h );
01817 //     resizeDecoration( TQSize( w, h ));
01818     if( !isShade())
01819         {
01820         TQSize cs = clientSize();
01821         XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01822             cs.width(), cs.height());
01823         XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01824         }
01825     updateShape();
01826     updateWorkareaDiffs();
01827     sendSyntheticConfigureNotify();
01828     updateWindowRules();
01829     checkMaximizeGeometry();
01830     workspace()->checkActiveScreen( this );
01831     }
01832 
01836 void Client::move( int x, int y, ForceGeometry_t force )
01837     {
01838     if( force == NormalGeometrySet && frame_geometry.topLeft() == TQPoint( x, y ))
01839         return;
01840     frame_geometry.moveTopLeft( TQPoint( x, y ));
01841     updateWorkareaDiffs();
01842     if( postpone_geometry_updates != 0 )
01843         {
01844         pending_geometry_update = true;
01845         return;
01846         }
01847     XMoveWindow( qt_xdisplay(), frameId(), x, y );
01848     sendSyntheticConfigureNotify();
01849     updateWindowRules();
01850     checkMaximizeGeometry();
01851     workspace()->checkActiveScreen( this );
01852     }
01853 
01854 
01855 void Client::postponeGeometryUpdates( bool postpone )
01856     {
01857     if( postpone )
01858         {
01859         if( postpone_geometry_updates == 0 )
01860             pending_geometry_update = false;
01861         ++postpone_geometry_updates;
01862         }
01863     else
01864         {
01865         if( --postpone_geometry_updates == 0 )
01866             {
01867             if( pending_geometry_update )
01868                 {
01869                 if( isShade())
01870                     setGeometry( TQRect( pos(), adjustedSize()), ForceGeometrySet );
01871                 else
01872                     setGeometry( geometry(), ForceGeometrySet );
01873                 pending_geometry_update = false;
01874                 }
01875             }
01876         }
01877     }
01878 
01879 void Client::maximize( MaximizeMode m )
01880     {
01881     setMaximize( m & MaximizeVertical, m & MaximizeHorizontal );
01882     }
01883 
01887 void Client::setMaximize( bool vertically, bool horizontally )
01888     {   // changeMaximize() flips the state, so change from set->flip
01889     changeMaximize(
01890         max_mode & MaximizeVertical ? !vertically : vertically,
01891         max_mode & MaximizeHorizontal ? !horizontally : horizontally,
01892         false );
01893     }
01894 
01895 void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
01896     {
01897     if( !isMaximizable())
01898         return;
01899 
01900     MaximizeMode old_mode = max_mode;
01901     // 'adjust == true' means to update the size only, e.g. after changing workspace size
01902     if( !adjust )
01903         {
01904         if( vertical )
01905             max_mode = MaximizeMode( max_mode ^ MaximizeVertical );
01906         if( horizontal )
01907             max_mode = MaximizeMode( max_mode ^ MaximizeHorizontal );
01908         }
01909         
01910     max_mode = rules()->checkMaximize( max_mode );
01911     if( !adjust && max_mode == old_mode )
01912         return;
01913 
01914     GeometryUpdatesPostponer blocker( this );
01915 
01916     // maximing one way and unmaximizing the other way shouldn't happen
01917     Q_ASSERT( !( vertical && horizontal )
01918         || ((( max_mode & MaximizeVertical ) != 0 ) == (( max_mode & MaximizeHorizontal ) != 0 )));
01919 
01920     TQRect clientArea = workspace()->clientArea( MaximizeArea, this );
01921 
01922     // save sizes for restoring, if maximalizing
01923     if( !adjust && !( y() == clientArea.top() && height() == clientArea.height()))
01924         {
01925         geom_restore.setTop( y());
01926         geom_restore.setHeight( height());
01927         }
01928     if( !adjust && !( x() == clientArea.left() && width() == clientArea.width()))
01929         {
01930         geom_restore.setLeft( x());
01931         geom_restore.setWidth( width());
01932         }
01933 
01934     if( !adjust )
01935         {
01936         if(( vertical && !(old_mode & MaximizeVertical ))
01937             || ( horizontal && !( old_mode & MaximizeHorizontal )))
01938             Notify::raise( Notify::Maximize );
01939         else
01940             Notify::raise( Notify::UnMaximize );
01941         }
01942 
01943     if( decoration != NULL ) // decorations may turn off some borders when maximized
01944         decoration->borders( border_left, border_right, border_top, border_bottom );
01945 
01946     // restore partial maximizations
01947     if ( old_mode==MaximizeFull && max_mode==MaximizeRestore )
01948         {
01949         if ( maximizeModeRestore()==MaximizeVertical )
01950         {
01951         max_mode = MaximizeVertical;
01952         maxmode_restore = MaximizeRestore;
01953         }
01954     if ( maximizeModeRestore()==MaximizeHorizontal )
01955         {
01956         max_mode = MaximizeHorizontal;
01957         maxmode_restore = MaximizeRestore;
01958         }   
01959     }
01960     
01961     switch (max_mode)
01962         {
01963 
01964         case MaximizeVertical:
01965             {
01966             if( old_mode & MaximizeHorizontal ) // actually restoring from MaximizeFull
01967                 {
01968                 if( geom_restore.width() == 0 )
01969                     { // needs placement
01970                     plainResize( adjustedSize(TQSize(width(), clientArea.height()), SizemodeFixedH ));
01971                     workspace()->placeSmart( this, clientArea );
01972                     }
01973                 else
01974                     setGeometry( TQRect(TQPoint( geom_restore.x(), clientArea.top()),
01975                               adjustedSize(TQSize( geom_restore.width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet);
01976                 }
01977             else
01978                 setGeometry( TQRect(TQPoint(x(), clientArea.top()),
01979                               adjustedSize(TQSize(width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet);
01980             info->setState( NET::MaxVert, NET::Max );
01981             break;
01982             }
01983 
01984         case MaximizeHorizontal:
01985             {
01986             if( old_mode & MaximizeVertical ) // actually restoring from MaximizeFull
01987                 {
01988                 if( geom_restore.height() == 0 )
01989                     { // needs placement
01990                     plainResize( adjustedSize(TQSize(clientArea.width(), height()), SizemodeFixedW ));
01991                     workspace()->placeSmart( this, clientArea );
01992                     }
01993                 else
01994                     setGeometry( TQRect( TQPoint(clientArea.left(), geom_restore.y()),
01995                               adjustedSize(TQSize(clientArea.width(), geom_restore.height()), SizemodeFixedW )), ForceGeometrySet);
01996                 }
01997             else
01998                 setGeometry( TQRect( TQPoint(clientArea.left(), y()),
01999                               adjustedSize(TQSize(clientArea.width(), height()), SizemodeFixedW )), ForceGeometrySet);
02000             info->setState( NET::MaxHoriz, NET::Max );
02001             break;
02002             }
02003 
02004         case MaximizeRestore:
02005             {
02006             TQRect restore = geometry();
02007     // when only partially maximized, geom_restore may not have the other dimension remembered
02008             if( old_mode & MaximizeVertical )
02009                 {
02010                 restore.setTop( geom_restore.top());
02011                 restore.setBottom( geom_restore.bottom());
02012                 }
02013             if( old_mode & MaximizeHorizontal )
02014                 {
02015                 restore.setLeft( geom_restore.left());
02016                 restore.setRight( geom_restore.right());
02017                 }
02018             if( !restore.isValid())
02019                 {
02020                 TQSize s = TQSize( clientArea.width()*2/3, clientArea.height()*2/3 );
02021                 if( geom_restore.width() > 0 )
02022                     s.setWidth( geom_restore.width());
02023                 if( geom_restore.height() > 0 )
02024                     s.setHeight( geom_restore.height());
02025                 plainResize( adjustedSize( s ));
02026                 workspace()->placeSmart( this, clientArea );
02027                 restore = geometry();
02028                 if( geom_restore.width() > 0 )
02029                     restore.moveLeft( geom_restore.x());
02030                 if( geom_restore.height() > 0 )
02031                     restore.moveTop( geom_restore.y());
02032                 }
02033             setGeometry( restore, ForceGeometrySet );
02034             info->setState( 0, NET::Max );
02035             break;
02036             }
02037 
02038         case MaximizeFull:
02039             {
02040             if( !adjust )
02041                 {
02042                 if( old_mode & MaximizeVertical )
02043                     maxmode_restore = MaximizeVertical;
02044                 if( old_mode & MaximizeHorizontal )
02045                     maxmode_restore = MaximizeHorizontal;
02046                 }
02047             TQSize adjSize = adjustedSize(clientArea.size(), SizemodeMax );
02048             TQRect r = TQRect(clientArea.topLeft(), adjSize);
02049             setGeometry( r, ForceGeometrySet );
02050             info->setState( NET::Max, NET::Max );
02051             break;
02052             }
02053         default:
02054             break;
02055         }
02056 
02057     updateAllowedActions();
02058     if( decoration != NULL )
02059         decoration->maximizeChange();
02060     updateWindowRules();
02061     }
02062 
02063 void Client::resetMaximize()
02064     {
02065     if( max_mode == MaximizeRestore )
02066         return;
02067     max_mode = MaximizeRestore;
02068     Notify::raise( Notify::UnMaximize );
02069     info->setState( 0, NET::Max );
02070     updateAllowedActions();
02071     if( decoration != NULL )
02072         decoration->borders( border_left, border_right, border_top, border_bottom );
02073     if( isShade())
02074         setGeometry( TQRect( pos(), sizeForClientSize( clientSize())), ForceGeometrySet );
02075     else
02076         setGeometry( geometry(), ForceGeometrySet );
02077     if( decoration != NULL )
02078         decoration->maximizeChange();
02079     }
02080 
02081 void Client::checkMaximizeGeometry()
02082     {
02083     // when adding new bail-out conditions here, checkMaximizeGeometry() needs to be called
02084     // when after the condition is no longer true
02085     if( isShade())
02086         return;
02087     if( isMove() || isResize()) // this is because of the option to disallow moving/resizing of max-ed windows
02088         return;
02089     // Just in case.
02090     static int recursion_protection = 0;
02091     if( recursion_protection > 3 )
02092         {
02093         kdWarning( 1212 ) << "Check maximize overflow - you loose!" << endl;
02094         kdWarning( 1212 ) << kdBacktrace() << endl;
02095         return;
02096         }
02097     ++recursion_protection;
02098     TQRect max_area = workspace()->clientArea( MaximizeArea, this );
02099     if( geometry() == max_area )
02100         {
02101         if( max_mode != MaximizeFull )
02102             maximize( MaximizeFull );
02103         }
02104     else if( x() == max_area.left() && width() == max_area.width())
02105         {
02106         if( max_mode != MaximizeHorizontal )
02107             maximize( MaximizeHorizontal );
02108         }
02109     else if( y() == max_area.top() && height() == max_area.height())
02110         {
02111         if( max_mode != MaximizeVertical )
02112             maximize( MaximizeVertical );
02113         }
02114     else if( max_mode != MaximizeRestore )
02115         {
02116         resetMaximize(); // not maximize( MaximizeRestore ), that'd change geometry - this is called from setGeometry()
02117         }
02118     --recursion_protection;
02119     }
02120 
02121 bool Client::isFullScreenable( bool fullscreen_hack ) const
02122     {
02123     if( !rules()->checkFullScreen( true ))
02124         return false;
02125     if( fullscreen_hack )
02126         return isNormalWindow();
02127     if( rules()->checkStrictGeometry( false ))
02128         {
02129         // the app wouldn't fit exactly fullscreen geometry due its strict geometry requirements
02130         TQRect fsarea = workspace()->clientArea( FullScreenArea, this );
02131         if( sizeForClientSize( fsarea.size(), SizemodeAny, true ) != fsarea.size())
02132             return false;
02133         }
02134      // don't check size constrains - some apps request fullscreen despite requesting fixed size
02135     return !isSpecialWindow(); // also better disallow only weird types to go fullscreen
02136     }
02137 
02138 bool Client::userCanSetFullScreen() const
02139     {
02140     if( fullscreen_mode == FullScreenHack )
02141         return false;
02142     if( !isFullScreenable( false ))
02143         return false;
02144     // isMaximizable() returns false if fullscreen
02145     TemporaryAssign< FullScreenMode > tmp( fullscreen_mode, FullScreenNone );
02146     return isNormalWindow() && isMaximizable();
02147     }
02148 
02149 void Client::setFullScreen( bool set, bool user )
02150     {
02151     if( !isFullScreen() && !set )
02152         return;
02153     if( fullscreen_mode == FullScreenHack )
02154         return;
02155     if( user && !userCanSetFullScreen())
02156         return;
02157     set = rules()->checkFullScreen( set );
02158     setShade( ShadeNone );
02159     bool was_fs = isFullScreen();
02160     if( !was_fs )
02161         geom_fs_restore = geometry();
02162     fullscreen_mode = set ? FullScreenNormal : FullScreenNone;
02163     if( was_fs == isFullScreen())
02164         return;
02165     StackingUpdatesBlocker blocker1( workspace());
02166     GeometryUpdatesPostponer blocker2( this );
02167     workspace()->updateClientLayer( this ); // active fullscreens get different layer
02168     info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen );
02169     updateDecoration( false, false );
02170     if( isFullScreen())
02171         setGeometry( workspace()->clientArea( FullScreenArea, this ));
02172     else
02173         {
02174         if( !geom_fs_restore.isNull())
02175             setGeometry( TQRect( geom_fs_restore.topLeft(), adjustedSize( geom_fs_restore.size())));
02176         // TODO isShaded() ?
02177         else
02178             { // does this ever happen?
02179             setGeometry( workspace()->clientArea( MaximizeArea, this ));
02180             }
02181         }
02182     updateWindowRules();
02183     }
02184 
02185 int Client::checkFullScreenHack( const TQRect& geom ) const
02186     {
02187     // if it's noborder window, and has size of one screen or the whole desktop geometry, it's fullscreen hack
02188     if( noBorder() && !isUserNoBorder() && isFullScreenable( true ))
02189         {
02190         if( geom.size() == workspace()->clientArea( FullArea, geom.center(), desktop()).size())
02191             return 2; // full area fullscreen hack
02192         if( geom.size() == workspace()->clientArea( ScreenArea, geom.center(), desktop()).size())
02193             return 1; // xinerama-aware fullscreen hack
02194         }
02195     return 0;
02196     }
02197 
02198 void Client::updateFullScreenHack( const TQRect& geom )
02199     {
02200     int type = checkFullScreenHack( geom );
02201     if( fullscreen_mode == FullScreenNone && type != 0 )
02202         {
02203         fullscreen_mode = FullScreenHack;
02204         updateDecoration( false, false );
02205         TQRect geom;
02206         if( rules()->checkStrictGeometry( false ))
02207             {
02208             geom = type == 2 // 1 - it's xinerama-aware fullscreen hack, 2 - it's full area
02209                 ? workspace()->clientArea( FullArea, geom.center(), desktop())
02210                 : workspace()->clientArea( ScreenArea, geom.center(), desktop());
02211             }
02212         else
02213             geom = workspace()->clientArea( FullScreenArea, geom.center(), desktop());
02214         setGeometry( geom );
02215         }
02216     else if( fullscreen_mode == FullScreenHack && type == 0 )
02217         {
02218         fullscreen_mode = FullScreenNone;
02219         updateDecoration( false, false );
02220         // whoever called this must setup correct geometry
02221         }
02222     StackingUpdatesBlocker blocker( workspace());
02223     workspace()->updateClientLayer( this ); // active fullscreens get different layer
02224     }
02225 
02226 static TQRect*       visible_bound  = 0;
02227 static GeometryTip* geometryTip    = 0;
02228 
02229 void Client::drawbound( const TQRect& geom )
02230     {
02231     assert( visible_bound == NULL );
02232     visible_bound = new TQRect( geom );
02233     doDrawbound( *visible_bound, false );
02234     }
02235 
02236 void Client::clearbound()
02237     {
02238     if( visible_bound == NULL )
02239         return;
02240     doDrawbound( *visible_bound, true );
02241     delete visible_bound;
02242     visible_bound = 0;
02243     }
02244 
02245 void Client::doDrawbound( const TQRect& geom, bool clear )
02246     {
02247     if( decoration != NULL && decoration->drawbound( geom, clear ))
02248         return; // done by decoration
02249     TQPainter p ( workspace()->desktopWidget() );
02250     p.setPen( TQPen( Qt::white, 5 ) );
02251     p.setRasterOp( TQt::XorROP );
02252     // the line is 5 pixel thick, so compensate for the extra two pixels
02253     // on outside (#88657)
02254     TQRect g = geom;
02255     if( g.width() > 5 )
02256         {
02257         g.setLeft( g.left() + 2 );
02258         g.setRight( g.right() - 2 );
02259         }
02260     if( g.height() > 5 )
02261         {
02262         g.setTop( g.top() + 2 );
02263         g.setBottom( g.bottom() - 2 );
02264         }
02265     p.drawRect( g );
02266     }
02267 
02268 void Client::positionGeometryTip()
02269     {
02270     assert( isMove() || isResize());
02271     // Position and Size display
02272     if (options->showGeometryTip())
02273         {
02274         if( !geometryTip )
02275             { // save under is not necessary with opaque, and seem to make things slower
02276             bool save_under = ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02277                         || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque );
02278             geometryTip = new GeometryTip( &xSizeHint, save_under );
02279             }
02280         TQRect wgeom( moveResizeGeom ); // position of the frame, size of the window itself
02281         wgeom.setWidth( wgeom.width() - ( width() - clientSize().width()));
02282         wgeom.setHeight( wgeom.height() - ( height() - clientSize().height()));
02283         if( isShade())
02284             wgeom.setHeight( 0 );
02285         geometryTip->setGeometry( wgeom );
02286         if( !geometryTip->isVisible())
02287             {
02288             geometryTip->show();
02289             geometryTip->raise();
02290             }
02291         }
02292     }
02293 
02294 class EatAllPaintEvents
02295     : public QObject
02296     {
02297     protected:
02298         virtual bool eventFilter( TQObject* o, TQEvent* e )
02299             { return e->type() == TQEvent::Paint && TQT_BASE_OBJECT(o) != TQT_BASE_OBJECT(geometryTip); }
02300     };
02301 
02302 static EatAllPaintEvents* eater = 0;
02303 
02304 bool Client::startMoveResize()
02305     {
02306     assert( !moveResizeMode );
02307     assert( TQWidget::keyboardGrabber() == NULL );
02308     assert( TQWidget::mouseGrabber() == NULL );
02309     if( TQApplication::activePopupWidget() != NULL )
02310         return false; // popups have grab
02311     bool has_grab = false;
02312     // This reportedly improves smoothness of the moveresize operation,
02313     // something with Enter/LeaveNotify events, looks like XFree performance problem or something *shrug*
02314     // (http://lists.kde.org/?t=107302193400001&r=1&w=2)
02315     XSetWindowAttributes attrs;
02316     TQRect r = workspace()->clientArea( FullArea, this );
02317     move_resize_grab_window = XCreateWindow( qt_xdisplay(), workspace()->rootWin(), r.x(), r.y(),
02318         r.width(), r.height(), 0, CopyFromParent, InputOnly, CopyFromParent, 0, &attrs );
02319     XMapRaised( qt_xdisplay(), move_resize_grab_window );
02320     if( XGrabPointer( qt_xdisplay(), move_resize_grab_window, False,
02321         ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask,
02322         GrabModeAsync, GrabModeAsync, move_resize_grab_window, cursor.handle(), GET_QT_X_TIME() ) == Success )
02323         has_grab = true;
02324     if( XGrabKeyboard( qt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, GET_QT_X_TIME() ) == Success )
02325         has_grab = true;
02326     if( !has_grab ) // at least one grab is necessary in order to be able to finish move/resize
02327         {
02328         XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02329         move_resize_grab_window = None;
02330         return false;
02331         }
02332     if ( maximizeMode() != MaximizeRestore )
02333         resetMaximize();
02334     removeShadow();
02335     moveResizeMode = true;
02336     workspace()->setClientIsMoving(this);
02337     initialMoveResizeGeom = moveResizeGeom = geometry();
02338     checkUnrestrictedMoveResize();
02339     // rule out non opaque windows from useless translucency settings, maybe resizes?
02340     if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02341         setShadowSize(0);
02342     if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){
02343         savedOpacity_ = opacity_;
02344         setOpacity(options->translucentMovingWindows, options->movingWindowOpacity);
02345     }
02346     if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02347       || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02348         {
02349         grabXServer();
02350         kapp->sendPostedEvents();
02351         // we have server grab -> nothing should cause paint events
02352         // unfortunately, that's not completely true, Qt may generate
02353         // paint events on some widgets due to FocusIn(?)
02354         // eat them, otherwise XOR painting will be broken (#58054)
02355         // paint events for the geometrytip need to be allowed, though
02356         eater = new EatAllPaintEvents;
02357 // not needed anymore?        kapp->installEventFilter( eater );
02358         }
02359     Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
02360     return true;
02361     }
02362 
02363 void Client::finishMoveResize( bool cancel )
02364     {
02365     leaveMoveResize();
02366     if( cancel )
02367         setGeometry( initialMoveResizeGeom );
02368     else
02369         setGeometry( moveResizeGeom );
02370     checkMaximizeGeometry();
02371 // FRAME    update();
02372     Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
02373     }
02374 
02375 void Client::leaveMoveResize()
02376     {
02377     // rule out non opaque windows from useless translucency settings, maybe resizes?
02378     if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque)
02379         setOpacity(true, savedOpacity_);
02380     if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove))
02381         updateShadowSize();
02382     clearbound();
02383     if (geometryTip)
02384         {
02385         geometryTip->hide();
02386         delete geometryTip;
02387         geometryTip = NULL;
02388         }
02389     if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque )
02390       || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) )
02391         ungrabXServer();
02392     XUngrabKeyboard( qt_xdisplay(), GET_QT_X_TIME() );
02393     XUngrabPointer( qt_xdisplay(), GET_QT_X_TIME() );
02394     XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
02395     move_resize_grab_window = None;
02396     workspace()->setClientIsMoving(0);
02397     if( move_faked_activity )
02398         workspace()->unfakeActivity( this );
02399     move_faked_activity = false;
02400     moveResizeMode = false;
02401     delete eater;
02402     eater = 0;
02403     if (options->shadowEnabled(isActive()))
02404         {
02405         drawIntersectingShadows();
02406         updateOpacityCache();
02407         }
02408     }
02409 
02410 // This function checks if it actually makes sense to perform a restricted move/resize.
02411 // If e.g. the titlebar is already outside of the workarea, there's no point in performing
02412 // a restricted move resize, because then e.g. resize would also move the window (#74555).
02413 // NOTE: Most of it is duplicated from handleMoveResize().
02414 void Client::checkUnrestrictedMoveResize()
02415     {
02416     if( unrestrictedMoveResize )
02417         return;
02418     TQRect desktopArea = workspace()->clientArea( WorkArea, moveResizeGeom.center(), desktop());
02419     int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02420     // restricted move/resize - keep at least part of the titlebar always visible 
02421     // how much must remain visible when moved away in that direction
02422     left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02423     right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02424     // width/height change with opaque resizing, use the initial ones
02425     titlebar_marge = initialMoveResizeGeom.height();
02426     top_marge = border_bottom;
02427     bottom_marge = border_top;
02428     if( isResize())
02429         {
02430         if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02431             unrestrictedMoveResize = true;
02432         if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02433             unrestrictedMoveResize = true;
02434         if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02435             unrestrictedMoveResize = true;
02436         if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02437             unrestrictedMoveResize = true;
02438         if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() ) // titlebar mustn't go out
02439             unrestrictedMoveResize = true;
02440         }
02441     if( isMove())
02442         {
02443         if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 ) // titlebar mustn't go out
02444             unrestrictedMoveResize = true;
02445         // no need to check top_marge, titlebar_marge already handles it
02446         if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02447             unrestrictedMoveResize = true;
02448         if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02449             unrestrictedMoveResize = true;
02450         if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02451             unrestrictedMoveResize = true;
02452         }
02453     }
02454 
02455 void Client::handleMoveResize( int x, int y, int x_root, int y_root )
02456     {
02457     if(( mode == PositionCenter && !isMovable())
02458         || ( mode != PositionCenter && ( isShade() || !isResizable())))
02459         return;
02460 
02461     if ( !moveResizeMode )
02462         {
02463         TQPoint p( TQPoint( x, y ) - moveOffset );
02464         if (p.manhattanLength() >= 6)
02465             {
02466             if( !startMoveResize())
02467                 {
02468                 buttonDown = false;
02469                 setCursor( mode );
02470                 return;
02471                 }
02472             }
02473         else
02474             return;
02475         }
02476 
02477     // ShadeHover or ShadeActive, ShadeNormal was already avoided above
02478     if ( mode != PositionCenter && shade_mode != ShadeNone )
02479         setShade( ShadeNone );
02480 
02481     TQPoint globalPos( x_root, y_root );
02482     // these two points limit the geometry rectangle, i.e. if bottomleft resizing is done,
02483     // the bottomleft corner should be at is at (topleft.x(), bottomright().y())
02484     TQPoint topleft = globalPos - moveOffset;
02485     TQPoint bottomright = globalPos + invertedMoveOffset;
02486     TQRect previousMoveResizeGeom = moveResizeGeom;
02487 
02488     // TODO move whole group when moving its leader or when the leader is not mapped?
02489 
02490     // compute bounds
02491     // NOTE: This is duped in checkUnrestrictedMoveResize().
02492     TQRect desktopArea = workspace()->clientArea( WorkArea, globalPos, desktop());
02493     int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
02494     if( unrestrictedMoveResize ) // unrestricted, just don't let it go out completely
02495         left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5;
02496     else // restricted move/resize - keep at least part of the titlebar always visible 
02497         {        
02498         // how much must remain visible when moved away in that direction
02499         left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
02500         right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
02501         // width/height change with opaque resizing, use the initial ones
02502         titlebar_marge = initialMoveResizeGeom.height();
02503         top_marge = border_bottom;
02504         bottom_marge = border_top;
02505         }
02506 
02507     bool update = false;
02508     if( isResize())
02509         {
02510         // first resize (without checking constraints), then snap, then check bounds, then check constraints
02511         TQRect orig = initialMoveResizeGeom;
02512         Sizemode sizemode = SizemodeAny;
02513         switch ( mode )
02514             {
02515             case PositionTopLeft:
02516                 moveResizeGeom =  TQRect( topleft, orig.bottomRight() ) ;
02517                 break;
02518             case PositionBottomRight:
02519                 moveResizeGeom =  TQRect( orig.topLeft(), bottomright ) ;
02520                 break;
02521             case PositionBottomLeft:
02522                 moveResizeGeom =  TQRect( TQPoint( topleft.x(), orig.y() ), TQPoint( orig.right(), bottomright.y()) ) ;
02523                 break;
02524             case PositionTopRight:
02525                 moveResizeGeom =  TQRect( TQPoint( orig.x(), topleft.y() ), TQPoint( bottomright.x(), orig.bottom()) ) ;
02526                 break;
02527             case PositionTop:
02528                 moveResizeGeom =  TQRect( TQPoint( orig.left(), topleft.y() ), orig.bottomRight() ) ;
02529                 sizemode = SizemodeFixedH; // try not to affect height
02530                 break;
02531             case PositionBottom:
02532                 moveResizeGeom =  TQRect( orig.topLeft(), TQPoint( orig.right(), bottomright.y() ) ) ;
02533                 sizemode = SizemodeFixedH;
02534                 break;
02535             case PositionLeft:
02536                 moveResizeGeom =  TQRect( TQPoint( topleft.x(), orig.top() ), orig.bottomRight() ) ;
02537                 sizemode = SizemodeFixedW;
02538                 break;
02539             case PositionRight:
02540                 moveResizeGeom =  TQRect( orig.topLeft(), TQPoint( bottomright.x(), orig.bottom() ) ) ;
02541                 sizemode = SizemodeFixedW;
02542                 break;
02543             case PositionCenter:
02544             default:
02545                 assert( false );
02546                 break;
02547             }
02548 
02549         // adjust new size to snap to other windows/borders
02550         moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode );
02551 
02552         // NOTE: This is duped in checkUnrestrictedMoveResize().
02553         if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
02554             moveResizeGeom.setBottom( desktopArea.top() + top_marge );
02555         if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02556             moveResizeGeom.setTop( desktopArea.bottom() - bottom_marge );
02557         if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02558             moveResizeGeom.setRight( desktopArea.left() + left_marge );
02559         if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02560             moveResizeGeom.setLeft(desktopArea.right() - right_marge );
02561         if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() ) // titlebar mustn't go out
02562             moveResizeGeom.setTop( desktopArea.top());
02563 
02564         TQSize size = adjustedSize( moveResizeGeom.size(), sizemode );
02565         // the new topleft and bottomright corners (after checking size constrains), if they'll be needed
02566         topleft = TQPoint( moveResizeGeom.right() - size.width() + 1, moveResizeGeom.bottom() - size.height() + 1 );
02567         bottomright = TQPoint( moveResizeGeom.left() + size.width() - 1, moveResizeGeom.top() + size.height() - 1 );
02568         orig = moveResizeGeom;
02569         switch ( mode )
02570             { // these 4 corners ones are copied from above
02571             case PositionTopLeft:
02572                 moveResizeGeom =  TQRect( topleft, orig.bottomRight() ) ;
02573                 break;
02574             case PositionBottomRight:
02575                 moveResizeGeom =  TQRect( orig.topLeft(), bottomright ) ;
02576                 break;
02577             case PositionBottomLeft:
02578                 moveResizeGeom =  TQRect( TQPoint( topleft.x(), orig.y() ), TQPoint( orig.right(), bottomright.y()) ) ;
02579                 break;
02580             case PositionTopRight:
02581                 moveResizeGeom =  TQRect( TQPoint( orig.x(), topleft.y() ), TQPoint( bottomright.x(), orig.bottom()) ) ;
02582                 break;
02583             // The side ones can't be copied exactly - if aspect ratios are specified, both dimensions may change.
02584             // Therefore grow to the right/bottom if needed.
02585             // TODO it should probably obey gravity rather than always using right/bottom ?
02586             case PositionTop:
02587                 moveResizeGeom =  TQRect( TQPoint( orig.left(), topleft.y() ), TQPoint( bottomright.x(), orig.bottom()) ) ;
02588                 break;
02589             case PositionBottom:
02590                 moveResizeGeom =  TQRect( orig.topLeft(), TQPoint( bottomright.x(), bottomright.y() ) ) ;
02591                 break;
02592             case PositionLeft:
02593                 moveResizeGeom =  TQRect( TQPoint( topleft.x(), orig.top() ), TQPoint( orig.right(), bottomright.y()));
02594                 break;
02595             case PositionRight:
02596                 moveResizeGeom =  TQRect( orig.topLeft(), TQPoint( bottomright.x(), bottomright.y() ) ) ;
02597                 break;
02598             case PositionCenter:
02599             default:
02600                 assert( false );
02601                 break;
02602             }
02603         if( moveResizeGeom.size() != previousMoveResizeGeom.size())
02604             update = true;
02605         }
02606     else if( isMove())
02607         {
02608         assert( mode == PositionCenter );
02609         // first move, then snap, then check bounds
02610         moveResizeGeom.moveTopLeft( topleft );
02611         moveResizeGeom.moveTopLeft( workspace()->adjustClientPosition( this, moveResizeGeom.topLeft() ) );
02612         // NOTE: This is duped in checkUnrestrictedMoveResize().
02613         if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 ) // titlebar mustn't go out
02614             moveResizeGeom.moveBottom( desktopArea.top() + titlebar_marge - 1 );
02615         // no need to check top_marge, titlebar_marge already handles it
02616         if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
02617             moveResizeGeom.moveTop( desktopArea.bottom() - bottom_marge );
02618         if( moveResizeGeom.right() < desktopArea.left() + left_marge )
02619             moveResizeGeom.moveRight( desktopArea.left() + left_marge );
02620         if( moveResizeGeom.left() > desktopArea.right() - right_marge )
02621             moveResizeGeom.moveLeft(desktopArea.right() - right_marge );
02622         if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft())
02623             update = true;
02624         }
02625     else
02626         assert( false );
02627 
02628     if( update )
02629         {
02630         if( rules()->checkMoveResizeMode
02631             ( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque )
02632             {
02633             setGeometry( moveResizeGeom );
02634             positionGeometryTip();
02635             }
02636         else if( rules()->checkMoveResizeMode
02637             ( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent )
02638             {
02639             clearbound();  // it's necessary to move the geometry tip when there's no outline
02640             positionGeometryTip(); // shown, otherwise it would cause repaint problems in case
02641             drawbound( moveResizeGeom ); // they overlap; the paint event will come after this,
02642             }                               // so the geometry tip will be painted above the outline
02643         }
02644     if ( isMove() )
02645       workspace()->clientMoved(globalPos, GET_QT_X_TIME());
02646     }
02647 
02648 
02649 } // namespace

kwin

Skip menu "kwin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kwin

Skip menu "kwin"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for kwin by doxygen 1.7.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |