• 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 extern Time qt_x_time;
00033 
00034 namespace KWinInternal
00035 {
00036 
00037 //********************************************
00038 // Workspace
00039 //********************************************
00040 
00044 void Workspace::desktopResized()
00045     {
00046     //printf("Workspace::desktopResized()\n\r");
00047     TQRect geom = KApplication::desktop()->geometry();
00048     NETSize desktop_geometry;
00049     desktop_geometry.width = geom.width();
00050     desktop_geometry.height = geom.height();
00051     rootInfo->setDesktopGeometry( -1, desktop_geometry );
00052 
00053     updateClientArea( true );
00054     checkElectricBorders( true );
00055     }
00056 
00060 void Workspace::kDestopResized()
00061     {
00062     //printf("Workspace::kDesktopResized()\n\r");
00063     TQRect geom = KApplication::desktop()->geometry();
00064     NETSize desktop_geometry;
00065     desktop_geometry.width = geom.width();
00066     desktop_geometry.height = geom.height();
00067     rootInfo->setDesktopGeometry( -1, desktop_geometry );
00068 
00069     updateClientArea( true );
00070     checkElectricBorders( true );
00071     }
00072 
00085 void Workspace::updateClientArea( bool force )
00086     {
00087     TQDesktopWidget *desktopwidget = KApplication::desktop();
00088     int nscreens = desktopwidget -> numScreens ();
00089 //    kdDebug () << "screens: " << nscreens << endl;
00090     TQRect* new_wareas = new QRect[ numberOfDesktops() + 1 ];
00091     TQRect** new_sareas = new TQRect*[ numberOfDesktops() + 1];
00092     TQRect* screens = new TQRect [ nscreens ];
00093     TQRect desktopArea = desktopwidget -> geometry ();
00094     for( int iS = 0;
00095             iS < nscreens;
00096             iS ++ )
00097         {
00098             screens [iS] = desktopwidget -> screenGeometry (iS);
00099         }
00100     for( int i = 1;
00101             i <= numberOfDesktops();
00102             ++i )
00103         {
00104             new_wareas[ i ] = desktopArea;
00105             new_sareas[ i ] = new TQRect [ nscreens ];
00106             for( int iS = 0;
00107                     iS < nscreens;
00108                     iS ++ )
00109                 new_sareas[ i ][ iS ] = screens[ iS ];
00110         }
00111     for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00112         {
00113             if( !(*it)->hasStrut())
00114                 continue;
00115             TQRect r = (*it)->adjustedClientArea( desktopArea, desktopArea );
00116             if( (*it)->isOnAllDesktops())
00117                 for( int i = 1;
00118                         i <= numberOfDesktops();
00119                         ++i )
00120                     {
00121                         new_wareas[ i ] = new_wareas[ i ].intersect( r );
00122                         for( int iS = 0;
00123                                 iS < nscreens;
00124                                 iS ++ )
00125                             new_sareas[ i ][ iS ] =
00126                                 new_sareas[ i ][ iS ].intersect(
00127                                         (*it)->adjustedClientArea( desktopArea, screens[ iS ] )
00128                                     );
00129                     }
00130             else
00131                 {
00132                     new_wareas[ (*it)->desktop() ] = new_wareas[ (*it)->desktop() ].intersect( r );
00133                     for( int iS = 0;
00134                             iS < nscreens;
00135                             iS ++ )
00136                         {
00137 //                            kdDebug () << "adjusting new_sarea: " << screens[ iS ] << endl;
00138                             new_sareas[ (*it)->desktop() ][ iS ] =
00139                                 new_sareas[ (*it)->desktop() ][ iS ].intersect(
00140                                         (*it)->adjustedClientArea( desktopArea, screens[ iS ] )
00141                                         );
00142                         }
00143                 }
00144         }
00145 #if 0
00146     for( int i = 1;
00147             i <= numberOfDesktops();
00148             ++i )
00149         {
00150             for( int iS = 0;
00151                     iS < nscreens;
00152                     iS ++ )
00153                 kdDebug () << "new_sarea: " << new_sareas[ i ][ iS ] << endl;
00154         }
00155 #endif
00156     // TODO topmenu update for screenarea changes?
00157     if( topmenu_space != NULL )
00158         {
00159         TQRect topmenu_area = desktopArea;
00160         topmenu_area.setTop( topMenuHeight());
00161         for( int i = 1;
00162              i <= numberOfDesktops();
00163              ++i )
00164             new_wareas[ i ] = new_wareas[ i ].intersect( topmenu_area );
00165         }
00166 
00167     bool changed = force;
00168 
00169     if (! screenarea)
00170         changed = true;
00171 
00172     for( int i = 1;
00173          !changed && i <= numberOfDesktops();
00174          ++i )
00175         {
00176             if( workarea[ i ] != new_wareas[ i ] )
00177                 changed = true;
00178             for( int iS = 0;
00179                     iS < nscreens;
00180                     iS ++ )
00181                 if (new_sareas[ i ][ iS ] != screenarea [ i ][ iS ])
00182                     changed = true;
00183         }
00184 
00185     if ( changed )
00186         {
00187         delete[] workarea;
00188         workarea = new_wareas;
00189         new_wareas = NULL;
00190         delete[] screenarea;
00191         screenarea = new_sareas;
00192         new_sareas = NULL;
00193         NETRect r;
00194         for( int i = 1; i <= numberOfDesktops(); i++)
00195             {
00196             r.pos.x = workarea[ i ].x();
00197             r.pos.y = workarea[ i ].y();
00198             r.size.width = workarea[ i ].width();
00199             r.size.height = workarea[ i ].height();
00200             rootInfo->setWorkArea( i, r );
00201             }
00202 
00203         updateTopMenuGeometry();
00204         for( ClientList::ConstIterator it = clients.begin();
00205              it != clients.end();
00206              ++it)
00207             (*it)->checkWorkspacePosition();
00208         for( ClientList::ConstIterator it = desktops.begin();
00209              it != desktops.end();
00210              ++it)
00211             (*it)->checkWorkspacePosition();
00212         }
00213     delete[] screens;
00214     delete[] new_sareas;
00215     delete[] new_wareas;
00216     }
00217 
00218 void Workspace::updateClientArea()
00219     {
00220     updateClientArea( false );
00221     }
00222 
00223 
00231 TQRect Workspace::clientArea( clientAreaOption opt, int screen, int desktop ) const
00232     {
00233     if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 )
00234         desktop = currentDesktop();
00235     TQDesktopWidget *desktopwidget = kapp->desktop();
00236     TQRect sarea = screenarea // may be NULL during KWin initialization
00237         ? screenarea[ desktop ][ screen ]
00238         : desktopwidget->screenGeometry( screen );
00239     TQRect warea = workarea[ desktop ].isNull()
00240         ? kapp->desktop()->geometry()
00241         : workarea[ desktop ];
00242     switch (opt)
00243         {
00244         case MaximizeArea:
00245             if (options->xineramaMaximizeEnabled)
00246                 if (desktopwidget->numScreens() < 2)
00247                     return warea;
00248                 else
00249                     return sarea;
00250             else
00251                 return warea;
00252         case MaximizeFullArea:
00253             if (options->xineramaMaximizeEnabled)
00254                 if (desktopwidget->numScreens() < 2)
00255                     return desktopwidget->geometry();
00256                 else
00257                     return desktopwidget->screenGeometry( screen );
00258             else
00259                 return desktopwidget->geometry();
00260         case FullScreenArea:
00261             if (options->xineramaFullscreenEnabled)
00262                 if (desktopwidget->numScreens() < 2)
00263                     return desktopwidget->geometry();
00264                 else
00265                     return desktopwidget->screenGeometry( screen );
00266             else
00267                 return desktopwidget->geometry();
00268         case PlacementArea:
00269             if (options->xineramaPlacementEnabled)
00270                 if (desktopwidget->numScreens() < 2)
00271                     return warea;
00272                 else
00273                     return sarea;
00274             else
00275                 return warea;
00276         case MovementArea:
00277             if (options->xineramaMovementEnabled)
00278                 if (desktopwidget->numScreens() < 2)
00279                     return desktopwidget->geometry();
00280                 else
00281                     return desktopwidget->screenGeometry( screen );
00282             else
00283                 return desktopwidget->geometry();
00284         case WorkArea:
00285             return warea;
00286         case FullArea:
00287             return desktopwidget->geometry();
00288         case ScreenArea:
00289             if (desktopwidget->numScreens() < 2)
00290                 return desktopwidget->geometry();
00291             else
00292                 return desktopwidget->screenGeometry( screen );
00293         }
00294     assert( false );
00295     return TQRect();
00296     }
00297 
00298 TQRect Workspace::clientArea( clientAreaOption opt, const TQPoint& p, int desktop ) const
00299     {
00300     TQDesktopWidget *desktopwidget = KApplication::desktop();
00301     int screen = desktopwidget->screenNumber( p );
00302     if( screen < 0 )
00303         screen = desktopwidget->primaryScreen();
00304     return clientArea( opt, screen, desktop );
00305     }
00306 
00307 TQRect Workspace::clientArea( clientAreaOption opt, const Client* c ) const
00308     {
00309     return clientArea( opt, c->geometry().center(), c->desktop());
00310     }
00311 
00312 
00318 TQPoint Workspace::adjustClientPosition( Client* c, TQPoint pos )
00319     {
00320    //CT 16mar98, 27May98 - magics: BorderSnapZone, WindowSnapZone
00321    //CT adapted for kwin on 25Nov1999
00322    //aleXXX 02Nov2000 added second snapping mode
00323     if (options->windowSnapZone || options->borderSnapZone )
00324         {
00325         const bool sOWO=options->snapOnlyWhenOverlapping;
00326         const TQRect maxRect = clientArea(MovementArea, pos+c->rect().center(), c->desktop());
00327         const int xmin = maxRect.left();
00328         const int xmax = maxRect.right()+1;               //desk size
00329         const int ymin = maxRect.top();
00330         const int ymax = maxRect.bottom()+1;
00331 
00332         const int cx(pos.x());
00333         const int cy(pos.y());
00334         const int cw(c->width());
00335         const int ch(c->height());
00336         const int rx(cx+cw);
00337         const int ry(cy+ch);                 //these don't change
00338 
00339         int nx(cx), ny(cy);                         //buffers
00340         int deltaX(xmax);
00341         int deltaY(ymax);   //minimum distance to other clients
00342 
00343         int lx, ly, lrx, lry; //coords and size for the comparison client, l
00344 
00345       // border snap
00346         int snap = options->borderSnapZone; //snap trigger
00347         if (snap)
00348             {
00349             if ((sOWO?(cx<xmin):true) && (QABS(xmin-cx)<snap))
00350                 {
00351                 deltaX = xmin-cx;
00352                 nx = xmin;
00353                 }
00354             if ((sOWO?(rx>xmax):true) && (QABS(rx-xmax)<snap) && (QABS(xmax-rx) < deltaX))
00355                 {
00356                 deltaX = rx-xmax;
00357                 nx = xmax - cw;
00358                 }
00359 
00360             if ((sOWO?(cy<ymin):true) && (QABS(ymin-cy)<snap))
00361                 {
00362                 deltaY = ymin-cy;
00363                 ny = ymin;
00364                 }
00365             if ((sOWO?(ry>ymax):true) && (QABS(ry-ymax)<snap) && (QABS(ymax-ry) < deltaY))
00366                 {
00367                 deltaY =ry-ymax;
00368                 ny = ymax - ch;
00369                 }
00370             }
00371 
00372       // windows snap
00373         snap = options->windowSnapZone;
00374         if (snap)
00375             {
00376             TQValueList<Client *>::ConstIterator l;
00377             for (l = clients.begin();l != clients.end();++l )
00378                 {
00379                 if ((*l)->isOnDesktop(currentDesktop()) &&
00380                    !(*l)->isMinimized()
00381                     && (*l) != c )
00382                     {
00383                     lx = (*l)->x();
00384                     ly = (*l)->y();
00385                     lrx = lx + (*l)->width();
00386                     lry = ly + (*l)->height();
00387 
00388                     if ( (( cy <= lry ) && ( cy  >= ly  ))  ||
00389                          (( ry >= ly  ) && ( ry  <= lry ))  ||
00390                          (( cy <= ly  ) && ( ry >= lry  )) )
00391                         {
00392                         if ((sOWO?(cx<lrx):true) && (QABS(lrx-cx)<snap) && ( QABS(lrx -cx) < deltaX) )
00393                             {
00394                             deltaX = QABS( lrx - cx );
00395                             nx = lrx;
00396                             }
00397                         if ((sOWO?(rx>lx):true) && (QABS(rx-lx)<snap) && ( QABS( rx - lx )<deltaX) )
00398                             {
00399                             deltaX = QABS(rx - lx);
00400                             nx = lx - cw;
00401                             }
00402                         }
00403 
00404                     if ( (( cx <= lrx ) && ( cx  >= lx  ))  ||
00405                          (( rx >= lx  ) && ( rx  <= lrx ))  ||
00406                          (( cx <= lx  ) && ( rx >= lrx  )) )
00407                         {
00408                         if ((sOWO?(cy<lry):true) && (QABS(lry-cy)<snap) && (QABS( lry -cy ) < deltaY))
00409                             {
00410                             deltaY = QABS( lry - cy );
00411                             ny = lry;
00412                             }
00413                   //if ( (QABS( ry-ly ) < snap) && (QABS( ry - ly ) < deltaY ))
00414                         if ((sOWO?(ry>ly):true) && (QABS(ry-ly)<snap) && (QABS( ry - ly ) < deltaY ))
00415                             {
00416                             deltaY = QABS( ry - ly );
00417                             ny = ly - ch;
00418                             }
00419                         }
00420                     }
00421                 }
00422             }
00423         pos = TQPoint(nx, ny);
00424         }
00425     return pos;
00426     }
00427 
00428 TQRect Workspace::adjustClientSize( Client* c, TQRect moveResizeGeom, int mode )
00429     {
00430    //adapted from adjustClientPosition on 29May2004
00431    //this function is called when resizing a window and will modify
00432    //the new dimensions to snap to other windows/borders if appropriate
00433     if ( options->windowSnapZone || options->borderSnapZone  )
00434         {
00435         const bool sOWO=options->snapOnlyWhenOverlapping;
00436 
00437         const TQRect maxRect = clientArea(MovementArea, c->rect().center(), c->desktop());
00438         const int xmin = maxRect.left();
00439         const int xmax = maxRect.right();               //desk size
00440         const int ymin = maxRect.top();
00441         const int ymax = maxRect.bottom();
00442 
00443         const int cx(moveResizeGeom.left());
00444         const int cy(moveResizeGeom.top());
00445         const int rx(moveResizeGeom.right());
00446         const int ry(moveResizeGeom.bottom());
00447 
00448         int newcx(cx), newcy(cy);                         //buffers
00449         int newrx(rx), newry(ry);
00450         int deltaX(xmax);
00451         int deltaY(ymax);   //minimum distance to other clients
00452 
00453         int lx, ly, lrx, lry; //coords and size for the comparison client, l
00454 
00455       // border snap
00456         int snap = options->borderSnapZone; //snap trigger
00457         if (snap)
00458             {
00459             deltaX = int(snap);
00460             deltaY = int(snap);
00461 
00462 #define SNAP_BORDER_TOP \
00463             if ((sOWO?(newcy<ymin):true) && (QABS(ymin-newcy)<deltaY)) \
00464               { \
00465                 deltaY = QABS(ymin-newcy); \
00466                 newcy = ymin; \
00467                }
00468 
00469 #define SNAP_BORDER_BOTTOM \
00470             if ((sOWO?(newry>ymax):true) && (QABS(ymax-newry)<deltaY)) \
00471               { \
00472                 deltaY = QABS(ymax-newcy); \
00473                 newry = ymax; \
00474                }
00475 
00476 #define SNAP_BORDER_LEFT \
00477             if ((sOWO?(newcx<xmin):true) && (QABS(xmin-newcx)<deltaX)) \
00478               { \
00479                 deltaX = QABS(xmin-newcx); \
00480                 newcx = xmin; \
00481                }
00482 
00483 #define SNAP_BORDER_RIGHT \
00484             if ((sOWO?(newrx>xmax):true) && (QABS(xmax-newrx)<deltaX)) \
00485               { \
00486                 deltaX = QABS(xmax-newrx); \
00487                 newrx = xmax; \
00488                }
00489                      switch ( mode )
00490                       {
00491                       case PositionBottomRight:
00492                         SNAP_BORDER_BOTTOM
00493                         SNAP_BORDER_RIGHT
00494                         break;
00495                       case PositionRight:
00496                         SNAP_BORDER_RIGHT
00497                         break;
00498                       case PositionBottom:
00499                         SNAP_BORDER_BOTTOM
00500                         break;
00501                       case PositionTopLeft:
00502                         SNAP_BORDER_TOP
00503                         SNAP_BORDER_LEFT
00504                         break;
00505                       case PositionLeft:
00506                         SNAP_BORDER_LEFT
00507                         break;
00508                       case PositionTop:
00509                         SNAP_BORDER_TOP
00510                         break;
00511                       case PositionTopRight:
00512                         SNAP_BORDER_TOP
00513                         SNAP_BORDER_RIGHT
00514                         break;
00515                       case PositionBottomLeft:
00516                         SNAP_BORDER_BOTTOM
00517                         SNAP_BORDER_LEFT
00518                         break;
00519                       default:
00520                         assert( false );
00521                         break;
00522                       }
00523 
00524 
00525             }
00526 
00527       // windows snap
00528         snap = options->windowSnapZone;
00529         if (snap)
00530             {
00531             deltaX = int(snap);
00532             deltaY = int(snap);
00533             TQValueList<Client *>::ConstIterator l;
00534             for (l = clients.begin();l != clients.end();++l )
00535                 {
00536                 if ((*l)->isOnDesktop(currentDesktop()) &&
00537                    !(*l)->isMinimized()
00538                     && (*l) != c )
00539                     {
00540                     lx = (*l)->x()-1;
00541                     ly = (*l)->y()-1;
00542                     lrx =(*l)->x() + (*l)->width();
00543                     lry =(*l)->y() + (*l)->height();
00544 
00545 #define WITHIN_HEIGHT ((( newcy <= lry ) && ( newcy  >= ly  ))  || \
00546                          (( newry >= ly  ) && ( newry  <= lry ))  || \
00547                          (( newcy <= ly  ) && ( newry >= lry  )) )
00548 
00549 #define WITHIN_WIDTH  ( (( cx <= lrx ) && ( cx  >= lx  ))  || \
00550                          (( rx >= lx  ) && ( rx  <= lrx ))  || \
00551                          (( cx <= lx  ) && ( rx >= lrx  )) )
00552 
00553 #define SNAP_WINDOW_TOP  if ( (sOWO?(newcy<lry):true) \
00554                   && WITHIN_WIDTH  \
00555                   && (QABS( lry - newcy ) < deltaY) ) {  \
00556                   deltaY = QABS( lry - newcy ); \
00557                   newcy=lry; \
00558                   }
00559 
00560 #define SNAP_WINDOW_BOTTOM  if ( (sOWO?(newry>ly):true)  \
00561                      && WITHIN_WIDTH  \
00562                      && (QABS( ly - newry ) < deltaY) ) {  \
00563                      deltaY = QABS( ly - newry );  \
00564                      newry=ly;  \
00565                      }
00566 
00567 #define SNAP_WINDOW_LEFT  if ( (sOWO?(newcx<lrx):true)  \
00568                    && WITHIN_HEIGHT  \
00569                    && (QABS( lrx - newcx ) < deltaX)) {  \
00570                    deltaX = QABS( lrx - newcx );  \
00571                    newcx=lrx;  \
00572                    }
00573 
00574 #define SNAP_WINDOW_RIGHT  if ( (sOWO?(newrx>lx):true)  \
00575                     && WITHIN_HEIGHT  \
00576                     && (QABS( lx - newrx ) < deltaX))  \
00577                     {  \
00578                     deltaX = QABS( lx - newrx );  \
00579                     newrx=lx;  \
00580                     }
00581 
00582                     switch ( mode )
00583                       {
00584                       case PositionBottomRight:
00585                         SNAP_WINDOW_BOTTOM
00586                         SNAP_WINDOW_RIGHT
00587                         break;
00588                       case PositionRight:
00589                         SNAP_WINDOW_RIGHT
00590                         break;
00591                       case PositionBottom:
00592                         SNAP_WINDOW_BOTTOM
00593                         break;
00594                       case PositionTopLeft:
00595                         SNAP_WINDOW_TOP
00596                         SNAP_WINDOW_LEFT
00597                         break;
00598                       case PositionLeft:
00599                         SNAP_WINDOW_LEFT
00600                         break;
00601                       case PositionTop:
00602                         SNAP_WINDOW_TOP
00603                         break;
00604                       case PositionTopRight:
00605                         SNAP_WINDOW_TOP
00606                         SNAP_WINDOW_RIGHT
00607                         break;
00608                       case PositionBottomLeft:
00609                         SNAP_WINDOW_BOTTOM
00610                         SNAP_WINDOW_LEFT
00611                         break;
00612                       default:
00613                         assert( false );
00614                         break;
00615                       }
00616                     }
00617                 }
00618             }
00619        moveResizeGeom = TQRect(TQPoint(newcx, newcy), TQPoint(newrx, newry));
00620        }
00621     return moveResizeGeom;
00622     }
00623 
00627 void Workspace::setClientIsMoving( Client *c )
00628     {
00629     Q_ASSERT(!c || !movingClient); // Catch attempts to move a second
00630     // window while still moving the first one.
00631     movingClient = c;
00632     if (movingClient)
00633         ++block_focus;
00634     else
00635         --block_focus;
00636     }
00637 
00641 void Workspace::cascadeDesktop()
00642     {
00643 // TODO XINERAMA this probably is not right for xinerama
00644     Q_ASSERT( block_stacking_updates == 0 );
00645     ClientList::ConstIterator it(stackingOrder().begin());
00646     initPositioning->reinitCascading( currentDesktop());
00647     TQRect area = clientArea( PlacementArea, TQPoint( 0, 0 ), currentDesktop());
00648     for (; it != stackingOrder().end(); ++it)
00649         {
00650         if((!(*it)->isOnDesktop(currentDesktop())) ||
00651            ((*it)->isMinimized())                  ||
00652            ((*it)->isOnAllDesktops())              ||
00653            (!(*it)->isMovable()) )
00654             continue;
00655         initPositioning->placeCascaded(*it, area);
00656         }
00657     }
00658 
00663 void Workspace::unclutterDesktop()
00664     {
00665     ClientList::Iterator it(clients.fromLast());
00666     for (; it != clients.end(); --it)
00667         {
00668         if((!(*it)->isOnDesktop(currentDesktop())) ||
00669            ((*it)->isMinimized())                  ||
00670            ((*it)->isOnAllDesktops())              ||
00671            (!(*it)->isMovable()) )
00672             continue;
00673         initPositioning->placeSmart(*it, TQRect());
00674         }
00675     }
00676 
00677 
00678 void Workspace::updateTopMenuGeometry( Client* c )
00679     {
00680     if( !managingTopMenus())
00681         return;
00682     if( c != NULL )
00683         {
00684         XEvent ev;
00685         ev.xclient.display = qt_xdisplay();
00686         ev.xclient.type = ClientMessage;
00687         ev.xclient.window = c->window();
00688         static Atom msg_type_atom = XInternAtom( qt_xdisplay(), "_KDE_TOPMENU_MINSIZE", False );
00689         ev.xclient.message_type = msg_type_atom;
00690         ev.xclient.format = 32;
00691         ev.xclient.data.l[0] = qt_x_time;
00692         ev.xclient.data.l[1] = topmenu_space->width();
00693         ev.xclient.data.l[2] = topmenu_space->height();
00694         ev.xclient.data.l[3] = 0;
00695         ev.xclient.data.l[4] = 0;
00696         XSendEvent( qt_xdisplay(), c->window(), False, NoEventMask, &ev );
00697         KWin::setStrut( c->window(), 0, 0, topmenu_height, 0 ); // so that kicker etc. know
00698         c->checkWorkspacePosition();
00699         return;
00700         }
00701     // c == NULL - update all, including topmenu_space
00702     TQRect area;
00703     area = clientArea( MaximizeFullArea, TQPoint( 0, 0 ), 1 ); // HACK desktop ?
00704     area.setHeight( topMenuHeight());
00705     topmenu_space->setGeometry( area );
00706     for( ClientList::ConstIterator it = topmenus.begin();
00707          it != topmenus.end();
00708          ++it )
00709         updateTopMenuGeometry( *it );
00710     }
00711 
00712 //********************************************
00713 // Client
00714 //********************************************
00715 
00716 
00717 void Client::keepInArea( TQRect area, bool partial )
00718     {
00719     if( partial )
00720         {
00721         // increase the area so that can have only 100 pixels in the area
00722         area.setLeft( QMIN( area.left() - width() + 100, area.left()));
00723         area.setTop( QMIN( area.top() - height() + 100, area.top()));
00724         area.setRight( QMAX( area.right() + width() - 100, area.right()));
00725         area.setBottom( QMAX( area.bottom() + height() - 100, area.bottom()));
00726         }
00727     if ( geometry().right() > area.right() && width() < area.width() )
00728         move( area.right() - width(), y() );
00729     if ( geometry().bottom() > area.bottom() && height() < area.height() )
00730         move( x(), area.bottom() - height() );
00731     if( !area.contains( geometry().topLeft() ))
00732         {
00733         int tx = x();
00734         int ty = y();
00735         if ( tx < area.x() )
00736             tx = area.x();
00737         if ( ty < area.y() )
00738             ty = area.y();
00739         move( tx, ty );
00740         }
00741     }
00742 
00748 // TODO move to Workspace?
00749 
00750 TQRect Client::adjustedClientArea( const TQRect &desktopArea, const TQRect& area ) const
00751     {
00752     TQRect r = area;
00753     // topmenu area is reserved in updateClientArea()
00754     if( isTopMenu())
00755         return r;
00756     NETExtendedStrut str = strut();
00757     TQRect stareaL = TQRect(
00758             0,
00759             str . left_start,
00760             str . left_width,
00761             str . left_end - str . left_start + 1 );
00762     TQRect stareaR = TQRect (
00763             desktopArea . right () - str . right_width + 1,
00764             str . right_start,
00765             str . right_width,
00766             str . right_end - str . right_start + 1 );
00767     TQRect stareaT = TQRect (
00768             str . top_start,
00769             0,
00770             str . top_end - str . top_start + 1,
00771             str . top_width);
00772     TQRect stareaB = TQRect (
00773             str . bottom_start,
00774             desktopArea . bottom () - str . bottom_width + 1,
00775             str . bottom_end - str . bottom_start + 1,
00776             str . bottom_width);
00777 
00778     NETExtendedStrut ext = info->extendedStrut();
00779     if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
00780         && ( str.left_width != 0 || str.right_width != 0 || str.top_width != 0 || str.bottom_width != 0 )) {
00781 
00782         // hack, might cause problems... this tries to guess the start/end of a
00783         // non-extended strut; only works on windows that have exact same
00784         // geometry as their strut (ie, if the geometry fits the width
00785         // exactly, we will adjust length of strut to match the geometry as well;
00786         // otherwise we use the full-edge strut)
00787 
00788         if (stareaT.top() == geometry().top() && stareaT.bottom() == geometry().bottom()) {
00789             stareaT.setLeft(geometry().left());
00790             stareaT.setRight(geometry().right());
00791 //            kdDebug () << "Trimming top-strut to geometry() to: " << stareaT << endl;
00792         }
00793         if (stareaB.top() == geometry().top() && stareaB.bottom() == geometry().bottom()) {
00794             stareaB.setLeft(geometry().left());
00795             stareaB.setRight(geometry().right());
00796 //            kdDebug () << "Trimming bottom-strut to geometry(): " << stareaB << endl;
00797         }
00798         if (stareaL.left() == geometry().left() && stareaL.right() == geometry().right()) {
00799             stareaL.setTop(geometry().top());
00800             stareaL.setBottom(geometry().bottom());
00801 //            kdDebug () << "Trimming left-strut to geometry(): " << stareaL << endl;
00802         }
00803         if (stareaR.left() == geometry().left() && stareaR.right() == geometry().right()) {
00804             stareaR.setTop(geometry().top());
00805             stareaR.setBottom(geometry().bottom());
00806 //            kdDebug () << "Trimming right-strut to geometry(): " << stareaR << endl;
00807         }
00808     }
00809 
00810     TQRect screenarea = workspace()->clientArea( ScreenArea, this );
00811     // HACK: workarea handling is not xinerama aware, so if this strut
00812     // reserves place at a xinerama edge that's inside the virtual screen,
00813     // ignore the strut for workspace setting.
00814     if( area == kapp->desktop()->geometry())
00815         {
00816         if( stareaL.left() < screenarea.left())
00817             stareaL = TQRect();
00818         if( stareaR.right() > screenarea.right())
00819             stareaR = TQRect();
00820         if( stareaT.top() < screenarea.top())
00821             stareaT = TQRect();
00822         if( stareaB.bottom() < screenarea.bottom())
00823             stareaB = TQRect();
00824         }
00825     // Handle struts at xinerama edges that are inside the virtual screen.
00826     // They're given in virtual screen coordinates, make them affect only
00827     // their xinerama screen.
00828     stareaL.setLeft( KMAX( stareaL.left(), screenarea.left()));
00829     stareaR.setRight( KMIN( stareaR.right(), screenarea.right()));
00830     stareaT.setTop( KMAX( stareaT.top(), screenarea.top()));
00831     stareaB.setBottom( KMIN( stareaB.bottom(), screenarea.bottom()));
00832 
00833     if (stareaL . intersects (area)) {
00834 //        kdDebug () << "Moving left of: " << r << " to " << stareaL.right() + 1 << endl;
00835         r . setLeft( stareaL . right() + 1 );
00836     }
00837     if (stareaR . intersects (area)) {
00838 //        kdDebug () << "Moving right of: " << r << " to " << stareaR.left() - 1 << endl;
00839         r . setRight( stareaR . left() - 1 );
00840     }
00841     if (stareaT . intersects (area)) {
00842 //        kdDebug () << "Moving top of: " << r << " to " << stareaT.bottom() + 1 << endl;
00843         r . setTop( stareaT . bottom() + 1 );
00844     }
00845     if (stareaB . intersects (area)) {
00846 //        kdDebug () << "Moving bottom of: " << r << " to " << stareaB.top() - 1 << endl;
00847         r . setBottom( stareaB . top() - 1 );
00848     }
00849     return r;
00850     }
00851 
00852 NETExtendedStrut Client::strut() const
00853     {
00854     NETExtendedStrut ext = info->extendedStrut();
00855     NETStrut str = info->strut();
00856     if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
00857         && ( str.left != 0 || str.right != 0 || str.top != 0 || str.bottom != 0 ))
00858         {
00859         // build extended from simple
00860         if( str.left != 0 )
00861             {
00862             ext.left_width = str.left;
00863             ext.left_start = 0;
00864             ext.left_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00865             }
00866         if( str.right != 0 )
00867             {
00868             ext.right_width = str.right;
00869             ext.right_start = 0;
00870             ext.right_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00871             }
00872         if( str.top != 0 )
00873             {
00874             ext.top_width = str.top;
00875             ext.top_start = 0;
00876             ext.top_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00877             }
00878         if( str.bottom != 0 )
00879             {
00880             ext.bottom_width = str.bottom;
00881             ext.bottom_start = 0;
00882             ext.bottom_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00883             }
00884         }
00885     return ext;
00886     }
00887 
00888 bool Client::hasStrut() const
00889     {
00890     NETExtendedStrut ext = strut();
00891     if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0 )
00892         return false;
00893     return true;
00894     }
00895 
00896 
00897 // updates differences to workarea edges for all directions
00898 void Client::updateWorkareaDiffs()
00899     {
00900     TQRect area = workspace()->clientArea( WorkArea, this );
00901     TQRect geom = geometry();
00902     workarea_diff_x = computeWorkareaDiff( geom.left(), geom.right(), area.left(), area.right());
00903     workarea_diff_y = computeWorkareaDiff( geom.top(), geom.bottom(), area.top(), area.bottom());
00904     }
00905 
00906 // If the client was inside workarea in the x direction, and if it was close to the left/right
00907 // edge, return the distance from the left/right edge (negative for left, positive for right)
00908 // INT_MIN means 'not inside workarea', INT_MAX means 'not near edge'.
00909 // In order to recognize 'at the left workarea edge' from 'at the right workarea edge'
00910 // (i.e. negative vs positive zero), the distances are one larger in absolute value than they
00911 // really are (i.e. 5 pixels from the left edge is -6, not -5). A bit hacky, but I'm lazy
00912 // to rewrite it just to make it nicer. If this will ever get touched again, perhaps then.
00913 // the y direction is done the same, just the values will be rotated: top->left, bottom->right
00914 int Client::computeWorkareaDiff( int left, int right, int a_left, int a_right )
00915     {
00916     int left_diff = left - a_left;
00917     int right_diff = a_right - right;
00918     if( left_diff < 0 || right_diff < 0 )
00919         return INT_MIN;
00920     else // fully inside workarea in this direction direction
00921         {
00922         // max distance from edge where it's still considered to be close and is kept at that distance
00923         int max_diff = ( a_right - a_left ) / 10;
00924         if( left_diff < right_diff )
00925             return left_diff < max_diff ? -left_diff - 1 : INT_MAX;
00926         else if( left_diff > right_diff )
00927             return right_diff < max_diff ? right_diff + 1 : INT_MAX;
00928         return INT_MAX; // not close to workarea edge
00929         }
00930     }
00931 
00932 void Client::checkWorkspacePosition()
00933     {
00934     if( isDesktop())
00935         {
00936         TQRect area = workspace()->clientArea( FullArea, this );
00937         if( geometry() != area )
00938             setGeometry( area );
00939         return;
00940         }
00941     if( isFullScreen())
00942         {
00943         TQRect area = workspace()->clientArea( FullScreenArea, this );
00944         if( geometry() != area )
00945             setGeometry( area );
00946         return;
00947         }
00948     if( isDock())
00949         return;
00950     if( isTopMenu())
00951         {
00952         if( workspace()->managingTopMenus())
00953             {
00954             TQRect area;
00955             ClientList mainclients = mainClients();
00956             if( mainclients.count() == 1 )
00957                 area = workspace()->clientArea( MaximizeFullArea, mainclients.first());
00958             else
00959                 area = workspace()->clientArea( MaximizeFullArea, TQPoint( 0, 0 ), desktop());
00960             area.setHeight( workspace()->topMenuHeight());
00961 //            kdDebug() << "TOPMENU size adjust: " << area << ":" << this << endl;
00962             setGeometry( area );
00963             }
00964         return;
00965         }
00966 
00967     if( maximizeMode() != MaximizeRestore )
00968     // TODO update geom_restore?
00969         changeMaximize( false, false, true ); // adjust size
00970 
00971     if( !isShade()) // TODO
00972         {
00973         int old_diff_x = workarea_diff_x;
00974         int old_diff_y = workarea_diff_y;
00975         updateWorkareaDiffs();
00976 
00977         // this can be true only if this window was mapped before KWin
00978         // was started - in such case, don't adjust position to workarea,
00979         // because the window already had its position, and if a window
00980         // with a strut altering the workarea would be managed in initialization
00981         // after this one, this window would be moved
00982         if( workspace()->initializing())
00983             return;
00984 
00985         TQRect area = workspace()->clientArea( WorkArea, this );
00986         TQRect new_geom = geometry();
00987         TQRect tmp_rect_x( new_geom.left(), 0, new_geom.width(), 0 );
00988         TQRect tmp_area_x( area.left(), 0, area.width(), 0 );
00989         checkDirection( workarea_diff_x, old_diff_x, tmp_rect_x, tmp_area_x );
00990         // the x<->y swapping
00991         TQRect tmp_rect_y( new_geom.top(), 0, new_geom.height(), 0 );
00992         TQRect tmp_area_y( area.top(), 0, area.height(), 0 );
00993         checkDirection( workarea_diff_y, old_diff_y, tmp_rect_y, tmp_area_y );
00994         new_geom = TQRect( tmp_rect_x.left(), tmp_rect_y.left(), tmp_rect_x.width(), tmp_rect_y.width());
00995         TQRect final_geom( new_geom.topLeft(), adjustedSize( new_geom.size()));
00996         if( final_geom != new_geom ) // size increments, or size restrictions
00997             { // adjusted size differing matters only for right and bottom edge
00998             if( old_diff_x != INT_MAX && old_diff_x > 0 )
00999                 final_geom.moveRight( area.right() - ( old_diff_x - 1 ));
01000             if( old_diff_y != INT_MAX && old_diff_y > 0 )
01001                 final_geom.moveBottom( area.bottom() - ( old_diff_y - 1 ));
01002             }
01003         if( final_geom != geometry() )
01004             setGeometry( final_geom );
01005         //    updateWorkareaDiffs(); done already by setGeometry()
01006         }
01007     }
01008 
01009 // Try to be smart about keeping the clients visible.
01010 // If the client was fully inside the workspace before, try to keep
01011 // it still inside the workarea, possibly moving it or making it smaller if possible,
01012 // and try to keep the distance from the nearest workarea edge.
01013 // On the other hand, it it was partially moved outside of the workspace in some direction,
01014 // don't do anything with that direction if it's still at least partially visible. If it's
01015 // not visible anymore at all, make sure it's visible at least partially
01016 // again (not fully, as that could(?) be potentionally annoying) by
01017 // moving it slightly inside the workarea (those '+ 5').
01018 // Again, this is done for the x direction, y direction will be done by x<->y swapping
01019 void Client::checkDirection( int new_diff, int old_diff, TQRect& rect, const TQRect& area )
01020     {
01021     if( old_diff != INT_MIN ) // was inside workarea
01022         {
01023         if( old_diff == INT_MAX ) // was in workarea, but far from edge
01024             {
01025             if( new_diff == INT_MIN )  // is not anymore fully in workarea
01026                 {
01027                 rect.setLeft( area.left());
01028                 rect.setRight( area.right());
01029                 }
01030             return;
01031             }
01032         if( isMovable())
01033             {
01034             if( old_diff < 0 ) // was in left third, keep distance from left edge
01035                 rect.moveLeft( area.left() + ( -old_diff - 1 ));
01036             else // old_diff > 0 // was in right third, keep distance from right edge
01037                 rect.moveRight( area.right() - ( old_diff - 1 ));
01038             }
01039         else if( isResizable())
01040             {
01041             if( old_diff < 0 )
01042                 rect.setLeft( area.left() + ( -old_diff - 1 ) );
01043             else // old_diff > 0
01044                 rect.setRight( area.right() - ( old_diff - 1 ));
01045             }
01046         if( rect.width() > area.width() && isResizable())
01047             rect.setWidth( area.width());
01048         if( isMovable())
01049             {
01050             if( rect.left() < area.left())
01051                 rect.moveLeft( area.left());
01052             else if( rect.right() > area.right())
01053                 rect.moveRight( area.right());
01054             }
01055         }
01056     if( rect.right() < area.left() + 5 || rect.left() > area.right() - 5 )
01057         { // not visible (almost) at all - try to make it at least partially visible
01058         if( isMovable())
01059             {
01060             if( rect.left() < area.left() + 5 )
01061                 rect.moveRight( area.left() + 5 );
01062             if( rect.right() > area.right() - 5 )
01063                 rect.moveLeft( area.right() - 5 );
01064             }
01065         }
01066     if (!moveResizeMode && options->shadowEnabled(isActive()))
01067         {
01068         // If the user is manually resizing, let Client::leaveMoveResize()
01069         // decide when to redraw the shadow
01070         removeShadow();
01071         drawIntersectingShadows();
01072         if (options->shadowEnabled(isActive()))
01073             drawDelayedShadow();
01074         }
01075     }
01076 
01080 TQSize Client::adjustedSize( const TQSize& frame, Sizemode mode ) const
01081     {
01082     // first, get the window size for the given frame size s
01083 
01084     TQSize wsize( frame.width() - ( border_left + border_right ),
01085              frame.height() - ( border_top + border_bottom ));
01086     if( wsize.isEmpty())
01087         wsize = TQSize( 1, 1 );
01088 
01089     return sizeForClientSize( wsize, mode, false );
01090     }
01091 
01092 // this helper returns proper size even if the window is shaded
01093 // see also the comment in Client::setGeometry()
01094 TQSize Client::adjustedSize() const
01095     {
01096     return sizeForClientSize( clientSize());
01097     }
01098 
01107 TQSize Client::sizeForClientSize( const TQSize& wsize, Sizemode mode, bool noframe ) const
01108     {
01109     int w = wsize.width();
01110     int h = wsize.height();
01111     if( w < 1 || h < 1 )
01112         {
01113         kdWarning() << "sizeForClientSize() with empty size!" << endl;
01114         kdWarning() << kdBacktrace() << endl;
01115         }
01116     if (w<1) w = 1;
01117     if (h<1) h = 1;
01118 
01119     // basesize, minsize, maxsize, paspect and resizeinc have all values defined,
01120     // even if they're not set in flags - see getWmNormalHints()
01121     TQSize min_size = minSize();
01122     TQSize max_size = maxSize();
01123     if( decoration != NULL )
01124         {
01125         TQSize decominsize = decoration->minimumSize();
01126         TQSize border_size( border_left + border_right, border_top + border_bottom );
01127         if( border_size.width() > decominsize.width()) // just in case
01128             decominsize.setWidth( border_size.width());
01129         if( border_size.height() > decominsize.height())
01130             decominsize.setHeight( border_size.height());
01131         if( decominsize.width() > min_size.width())
01132                 min_size.setWidth( decominsize.width());
01133         if( decominsize.height() > min_size.height())
01134                 min_size.setHeight( decominsize.height());
01135         }
01136     w = QMIN( max_size.width(), w );
01137     h = QMIN( max_size.height(), h );
01138     w = QMAX( min_size.width(), w );
01139     h = QMAX( min_size.height(), h );
01140 
01141     int w1 = w;
01142     int h1 = h;
01143     int width_inc = xSizeHint.width_inc;
01144     int height_inc = xSizeHint.height_inc;
01145     int basew_inc = xSizeHint.min_width; // see getWmNormalHints()
01146     int baseh_inc = xSizeHint.min_height;
01147     w = int(( w - basew_inc ) / width_inc ) * width_inc + basew_inc;
01148     h = int(( h - baseh_inc ) / height_inc ) * height_inc + baseh_inc;
01149 // code for aspect ratios based on code from FVWM
01150     /*
01151      * The math looks like this:
01152      *
01153      * minAspectX    dwidth     maxAspectX
01154      * ---------- <= ------- <= ----------
01155      * minAspectY    dheight    maxAspectY
01156      *
01157      * If that is multiplied out, then the width and height are
01158      * invalid in the following situations:
01159      *
01160      * minAspectX * dheight > minAspectY * dwidth
01161      * maxAspectX * dheight < maxAspectY * dwidth
01162      *
01163      */
01164     if( xSizeHint.flags & PAspect )
01165         {
01166         double min_aspect_w = xSizeHint.min_aspect.x; // use doubles, because the values can be MAX_INT
01167         double min_aspect_h = xSizeHint.min_aspect.y; // and multiplying would go wrong otherwise
01168         double max_aspect_w = xSizeHint.max_aspect.x;
01169         double max_aspect_h = xSizeHint.max_aspect.y;
01170         // According to ICCCM 4.1.2.3 PMinSize should be a fallback for PBaseSize for size increments,
01171         // but not for aspect ratio. Since this code comes from FVWM, handles both at the same time,
01172         // and I have no idea how it works, let's hope nobody relies on that.
01173         w -= xSizeHint.base_width;
01174         h -= xSizeHint.base_height;
01175         int max_width = max_size.width() - xSizeHint.base_width;
01176         int min_width = min_size.width() - xSizeHint.base_width;
01177         int max_height = max_size.height() - xSizeHint.base_height;
01178         int min_height = min_size.height() - xSizeHint.base_height;
01179 #define ASPECT_CHECK_GROW_W \
01180         if( min_aspect_w * h > min_aspect_h * w ) \
01181             { \
01182             int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \
01183             if( w + delta <= max_width ) \
01184                 w += delta; \
01185             }
01186 #define ASPECT_CHECK_SHRINK_H_GROW_W \
01187         if( min_aspect_w * h > min_aspect_h * w ) \
01188             { \
01189             int delta = int( h - w * min_aspect_h / min_aspect_w ) / height_inc * height_inc; \
01190             if( h - delta >= min_height ) \
01191                 h -= delta; \
01192             else \
01193                 { \
01194                 int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \
01195                 if( w + delta <= max_width ) \
01196                     w += delta; \
01197                 } \
01198             }
01199 #define ASPECT_CHECK_GROW_H \
01200         if( max_aspect_w * h < max_aspect_h * w ) \
01201             { \
01202             int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \
01203             if( h + delta <= max_height ) \
01204                 h += delta; \
01205             }
01206 #define ASPECT_CHECK_SHRINK_W_GROW_H \
01207         if( max_aspect_w * h < max_aspect_h * w ) \
01208             { \
01209             int delta = int( w - max_aspect_w * h / max_aspect_h ) / width_inc * width_inc; \
01210             if( w - delta >= min_width ) \
01211                 w -= delta; \
01212             else \
01213                 { \
01214                 int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \
01215                 if( h + delta <= max_height ) \
01216                     h += delta; \
01217                 } \
01218             }
01219         switch( mode )
01220             {
01221             case SizemodeAny:
01222 #if 0 // make SizemodeAny equal to SizemodeFixedW - prefer keeping fixed width,
01223       // so that changing aspect ratio to a different value and back keeps the same size (#87298)
01224                 {
01225                 ASPECT_CHECK_SHRINK_H_GROW_W
01226                 ASPECT_CHECK_SHRINK_W_GROW_H
01227                 ASPECT_CHECK_GROW_H
01228                 ASPECT_CHECK_GROW_W
01229                 break;
01230                 }
01231 #endif
01232             case SizemodeFixedW:
01233                 {
01234                 // the checks are order so that attempts to modify height are first
01235                 ASPECT_CHECK_GROW_H
01236                 ASPECT_CHECK_SHRINK_H_GROW_W
01237                 ASPECT_CHECK_SHRINK_W_GROW_H
01238                 ASPECT_CHECK_GROW_W
01239                 break;
01240                 }
01241             case SizemodeFixedH:
01242                 {
01243                 ASPECT_CHECK_GROW_W
01244                 ASPECT_CHECK_SHRINK_W_GROW_H
01245                 ASPECT_CHECK_SHRINK_H_GROW_W
01246                 ASPECT_CHECK_GROW_H
01247                 break;
01248                 }
01249             case SizemodeMax:
01250                 {
01251                 // first checks that try to shrink
01252                 ASPECT_CHECK_SHRINK_H_GROW_W
01253                 ASPECT_CHECK_SHRINK_W_GROW_H
01254                 ASPECT_CHECK_GROW_W
01255                 ASPECT_CHECK_GROW_H
01256                 break;
01257                 }
01258             }
01259 #undef ASPECT_CHECK_SHRINK_H_GROW_W
01260 #undef ASPECT_CHECK_SHRINK_W_GROW_H
01261 #undef ASPECT_CHECK_GROW_W
01262 #undef ASPECT_CHECK_GROW_H
01263         w += xSizeHint.base_width;
01264         h += xSizeHint.base_height;
01265         }
01266     if( !rules()->checkStrictGeometry( false ))
01267         {
01268         // disobey increments and aspect when maximized
01269         if( maximizeMode() & MaximizeHorizontal )
01270             w = w1;
01271         if( maximizeMode() & MaximizeVertical )
01272             h = h1;
01273         }
01274 
01275     if( !noframe )
01276         {
01277         w += border_left + border_right;
01278         h += border_top + border_bottom;
01279         }
01280     return rules()->checkSize( TQSize( w, h ));
01281     }
01282 
01286 void Client::getWmNormalHints()
01287     {
01288     long msize;
01289     if (XGetWMNormalHints(qt_xdisplay(), window(), &xSizeHint, &msize) == 0 )
01290         xSizeHint.flags = 0;
01291     // set defined values for the fields, even if they're not in flags
01292 
01293     if( ! ( xSizeHint.flags & PMinSize ))
01294         xSizeHint.min_width = xSizeHint.min_height = 0;
01295     if( xSizeHint.flags & PBaseSize )
01296         {
01297         // PBaseSize is a fallback for PMinSize according to ICCCM 4.1.2.3
01298         // The other way around PMinSize is not a complete fallback for PBaseSize,
01299         // so that's not handled here.
01300         if( ! ( xSizeHint.flags & PMinSize ))
01301             {
01302             xSizeHint.min_width = xSizeHint.base_width;
01303             xSizeHint.min_height = xSizeHint.base_height;
01304             }
01305         }
01306     else
01307         xSizeHint.base_width = xSizeHint.base_height = 0;
01308     if( ! ( xSizeHint.flags & PMaxSize ))
01309         xSizeHint.max_width = xSizeHint.max_height = INT_MAX;
01310     else
01311         {
01312         xSizeHint.max_width = QMAX( xSizeHint.max_width, 1 );
01313         xSizeHint.max_height = QMAX( xSizeHint.max_height, 1 );
01314         }
01315     if( xSizeHint.flags & PResizeInc )
01316         {
01317         xSizeHint.width_inc = kMax( xSizeHint.width_inc, 1 );
01318         xSizeHint.height_inc = kMax( xSizeHint.height_inc, 1 );
01319         }
01320     else
01321         {
01322         xSizeHint.width_inc = 1;
01323         xSizeHint.height_inc = 1;
01324         }
01325     if( xSizeHint.flags & PAspect )
01326         { // no dividing by zero
01327         xSizeHint.min_aspect.y = kMax( xSizeHint.min_aspect.y, 1 );
01328         xSizeHint.max_aspect.y = kMax( xSizeHint.max_aspect.y, 1 );
01329         }
01330     else
01331         {
01332         xSizeHint.min_aspect.x = 1;
01333         xSizeHint.min_aspect.y = INT_MAX;
01334         xSizeHint.max_aspect.x = INT_MAX;
01335         xSizeHint.max_aspect.y = 1;
01336         }
01337     if( ! ( xSizeHint.flags & PWinGravity ))
01338         xSizeHint.win_gravity = NorthWestGravity;
01339     if( isManaged())
01340         { // update to match restrictions
01341         TQSize new_size = adjustedSize();
01342         if( new_size != size() && !isFullScreen())
01343             {
01344             TQRect orig_geometry = geometry();
01345             resizeWithChecks( new_size );
01346             if( ( !isSpecialWindow() || isToolbar()) && !isFullScreen())
01347                 {
01348                 // try to keep the window in its xinerama screen if possible,
01349                 // if that fails at least keep it visible somewhere
01350                 TQRect area = workspace()->clientArea( MovementArea, this );
01351                 if( area.contains( orig_geometry ))
01352                     keepInArea( area );
01353                 area = workspace()->clientArea( WorkArea, this );
01354                 if( area.contains( orig_geometry ))
01355                     keepInArea( area );
01356                 }
01357             }
01358         }
01359     updateAllowedActions(); // affects isResizeable()
01360     }
01361 
01362 TQSize Client::minSize() const
01363     {
01364     return rules()->checkMinSize( TQSize( xSizeHint.min_width, xSizeHint.min_height ));
01365     }
01366 
01367 TQSize Client::maxSize() const
01368     {
01369     return rules()->checkMaxSize( TQSize( xSizeHint.max_width, xSizeHint.max_height ));
01370     }
01371 
01377 void Client::sendSyntheticConfigureNotify()
01378     {
01379     XConfigureEvent c;
01380     c.type = ConfigureNotify;
01381     c.send_event = True;
01382     c.event = window();
01383     c.window = window();
01384     c.x = x() + clientPos().x();
01385     c.y = y() + clientPos().y();
01386     c.width = clientSize().width();
01387     c.height = clientSize().height();
01388     c.border_width = 0;
01389     c.above = None;
01390     c.override_redirect = 0;
01391     XSendEvent( qt_xdisplay(), c.event, TRUE, StructureNotifyMask, (XEvent*)&c );
01392     }
01393 
01394 const TQPoint Client::calculateGravitation( bool invert, int gravity ) const
01395     {
01396     int dx, dy;
01397     dx = dy = 0;
01398 
01399     if( gravity == 0 ) // default (nonsense) value for the argument
01400         gravity = xSizeHint.win_gravity;
01401 
01402 // dx, dy specify how the client window moves to make space for the frame
01403     switch (gravity)
01404         {
01405         case NorthWestGravity: // move down right
01406         default:
01407             dx = border_left;
01408             dy = border_top;
01409             break;
01410         case NorthGravity: // move right
01411             dx = 0;
01412             dy = border_top;
01413             break;
01414         case NorthEastGravity: // move down left
01415             dx = -border_right;
01416             dy = border_top;
01417             break;
01418         case WestGravity: // move right
01419             dx = border_left;
01420             dy = 0;
01421             break;
01422         case CenterGravity:
01423             break; // will be handled specially
01424         case StaticGravity: // don't move
01425             dx = 0;
01426             dy = 0;
01427             break;
01428         case EastGravity: // move left
01429             dx = -border_right;
01430             dy = 0;
01431             break;
01432         case SouthWestGravity: // move up right
01433             dx = border_left ;
01434             dy = -border_bottom;
01435             break;
01436         case SouthGravity: // move up
01437             dx = 0;
01438             dy = -border_bottom;
01439             break;
01440         case SouthEastGravity: // move up left
01441             dx = -border_right;
01442             dy = -border_bottom;
01443             break;
01444         }
01445     if( gravity != CenterGravity )
01446         { // translate from client movement to frame movement
01447         dx -= border_left;
01448         dy -= border_top;
01449         }
01450     else
01451         { // center of the frame will be at the same position client center without frame would be
01452         dx = - ( border_left + border_right ) / 2;
01453         dy = - ( border_top + border_bottom ) / 2;
01454         }
01455     if( !invert )
01456         return TQPoint( x() + dx, y() + dy );
01457     else
01458         return TQPoint( x() - dx, y() - dy );
01459     }
01460 
01461 void Client::configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool )
01462     {
01463     if( gravity == 0 ) // default (nonsense) value for the argument
01464         gravity = xSizeHint.win_gravity;
01465     if( value_mask & ( CWX | CWY ))
01466         {
01467         TQPoint new_pos = calculateGravitation( true, gravity ); // undo gravitation
01468         if ( value_mask & CWX )
01469             new_pos.setX( rx );
01470         if ( value_mask & CWY )
01471             new_pos.setY( ry );
01472 
01473         // clever(?) workaround for applications like xv that want to set
01474         // the location to the current location but miscalculate the
01475         // frame size due to kwin being a double-reparenting window
01476         // manager
01477         if ( new_pos.x() == x() + clientPos().x() && new_pos.y() == y() + clientPos().y()
01478             && gravity == NorthWestGravity && !from_tool )
01479             {
01480             new_pos.setX( x());
01481             new_pos.setY( y());
01482             }
01483 
01484         int nw = clientSize().width();
01485         int nh = clientSize().height();
01486         if ( value_mask & CWWidth )
01487             nw = rw;
01488         if ( value_mask & CWHeight )
01489             nh = rh;
01490         TQSize ns = sizeForClientSize( TQSize( nw, nh ) );
01491         new_pos = rules()->checkPosition( new_pos );
01492 
01493         // TODO what to do with maximized windows?
01494         if ( maximizeMode() != MaximizeFull
01495             || ns != size())
01496             {
01497             TQRect orig_geometry = geometry();
01498             GeometryUpdatesPostponer blocker( this );
01499             move( new_pos );
01500             plainResize( ns );
01501             setGeometry( TQRect( calculateGravitation( false, gravity ), size()));
01502             updateFullScreenHack( TQRect( new_pos, TQSize( nw, nh )));
01503             TQRect area = workspace()->clientArea( WorkArea, this );
01504             if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen()
01505                 && area.contains( orig_geometry ))
01506                 keepInArea( area );
01507 
01508             // this is part of the kicker-xinerama-hack... it should be
01509             // safe to remove when kicker gets proper ExtendedStrut support;
01510             // see Workspace::updateClientArea() and
01511             // Client::adjustedClientArea()
01512             if (hasStrut ())
01513                 workspace() -> updateClientArea ();
01514             }
01515         }
01516 
01517     if ( value_mask & (CWWidth | CWHeight )
01518         && ! ( value_mask & ( CWX | CWY )) )  // pure resize
01519         {
01520         int nw = clientSize().width();
01521         int nh = clientSize().height();
01522         if ( value_mask & CWWidth )
01523             nw = rw;
01524         if ( value_mask & CWHeight )
01525             nh = rh;
01526         TQSize ns = sizeForClientSize( TQSize( nw, nh ) );
01527 
01528         if( ns != size())  // don't restore if some app sets its own size again
01529             {
01530             TQRect orig_geometry = geometry();
01531             GeometryUpdatesPostponer blocker( this );
01532             int save_gravity = xSizeHint.win_gravity;
01533             xSizeHint.win_gravity = gravity;
01534             resizeWithChecks( ns );
01535             xSizeHint.win_gravity = save_gravity;
01536             updateFullScreenHack( TQRect( calculateGravitation( true, xSizeHint.win_gravity ), TQSize( nw, nh )));
01537             if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen())
01538                 {
01539                 // try to keep the window in its xinerama screen if possible,
01540                 // if that fails at least keep it visible somewhere
01541                 TQRect area = workspace()->clientArea( MovementArea, this );
01542                 if( area.contains( orig_geometry ))
01543                     keepInArea( area );
01544                 area = workspace()->clientArea( WorkArea, this );
01545                 if( area.contains( orig_geometry ))
01546                     keepInArea( area );
01547                 }
01548             }
01549         }
01550     // No need to send synthetic configure notify event here, either it's sent together
01551     // with geometry change, or there's no need to send it.
01552     // Handling of the real ConfigureRequest event forces sending it, as there it's necessary.
01553     }
01554 
01555 void Client::resizeWithChecks( int w, int h, ForceGeometry_t force )
01556     {
01557     if( shade_geometry_change )
01558         assert( false );
01559     else if( isShade())
01560         {
01561         if( h == border_top + border_bottom )
01562             {
01563             kdWarning() << "Shaded geometry passed for size:" << endl;
01564             kdWarning() << kdBacktrace() << endl;
01565             }
01566         }
01567     int newx = x();
01568     int newy = y();
01569     TQRect area = workspace()->clientArea( WorkArea, this );
01570     // don't allow growing larger than workarea
01571     if( w > area.width())
01572         w = area.width();
01573     if( h > area.height())
01574         h = area.height();
01575     TQSize tmp = adjustedSize( TQSize( w, h )); // checks size constraints, including min/max size
01576     w = tmp.width();
01577     h = tmp.height();
01578     switch( xSizeHint.win_gravity )
01579         {
01580         case NorthWestGravity: // top left corner doesn't move
01581         default:
01582             break;
01583         case NorthGravity: // middle of top border doesn't move
01584             newx = ( newx + width() / 2 ) - ( w / 2 );
01585             break;
01586         case NorthEastGravity: // top right corner doesn't move
01587             newx = newx + width() - w;
01588             break;
01589         case WestGravity: // middle of left border doesn't move
01590             newy = ( newy + height() / 2 ) - ( h / 2 );
01591             break;
01592         case CenterGravity: // middle point doesn't move
01593             newx = ( newx + width() / 2 ) - ( w / 2 );
01594             newy = ( newy + height() / 2 ) - ( h / 2 );
01595             break;
01596         case StaticGravity: // top left corner of _client_ window doesn't move
01597             // since decoration doesn't change, equal to NorthWestGravity
01598             break;
01599         case EastGravity: // // middle of right border doesn't move
01600             newx = newx + width() - w;
01601             newy = ( newy + height() / 2 ) - ( h / 2 );
01602             break;
01603         case SouthWestGravity: // bottom left corner doesn't move
01604             newy = newy + height() - h;
01605             break;
01606         case SouthGravity: // middle of bottom border doesn't move
01607             newx = ( newx + width() / 2 ) - ( w / 2 );
01608             newy = newy + height() - h;
01609             break;
01610         case SouthEastGravity: // bottom right corner doesn't move
01611             newx = newx + width() - w;
01612             newy = newy + height() - h;
01613             break;
01614         }
01615     // if it would be moved outside of workarea, keep it inside,
01616     // see also Client::computeWorkareaDiff()
01617     if( workarea_diff_x != INT_MIN && w <= area.width()) // was inside and can still fit
01618         {
01619         if( newx < area.left())
01620             newx = area.left();
01621         if( newx + w > area.right() + 1 )
01622             newx = area.right() + 1 - w;
01623         assert( newx >= area.left() && newx + w <= area.right() + 1 ); // width was checked above
01624         }
01625     if( workarea_diff_y != INT_MIN && h <= area.height()) // was inside and can still fit
01626         {
01627         if( newy < area.top())
01628             newy = area.top();
01629         if( newy + h > area.bottom() + 1 )
01630             newy = area.bottom() + 1 - h;
01631         assert( newy >= area.top() && newy + h <= area.bottom() + 1 ); // height was checked above
01632         }
01633     setGeometry( newx, newy, w, h, force );
01634     }
01635 
01636 // _NET_MOVERESIZE_WINDOW
01637 void Client::NETMoveResizeWindow( int flags, int x, int y, int width, int height )
01638     {
01639     int gravity = flags & 0xff;
01640     int value_mask = 0;
01641     if( flags & ( 1 << 8 ))
01642         value_mask |= CWX;
01643     if( flags & ( 1 << 9 ))
01644         value_mask |= CWY;
01645     if( flags & ( 1 << 10 ))
01646         value_mask |= CWWidth;
01647     if( flags & ( 1 << 11 ))
01648         value_mask |= CWHeight;
01649     configureRequest( value_mask, x, y, width, height, gravity, true );
01650     }
01651 
01656 bool Client::isMovable() const
01657     {
01658     if( !motif_may_move || isFullScreen())
01659         return false;
01660     if( isSpecialWindow() && !isSplash() && !isToolbar()) // allow moving of splashscreens :)
01661         return false;
01662     if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01663         return false;
01664     if( rules()->checkPosition( invalidPoint ) != invalidPoint ) // forced position
01665         return false;
01666     return true;
01667     }
01668 
01672 bool Client::isResizable() const
01673     {
01674     if( !motif_may_resize || isFullScreen())
01675         return false;
01676     if( isSpecialWindow() )
01677         return false;
01678     if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() )
01679         return false;
01680     if( rules()->checkSize( TQSize()).isValid()) // forced size
01681         return false;
01682 
01683     TQSize min = minSize();
01684     TQSize max = maxSize();
01685     return min.width() < max.width() || min.height() < max.height();
01686     }
01687 
01688 /*
01689   Returns whether the window is maximizable or not
01690  */
01691 bool Client::isMaximizable() const
01692     {
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( Qt::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 && o != 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(), qt_x_time ) == Success )
02323         has_grab = true;
02324     if( XGrabKeyboard( qt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, 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(), qt_x_time );
02393     XUngrabPointer( qt_xdisplay(), 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 constrains), then snap, then check bounds, then check constrains
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, 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.5.6
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |