diff options
Diffstat (limited to 'kwin/geometry.cpp')
-rw-r--r-- | kwin/geometry.cpp | 2649 |
1 files changed, 0 insertions, 2649 deletions
diff --git a/kwin/geometry.cpp b/kwin/geometry.cpp deleted file mode 100644 index 2e0b205c7..000000000 --- a/kwin/geometry.cpp +++ /dev/null @@ -1,2649 +0,0 @@ -/***************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org> -Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> - -You can Freely distribute this program under the GNU General Public -License. See the file "COPYING" for the exact licensing terms. -******************************************************************/ - -/* - - This file contains things relevant to geometry, i.e. workspace size, - window positions and window sizes. - -*/ - -#include "client.h" -#include "workspace.h" - -#include <kapplication.h> -#include <kglobal.h> -#include <tqpainter.h> -#include <twin.h> - -#include "placement.h" -#include "notifications.h" -#include "geometrytip.h" -#include "rules.h" - -namespace KWinInternal -{ - -//******************************************** -// Workspace -//******************************************** - -/*! - Resizes the workspace after an XRANDR screen size change - */ -void Workspace::desktopResized() - { - //printf("Workspace::desktopResized()\n\r"); - TQRect geom = KApplication::desktop()->geometry(); - NETSize desktop_geometry; - desktop_geometry.width = geom.width(); - desktop_geometry.height = geom.height(); - rootInfo->setDesktopGeometry( -1, desktop_geometry ); - - updateClientArea( true ); - checkElectricBorders( true ); - } - -/*! - Resizes the workspace after kdesktop signals a desktop resize - */ -void Workspace::kDestopResized() - { - //printf("Workspace::kDesktopResized()\n\r"); - TQRect geom = KApplication::desktop()->geometry(); - NETSize desktop_geometry; - desktop_geometry.width = geom.width(); - desktop_geometry.height = geom.height(); - rootInfo->setDesktopGeometry( -1, desktop_geometry ); - - updateClientArea( true ); - checkElectricBorders( true ); - } - -/*! - Updates the current client areas according to the current clients. - - If the area changes or force is true, the new areas are propagated to the world. - - The client area is the area that is available for clients (that - which is not taken by windows like panels, the top-of-screen menu - etc). - - \sa clientArea() - */ - -void Workspace::updateClientArea( bool force ) - { - TQDesktopWidget *desktopwidget = KApplication::desktop(); - int nscreens = desktopwidget -> numScreens (); -// kdDebug () << "screens: " << nscreens << endl; - TQRect* new_wareas = new TQRect[ numberOfDesktops() + 1 ]; - TQRect** new_sareas = new TQRect*[ numberOfDesktops() + 1]; - TQRect* screens = new TQRect [ nscreens ]; - TQRect desktopArea = desktopwidget -> geometry (); - for( int iS = 0; - iS < nscreens; - iS ++ ) - { - screens [iS] = desktopwidget -> screenGeometry (iS); - } - for( int i = 1; - i <= numberOfDesktops(); - ++i ) - { - new_wareas[ i ] = desktopArea; - new_sareas[ i ] = new TQRect [ nscreens ]; - for( int iS = 0; - iS < nscreens; - iS ++ ) - new_sareas[ i ][ iS ] = screens[ iS ]; - } - for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) - { - if( !(*it)->hasStrut()) - continue; - TQRect r = (*it)->adjustedClientArea( desktopArea, desktopArea ); - if( (*it)->isOnAllDesktops()) - for( int i = 1; - i <= numberOfDesktops(); - ++i ) - { - new_wareas[ i ] = new_wareas[ i ].intersect( r ); - for( int iS = 0; - iS < nscreens; - iS ++ ) - new_sareas[ i ][ iS ] = - new_sareas[ i ][ iS ].intersect( - (*it)->adjustedClientArea( desktopArea, screens[ iS ] ) - ); - } - else - { - new_wareas[ (*it)->desktop() ] = new_wareas[ (*it)->desktop() ].intersect( r ); - for( int iS = 0; - iS < nscreens; - iS ++ ) - { -// kdDebug () << "adjusting new_sarea: " << screens[ iS ] << endl; - new_sareas[ (*it)->desktop() ][ iS ] = - new_sareas[ (*it)->desktop() ][ iS ].intersect( - (*it)->adjustedClientArea( desktopArea, screens[ iS ] ) - ); - } - } - } -#if 0 - for( int i = 1; - i <= numberOfDesktops(); - ++i ) - { - for( int iS = 0; - iS < nscreens; - iS ++ ) - kdDebug () << "new_sarea: " << new_sareas[ i ][ iS ] << endl; - } -#endif - // TODO topmenu update for screenarea changes? - if( topmenu_space != NULL ) - { - TQRect topmenu_area = desktopArea; - topmenu_area.setTop( topMenuHeight()); - for( int i = 1; - i <= numberOfDesktops(); - ++i ) - new_wareas[ i ] = new_wareas[ i ].intersect( topmenu_area ); - } - - bool changed = force; - - if (! screenarea) - changed = true; - - for( int i = 1; - !changed && i <= numberOfDesktops(); - ++i ) - { - if( workarea[ i ] != new_wareas[ i ] ) - changed = true; - for( int iS = 0; - iS < nscreens; - iS ++ ) - if (new_sareas[ i ][ iS ] != screenarea [ i ][ iS ]) - changed = true; - } - - if ( changed ) - { - delete[] workarea; - workarea = new_wareas; - new_wareas = NULL; - delete[] screenarea; - screenarea = new_sareas; - new_sareas = NULL; - NETRect r; - for( int i = 1; i <= numberOfDesktops(); i++) - { - r.pos.x = workarea[ i ].x(); - r.pos.y = workarea[ i ].y(); - r.size.width = workarea[ i ].width(); - r.size.height = workarea[ i ].height(); - rootInfo->setWorkArea( i, r ); - } - - updateTopMenuGeometry(); - for( ClientList::ConstIterator it = clients.begin(); - it != clients.end(); - ++it) - (*it)->checkWorkspacePosition(); - for( ClientList::ConstIterator it = desktops.begin(); - it != desktops.end(); - ++it) - (*it)->checkWorkspacePosition(); - } - delete[] screens; - delete[] new_sareas; - delete[] new_wareas; - } - -void Workspace::updateClientArea() - { - updateClientArea( false ); - } - - -/*! - returns the area available for clients. This is the desktop - geometry minus windows on the dock. Placement algorithms should - refer to this rather than geometry(). - - \sa geometry() - */ -TQRect Workspace::clientArea( clientAreaOption opt, int screen, int desktop ) const - { - if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 ) - desktop = currentDesktop(); - TQDesktopWidget *desktopwidget = kapp->desktop(); - TQRect sarea = screenarea // may be NULL during KWin initialization - ? screenarea[ desktop ][ screen ] - : desktopwidget->screenGeometry( screen ); - TQRect warea = workarea[ desktop ].isNull() - ? kapp->desktop()->geometry() - : workarea[ desktop ]; - switch (opt) - { - case MaximizeArea: - if (options->xineramaMaximizeEnabled) - if (desktopwidget->numScreens() < 2) - return warea; - else - return sarea; - else - return warea; - case MaximizeFullArea: - if (options->xineramaMaximizeEnabled) - if (desktopwidget->numScreens() < 2) - return desktopwidget->geometry(); - else - return desktopwidget->screenGeometry( screen ); - else - return desktopwidget->geometry(); - case FullScreenArea: - if (options->xineramaFullscreenEnabled) - if (desktopwidget->numScreens() < 2) - return desktopwidget->geometry(); - else - return desktopwidget->screenGeometry( screen ); - else - return desktopwidget->geometry(); - case PlacementArea: - if (options->xineramaPlacementEnabled) - if (desktopwidget->numScreens() < 2) - return warea; - else - return sarea; - else - return warea; - case MovementArea: - if (options->xineramaMovementEnabled) - if (desktopwidget->numScreens() < 2) - return desktopwidget->geometry(); - else - return desktopwidget->screenGeometry( screen ); - else - return desktopwidget->geometry(); - case WorkArea: - return warea; - case FullArea: - return desktopwidget->geometry(); - case ScreenArea: - if (desktopwidget->numScreens() < 2) - return desktopwidget->geometry(); - else - return desktopwidget->screenGeometry( screen ); - } - assert( false ); - return TQRect(); - } - -TQRect Workspace::clientArea( clientAreaOption opt, const TQPoint& p, int desktop ) const - { - TQDesktopWidget *desktopwidget = KApplication::desktop(); - int screen = desktopwidget->screenNumber( p ); - if( screen < 0 ) - screen = desktopwidget->primaryScreen(); - return clientArea( opt, screen, desktop ); - } - -TQRect Workspace::clientArea( clientAreaOption opt, const Client* c ) const - { - return clientArea( opt, c->geometry().center(), c->desktop()); - } - - -/*! - Client \a c is moved around to position \a pos. This gives the - workspace the opportunity to interveniate and to implement - snap-to-windows functionality. - */ -TQPoint Workspace::adjustClientPosition( Client* c, TQPoint pos ) - { - //CT 16mar98, 27May98 - magics: BorderSnapZone, WindowSnapZone - //CT adapted for twin on 25Nov1999 - //aleXXX 02Nov2000 added second snapping mode - if (options->windowSnapZone || options->borderSnapZone ) - { - const bool sOWO=options->snapOnlyWhenOverlapping; - const TQRect maxRect = clientArea(MovementArea, pos+c->rect().center(), c->desktop()); - const int xmin = maxRect.left(); - const int xmax = maxRect.right()+1; //desk size - const int ymin = maxRect.top(); - const int ymax = maxRect.bottom()+1; - - const int cx(pos.x()); - const int cy(pos.y()); - const int cw(c->width()); - const int ch(c->height()); - const int rx(cx+cw); - const int ry(cy+ch); //these don't change - - int nx(cx), ny(cy); //buffers - int deltaX(xmax); - int deltaY(ymax); //minimum distance to other clients - - int lx, ly, lrx, lry; //coords and size for the comparison client, l - - // border snap - int snap = options->borderSnapZone; //snap trigger - if (snap) - { - if ((sOWO?(cx<xmin):true) && (QABS(xmin-cx)<snap)) - { - deltaX = xmin-cx; - nx = xmin; - } - if ((sOWO?(rx>xmax):true) && (QABS(rx-xmax)<snap) && (QABS(xmax-rx) < deltaX)) - { - deltaX = rx-xmax; - nx = xmax - cw; - } - - if ((sOWO?(cy<ymin):true) && (QABS(ymin-cy)<snap)) - { - deltaY = ymin-cy; - ny = ymin; - } - if ((sOWO?(ry>ymax):true) && (QABS(ry-ymax)<snap) && (QABS(ymax-ry) < deltaY)) - { - deltaY =ry-ymax; - ny = ymax - ch; - } - } - - // windows snap - snap = options->windowSnapZone; - if (snap) - { - TQValueList<Client *>::ConstIterator l; - for (l = clients.begin();l != clients.end();++l ) - { - if ((*l)->isOnDesktop(currentDesktop()) && - !(*l)->isMinimized() - && (*l) != c ) - { - lx = (*l)->x(); - ly = (*l)->y(); - lrx = lx + (*l)->width(); - lry = ly + (*l)->height(); - - if ( (( cy <= lry ) && ( cy >= ly )) || - (( ry >= ly ) && ( ry <= lry )) || - (( cy <= ly ) && ( ry >= lry )) ) - { - if ((sOWO?(cx<lrx):true) && (QABS(lrx-cx)<snap) && ( QABS(lrx -cx) < deltaX) ) - { - deltaX = QABS( lrx - cx ); - nx = lrx; - } - if ((sOWO?(rx>lx):true) && (QABS(rx-lx)<snap) && ( QABS( rx - lx )<deltaX) ) - { - deltaX = QABS(rx - lx); - nx = lx - cw; - } - } - - if ( (( cx <= lrx ) && ( cx >= lx )) || - (( rx >= lx ) && ( rx <= lrx )) || - (( cx <= lx ) && ( rx >= lrx )) ) - { - if ((sOWO?(cy<lry):true) && (QABS(lry-cy)<snap) && (QABS( lry -cy ) < deltaY)) - { - deltaY = QABS( lry - cy ); - ny = lry; - } - //if ( (QABS( ry-ly ) < snap) && (QABS( ry - ly ) < deltaY )) - if ((sOWO?(ry>ly):true) && (QABS(ry-ly)<snap) && (QABS( ry - ly ) < deltaY )) - { - deltaY = QABS( ry - ly ); - ny = ly - ch; - } - } - } - } - } - pos = TQPoint(nx, ny); - } - return pos; - } - -TQRect Workspace::adjustClientSize( Client* c, TQRect moveResizeGeom, int mode ) - { - //adapted from adjustClientPosition on 29May2004 - //this function is called when resizing a window and will modify - //the new dimensions to snap to other windows/borders if appropriate - if ( options->windowSnapZone || options->borderSnapZone ) - { - const bool sOWO=options->snapOnlyWhenOverlapping; - - const TQRect maxRect = clientArea(MovementArea, c->rect().center(), c->desktop()); - const int xmin = maxRect.left(); - const int xmax = maxRect.right(); //desk size - const int ymin = maxRect.top(); - const int ymax = maxRect.bottom(); - - const int cx(moveResizeGeom.left()); - const int cy(moveResizeGeom.top()); - const int rx(moveResizeGeom.right()); - const int ry(moveResizeGeom.bottom()); - - int newcx(cx), newcy(cy); //buffers - int newrx(rx), newry(ry); - int deltaX(xmax); - int deltaY(ymax); //minimum distance to other clients - - int lx, ly, lrx, lry; //coords and size for the comparison client, l - - // border snap - int snap = options->borderSnapZone; //snap trigger - if (snap) - { - deltaX = int(snap); - deltaY = int(snap); - -#define SNAP_BORDER_TOP \ - if ((sOWO?(newcy<ymin):true) && (QABS(ymin-newcy)<deltaY)) \ - { \ - deltaY = QABS(ymin-newcy); \ - newcy = ymin; \ - } - -#define SNAP_BORDER_BOTTOM \ - if ((sOWO?(newry>ymax):true) && (QABS(ymax-newry)<deltaY)) \ - { \ - deltaY = QABS(ymax-newcy); \ - newry = ymax; \ - } - -#define SNAP_BORDER_LEFT \ - if ((sOWO?(newcx<xmin):true) && (QABS(xmin-newcx)<deltaX)) \ - { \ - deltaX = QABS(xmin-newcx); \ - newcx = xmin; \ - } - -#define SNAP_BORDER_RIGHT \ - if ((sOWO?(newrx>xmax):true) && (QABS(xmax-newrx)<deltaX)) \ - { \ - deltaX = QABS(xmax-newrx); \ - newrx = xmax; \ - } - switch ( mode ) - { - case PositionBottomRight: - SNAP_BORDER_BOTTOM - SNAP_BORDER_RIGHT - break; - case PositionRight: - SNAP_BORDER_RIGHT - break; - case PositionBottom: - SNAP_BORDER_BOTTOM - break; - case PositionTopLeft: - SNAP_BORDER_TOP - SNAP_BORDER_LEFT - break; - case PositionLeft: - SNAP_BORDER_LEFT - break; - case PositionTop: - SNAP_BORDER_TOP - break; - case PositionTopRight: - SNAP_BORDER_TOP - SNAP_BORDER_RIGHT - break; - case PositionBottomLeft: - SNAP_BORDER_BOTTOM - SNAP_BORDER_LEFT - break; - default: - assert( false ); - break; - } - - - } - - // windows snap - snap = options->windowSnapZone; - if (snap) - { - deltaX = int(snap); - deltaY = int(snap); - TQValueList<Client *>::ConstIterator l; - for (l = clients.begin();l != clients.end();++l ) - { - if ((*l)->isOnDesktop(currentDesktop()) && - !(*l)->isMinimized() - && (*l) != c ) - { - lx = (*l)->x()-1; - ly = (*l)->y()-1; - lrx =(*l)->x() + (*l)->width(); - lry =(*l)->y() + (*l)->height(); - -#define WITHIN_HEIGHT ((( newcy <= lry ) && ( newcy >= ly )) || \ - (( newry >= ly ) && ( newry <= lry )) || \ - (( newcy <= ly ) && ( newry >= lry )) ) - -#define WITHIN_WIDTH ( (( cx <= lrx ) && ( cx >= lx )) || \ - (( rx >= lx ) && ( rx <= lrx )) || \ - (( cx <= lx ) && ( rx >= lrx )) ) - -#define SNAP_WINDOW_TOP if ( (sOWO?(newcy<lry):true) \ - && WITHIN_WIDTH \ - && (QABS( lry - newcy ) < deltaY) ) { \ - deltaY = QABS( lry - newcy ); \ - newcy=lry; \ - } - -#define SNAP_WINDOW_BOTTOM if ( (sOWO?(newry>ly):true) \ - && WITHIN_WIDTH \ - && (QABS( ly - newry ) < deltaY) ) { \ - deltaY = QABS( ly - newry ); \ - newry=ly; \ - } - -#define SNAP_WINDOW_LEFT if ( (sOWO?(newcx<lrx):true) \ - && WITHIN_HEIGHT \ - && (QABS( lrx - newcx ) < deltaX)) { \ - deltaX = QABS( lrx - newcx ); \ - newcx=lrx; \ - } - -#define SNAP_WINDOW_RIGHT if ( (sOWO?(newrx>lx):true) \ - && WITHIN_HEIGHT \ - && (QABS( lx - newrx ) < deltaX)) \ - { \ - deltaX = QABS( lx - newrx ); \ - newrx=lx; \ - } - - switch ( mode ) - { - case PositionBottomRight: - SNAP_WINDOW_BOTTOM - SNAP_WINDOW_RIGHT - break; - case PositionRight: - SNAP_WINDOW_RIGHT - break; - case PositionBottom: - SNAP_WINDOW_BOTTOM - break; - case PositionTopLeft: - SNAP_WINDOW_TOP - SNAP_WINDOW_LEFT - break; - case PositionLeft: - SNAP_WINDOW_LEFT - break; - case PositionTop: - SNAP_WINDOW_TOP - break; - case PositionTopRight: - SNAP_WINDOW_TOP - SNAP_WINDOW_RIGHT - break; - case PositionBottomLeft: - SNAP_WINDOW_BOTTOM - SNAP_WINDOW_LEFT - break; - default: - assert( false ); - break; - } - } - } - } - moveResizeGeom = TQRect(TQPoint(newcx, newcy), TQPoint(newrx, newry)); - } - return moveResizeGeom; - } - -/*! - Marks the client as being moved around by the user. - */ -void Workspace::setClientIsMoving( Client *c ) - { - Q_ASSERT(!c || !movingClient); // Catch attempts to move a second - // window while still moving the first one. - movingClient = c; - if (movingClient) - ++block_focus; - else - --block_focus; - } - -/*! - Cascades all clients on the current desktop - */ -void Workspace::cascadeDesktop() - { -// TODO XINERAMA this probably is not right for xinerama - Q_ASSERT( block_stacking_updates == 0 ); - ClientList::ConstIterator it(stackingOrder().begin()); - initPositioning->reinitCascading( currentDesktop()); - TQRect area = clientArea( PlacementArea, TQPoint( 0, 0 ), currentDesktop()); - for (; it != stackingOrder().end(); ++it) - { - if((!(*it)->isOnDesktop(currentDesktop())) || - ((*it)->isMinimized()) || - ((*it)->isOnAllDesktops()) || - (!(*it)->isMovable()) ) - continue; - initPositioning->placeCascaded(*it, area); - } - } - -/*! - Unclutters the current desktop by smart-placing all clients - again. - */ -void Workspace::unclutterDesktop() - { - ClientList::Iterator it(clients.fromLast()); - for (; it != clients.end(); --it) - { - if((!(*it)->isOnDesktop(currentDesktop())) || - ((*it)->isMinimized()) || - ((*it)->isOnAllDesktops()) || - (!(*it)->isMovable()) ) - continue; - initPositioning->placeSmart(*it, TQRect()); - } - } - - -void Workspace::updateTopMenuGeometry( Client* c ) - { - if( !managingTopMenus()) - return; - if( c != NULL ) - { - XEvent ev; - ev.xclient.display = qt_xdisplay(); - ev.xclient.type = ClientMessage; - ev.xclient.window = c->window(); - static Atom msg_type_atom = XInternAtom( qt_xdisplay(), "_KDE_TOPMENU_MINSIZE", False ); - ev.xclient.message_type = msg_type_atom; - ev.xclient.format = 32; - ev.xclient.data.l[0] = GET_QT_X_TIME(); - ev.xclient.data.l[1] = topmenu_space->width(); - ev.xclient.data.l[2] = topmenu_space->height(); - ev.xclient.data.l[3] = 0; - ev.xclient.data.l[4] = 0; - XSendEvent( qt_xdisplay(), c->window(), False, NoEventMask, &ev ); - KWin::setStrut( c->window(), 0, 0, topmenu_height, 0 ); // so that kicker etc. know - c->checkWorkspacePosition(); - return; - } - // c == NULL - update all, including topmenu_space - TQRect area; - area = clientArea( MaximizeFullArea, TQPoint( 0, 0 ), 1 ); // HACK desktop ? - area.setHeight( topMenuHeight()); - topmenu_space->setGeometry( area ); - for( ClientList::ConstIterator it = topmenus.begin(); - it != topmenus.end(); - ++it ) - updateTopMenuGeometry( *it ); - } - -//******************************************** -// Client -//******************************************** - - -void Client::keepInArea( TQRect area, bool partial ) - { - if( partial ) - { - // increase the area so that can have only 100 pixels in the area - area.setLeft( QMIN( area.left() - width() + 100, area.left())); - area.setTop( QMIN( area.top() - height() + 100, area.top())); - area.setRight( QMAX( area.right() + width() - 100, area.right())); - area.setBottom( QMAX( area.bottom() + height() - 100, area.bottom())); - } - if ( geometry().right() > area.right() && width() < area.width() ) - move( area.right() - width(), y() ); - if ( geometry().bottom() > area.bottom() && height() < area.height() ) - move( x(), area.bottom() - height() ); - if( !area.contains( geometry().topLeft() )) - { - int tx = x(); - int ty = y(); - if ( tx < area.x() ) - tx = area.x(); - if ( ty < area.y() ) - ty = area.y(); - move( tx, ty ); - } - } - -/*! - Returns \a area with the client's strut taken into account. - - Used from Workspace in updateClientArea. - */ -// TODO move to Workspace? - -TQRect Client::adjustedClientArea( const TQRect &desktopArea, const TQRect& area ) const - { - TQRect r = area; - // topmenu area is reserved in updateClientArea() - if( isTopMenu()) - return r; - NETExtendedStrut str = strut(); - TQRect stareaL = TQRect( - 0, - str . left_start, - str . left_width, - str . left_end - str . left_start + 1 ); - TQRect stareaR = TQRect ( - desktopArea . right () - str . right_width + 1, - str . right_start, - str . right_width, - str . right_end - str . right_start + 1 ); - TQRect stareaT = TQRect ( - str . top_start, - 0, - str . top_end - str . top_start + 1, - str . top_width); - TQRect stareaB = TQRect ( - str . bottom_start, - desktopArea . bottom () - str . bottom_width + 1, - str . bottom_end - str . bottom_start + 1, - str . bottom_width); - - NETExtendedStrut ext = info->extendedStrut(); - if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0 - && ( str.left_width != 0 || str.right_width != 0 || str.top_width != 0 || str.bottom_width != 0 )) { - - // hack, might cause problems... this tries to guess the start/end of a - // non-extended strut; only works on windows that have exact same - // geometry as their strut (ie, if the geometry fits the width - // exactly, we will adjust length of strut to match the geometry as well; - // otherwise we use the full-edge strut) - - if (stareaT.top() == geometry().top() && stareaT.bottom() == geometry().bottom()) { - stareaT.setLeft(geometry().left()); - stareaT.setRight(geometry().right()); -// kdDebug () << "Trimming top-strut to geometry() to: " << stareaT << endl; - } - if (stareaB.top() == geometry().top() && stareaB.bottom() == geometry().bottom()) { - stareaB.setLeft(geometry().left()); - stareaB.setRight(geometry().right()); -// kdDebug () << "Trimming bottom-strut to geometry(): " << stareaB << endl; - } - if (stareaL.left() == geometry().left() && stareaL.right() == geometry().right()) { - stareaL.setTop(geometry().top()); - stareaL.setBottom(geometry().bottom()); -// kdDebug () << "Trimming left-strut to geometry(): " << stareaL << endl; - } - if (stareaR.left() == geometry().left() && stareaR.right() == geometry().right()) { - stareaR.setTop(geometry().top()); - stareaR.setBottom(geometry().bottom()); -// kdDebug () << "Trimming right-strut to geometry(): " << stareaR << endl; - } - } - - TQRect screenarea = workspace()->clientArea( ScreenArea, this ); - // HACK: workarea handling is not xinerama aware, so if this strut - // reserves place at a xinerama edge that's inside the virtual screen, - // ignore the strut for workspace setting. - if( area == kapp->desktop()->geometry()) - { - if( stareaL.left() < screenarea.left()) - stareaL = TQRect(); - if( stareaR.right() > screenarea.right()) - stareaR = TQRect(); - if( stareaT.top() < screenarea.top()) - stareaT = TQRect(); - if( stareaB.bottom() < screenarea.bottom()) - stareaB = TQRect(); - } - // Handle struts at xinerama edges that are inside the virtual screen. - // They're given in virtual screen coordinates, make them affect only - // their xinerama screen. - stareaL.setLeft( KMAX( stareaL.left(), screenarea.left())); - stareaR.setRight( KMIN( stareaR.right(), screenarea.right())); - stareaT.setTop( KMAX( stareaT.top(), screenarea.top())); - stareaB.setBottom( KMIN( stareaB.bottom(), screenarea.bottom())); - - if (stareaL . intersects (area)) { -// kdDebug () << "Moving left of: " << r << " to " << stareaL.right() + 1 << endl; - r . setLeft( stareaL . right() + 1 ); - } - if (stareaR . intersects (area)) { -// kdDebug () << "Moving right of: " << r << " to " << stareaR.left() - 1 << endl; - r . setRight( stareaR . left() - 1 ); - } - if (stareaT . intersects (area)) { -// kdDebug () << "Moving top of: " << r << " to " << stareaT.bottom() + 1 << endl; - r . setTop( stareaT . bottom() + 1 ); - } - if (stareaB . intersects (area)) { -// kdDebug () << "Moving bottom of: " << r << " to " << stareaB.top() - 1 << endl; - r . setBottom( stareaB . top() - 1 ); - } - return r; - } - -NETExtendedStrut Client::strut() const - { - NETExtendedStrut ext = info->extendedStrut(); - NETStrut str = info->strut(); - if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0 - && ( str.left != 0 || str.right != 0 || str.top != 0 || str.bottom != 0 )) - { - // build extended from simple - if( str.left != 0 ) - { - ext.left_width = str.left; - ext.left_start = 0; - ext.left_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay())); - } - if( str.right != 0 ) - { - ext.right_width = str.right; - ext.right_start = 0; - ext.right_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay())); - } - if( str.top != 0 ) - { - ext.top_width = str.top; - ext.top_start = 0; - ext.top_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay())); - } - if( str.bottom != 0 ) - { - ext.bottom_width = str.bottom; - ext.bottom_start = 0; - ext.bottom_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay())); - } - } - return ext; - } - -bool Client::hasStrut() const - { - NETExtendedStrut ext = strut(); - if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0 ) - return false; - return true; - } - - -// updates differences to workarea edges for all directions -void Client::updateWorkareaDiffs() - { - TQRect area = workspace()->clientArea( WorkArea, this ); - TQRect geom = geometry(); - workarea_diff_x = computeWorkareaDiff( geom.left(), geom.right(), area.left(), area.right()); - workarea_diff_y = computeWorkareaDiff( geom.top(), geom.bottom(), area.top(), area.bottom()); - } - -// If the client was inside workarea in the x direction, and if it was close to the left/right -// edge, return the distance from the left/right edge (negative for left, positive for right) -// INT_MIN means 'not inside workarea', INT_MAX means 'not near edge'. -// In order to recognize 'at the left workarea edge' from 'at the right workarea edge' -// (i.e. negative vs positive zero), the distances are one larger in absolute value than they -// really are (i.e. 5 pixels from the left edge is -6, not -5). A bit hacky, but I'm lazy -// to rewrite it just to make it nicer. If this will ever get touched again, perhaps then. -// the y direction is done the same, just the values will be rotated: top->left, bottom->right -int Client::computeWorkareaDiff( int left, int right, int a_left, int a_right ) - { - int left_diff = left - a_left; - int right_diff = a_right - right; - if( left_diff < 0 || right_diff < 0 ) - return INT_MIN; - else // fully inside workarea in this direction direction - { - // max distance from edge where it's still considered to be close and is kept at that distance - int max_diff = ( a_right - a_left ) / 10; - if( left_diff < right_diff ) - return left_diff < max_diff ? -left_diff - 1 : INT_MAX; - else if( left_diff > right_diff ) - return right_diff < max_diff ? right_diff + 1 : INT_MAX; - return INT_MAX; // not close to workarea edge - } - } - -void Client::checkWorkspacePosition() - { - if( isDesktop()) - { - TQRect area = workspace()->clientArea( FullArea, this ); - if( geometry() != area ) - setGeometry( area ); - return; - } - if( isFullScreen()) - { - TQRect area = workspace()->clientArea( FullScreenArea, this ); - if( geometry() != area ) - setGeometry( area ); - return; - } - if( isDock()) - return; - if( isTopMenu()) - { - if( workspace()->managingTopMenus()) - { - TQRect area; - ClientList mainclients = mainClients(); - if( mainclients.count() == 1 ) - area = workspace()->clientArea( MaximizeFullArea, mainclients.first()); - else - area = workspace()->clientArea( MaximizeFullArea, TQPoint( 0, 0 ), desktop()); - area.setHeight( workspace()->topMenuHeight()); -// kdDebug() << "TOPMENU size adjust: " << area << ":" << this << endl; - setGeometry( area ); - } - return; - } - - if( maximizeMode() != MaximizeRestore ) - // TODO update geom_restore? - changeMaximize( false, false, true ); // adjust size - - if( !isShade()) // TODO - { - int old_diff_x = workarea_diff_x; - int old_diff_y = workarea_diff_y; - updateWorkareaDiffs(); - - // this can be true only if this window was mapped before KWin - // was started - in such case, don't adjust position to workarea, - // because the window already had its position, and if a window - // with a strut altering the workarea would be managed in initialization - // after this one, this window would be moved - if( workspace()->initializing()) - return; - - TQRect area = workspace()->clientArea( WorkArea, this ); - TQRect new_geom = geometry(); - TQRect tmp_rect_x( new_geom.left(), 0, new_geom.width(), 0 ); - TQRect tmp_area_x( area.left(), 0, area.width(), 0 ); - checkDirection( workarea_diff_x, old_diff_x, tmp_rect_x, tmp_area_x ); - // the x<->y swapping - TQRect tmp_rect_y( new_geom.top(), 0, new_geom.height(), 0 ); - TQRect tmp_area_y( area.top(), 0, area.height(), 0 ); - checkDirection( workarea_diff_y, old_diff_y, tmp_rect_y, tmp_area_y ); - new_geom = TQRect( tmp_rect_x.left(), tmp_rect_y.left(), tmp_rect_x.width(), tmp_rect_y.width()); - TQRect final_geom( new_geom.topLeft(), adjustedSize( new_geom.size())); - if( final_geom != new_geom ) // size increments, or size restrictions - { // adjusted size differing matters only for right and bottom edge - if( old_diff_x != INT_MAX && old_diff_x > 0 ) - final_geom.moveRight( area.right() - ( old_diff_x - 1 )); - if( old_diff_y != INT_MAX && old_diff_y > 0 ) - final_geom.moveBottom( area.bottom() - ( old_diff_y - 1 )); - } - if( final_geom != geometry() ) - setGeometry( final_geom ); - // updateWorkareaDiffs(); done already by setGeometry() - } - } - -// Try to be smart about keeping the clients visible. -// If the client was fully inside the workspace before, try to keep -// it still inside the workarea, possibly moving it or making it smaller if possible, -// and try to keep the distance from the nearest workarea edge. -// On the other hand, it it was partially moved outside of the workspace in some direction, -// don't do anything with that direction if it's still at least partially visible. If it's -// not visible anymore at all, make sure it's visible at least partially -// again (not fully, as that could(?) be potentionally annoying) by -// moving it slightly inside the workarea (those '+ 5'). -// Again, this is done for the x direction, y direction will be done by x<->y swapping -void Client::checkDirection( int new_diff, int old_diff, TQRect& rect, const TQRect& area ) - { - if( old_diff != INT_MIN ) // was inside workarea - { - if( old_diff == INT_MAX ) // was in workarea, but far from edge - { - if( new_diff == INT_MIN ) // is not anymore fully in workarea - { - rect.setLeft( area.left()); - rect.setRight( area.right()); - } - return; - } - if( isMovable()) - { - if( old_diff < 0 ) // was in left third, keep distance from left edge - rect.moveLeft( area.left() + ( -old_diff - 1 )); - else // old_diff > 0 // was in right third, keep distance from right edge - rect.moveRight( area.right() - ( old_diff - 1 )); - } - else if( isResizable()) - { - if( old_diff < 0 ) - rect.setLeft( area.left() + ( -old_diff - 1 ) ); - else // old_diff > 0 - rect.setRight( area.right() - ( old_diff - 1 )); - } - if( rect.width() > area.width() && isResizable()) - rect.setWidth( area.width()); - if( isMovable()) - { - if( rect.left() < area.left()) - rect.moveLeft( area.left()); - else if( rect.right() > area.right()) - rect.moveRight( area.right()); - } - } - if( rect.right() < area.left() + 5 || rect.left() > area.right() - 5 ) - { // not visible (almost) at all - try to make it at least partially visible - if( isMovable()) - { - if( rect.left() < area.left() + 5 ) - rect.moveRight( area.left() + 5 ); - if( rect.right() > area.right() - 5 ) - rect.moveLeft( area.right() - 5 ); - } - } - if (!moveResizeMode && options->shadowEnabled(isActive())) - { - // If the user is manually resizing, let Client::leaveMoveResize() - // decide when to redraw the shadow - removeShadow(); - drawIntersectingShadows(); - if (options->shadowEnabled(isActive())) - drawDelayedShadow(); - } - } - -/*! - Adjust the frame size \a frame according to he window's size hints. - */ -TQSize Client::adjustedSize( const TQSize& frame, Sizemode mode ) const - { - // first, get the window size for the given frame size s - - TQSize wsize( frame.width() - ( border_left + border_right ), - frame.height() - ( border_top + border_bottom )); - if( wsize.isEmpty()) - wsize = TQSize( 1, 1 ); - - return sizeForClientSize( wsize, mode, false ); - } - -// this helper returns proper size even if the window is shaded -// see also the comment in Client::setGeometry() -TQSize Client::adjustedSize() const - { - return sizeForClientSize( clientSize()); - } - -/*! - Calculate the appropriate frame size for the given client size \a - wsize. - - \a wsize is adapted according to the window's size hints (minimum, - maximum and incremental size changes). - - */ -TQSize Client::sizeForClientSize( const TQSize& wsize, Sizemode mode, bool noframe ) const - { - int w = wsize.width(); - int h = wsize.height(); - if( w < 1 || h < 1 ) - { - kdWarning() << "sizeForClientSize() with empty size!" << endl; - kdWarning() << kdBacktrace() << endl; - } - if (w<1) w = 1; - if (h<1) h = 1; - - // basesize, minsize, maxsize, paspect and resizeinc have all values defined, - // even if they're not set in flags - see getWmNormalHints() - TQSize min_size = minSize(); - TQSize max_size = maxSize(); - if( decoration != NULL ) - { - TQSize decominsize = decoration->tqminimumSize(); - TQSize border_size( border_left + border_right, border_top + border_bottom ); - if( border_size.width() > decominsize.width()) // just in case - decominsize.setWidth( border_size.width()); - if( border_size.height() > decominsize.height()) - decominsize.setHeight( border_size.height()); - if( decominsize.width() > min_size.width()) - min_size.setWidth( decominsize.width()); - if( decominsize.height() > min_size.height()) - min_size.setHeight( decominsize.height()); - } - w = QMIN( max_size.width(), w ); - h = QMIN( max_size.height(), h ); - w = QMAX( min_size.width(), w ); - h = QMAX( min_size.height(), h ); - - int w1 = w; - int h1 = h; - int width_inc = xSizeHint.width_inc; - int height_inc = xSizeHint.height_inc; - int basew_inc = xSizeHint.min_width; // see getWmNormalHints() - int baseh_inc = xSizeHint.min_height; - w = int(( w - basew_inc ) / width_inc ) * width_inc + basew_inc; - h = int(( h - baseh_inc ) / height_inc ) * height_inc + baseh_inc; -// code for aspect ratios based on code from FVWM - /* - * The math looks like this: - * - * minAspectX dwidth maxAspectX - * ---------- <= ------- <= ---------- - * minAspectY dheight maxAspectY - * - * If that is multiplied out, then the width and height are - * invalid in the following situations: - * - * minAspectX * dheight > minAspectY * dwidth - * maxAspectX * dheight < maxAspectY * dwidth - * - */ - if( xSizeHint.flags & PAspect ) - { - double min_aspect_w = xSizeHint.min_aspect.x; // use doubles, because the values can be MAX_INT - double min_aspect_h = xSizeHint.min_aspect.y; // and multiplying would go wrong otherwise - double max_aspect_w = xSizeHint.max_aspect.x; - double max_aspect_h = xSizeHint.max_aspect.y; - // According to ICCCM 4.1.2.3 PMinSize should be a fallback for PBaseSize for size increments, - // but not for aspect ratio. Since this code comes from FVWM, handles both at the same time, - // and I have no idea how it works, let's hope nobody relies on that. - w -= xSizeHint.base_width; - h -= xSizeHint.base_height; - int max_width = max_size.width() - xSizeHint.base_width; - int min_width = min_size.width() - xSizeHint.base_width; - int max_height = max_size.height() - xSizeHint.base_height; - int min_height = min_size.height() - xSizeHint.base_height; -#define ASPECT_CHECK_GROW_W \ - if( min_aspect_w * h > min_aspect_h * w ) \ - { \ - int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \ - if( w + delta <= max_width ) \ - w += delta; \ - } -#define ASPECT_CHECK_SHRINK_H_GROW_W \ - if( min_aspect_w * h > min_aspect_h * w ) \ - { \ - int delta = int( h - w * min_aspect_h / min_aspect_w ) / height_inc * height_inc; \ - if( h - delta >= min_height ) \ - h -= delta; \ - else \ - { \ - int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \ - if( w + delta <= max_width ) \ - w += delta; \ - } \ - } -#define ASPECT_CHECK_GROW_H \ - if( max_aspect_w * h < max_aspect_h * w ) \ - { \ - int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \ - if( h + delta <= max_height ) \ - h += delta; \ - } -#define ASPECT_CHECK_SHRINK_W_GROW_H \ - if( max_aspect_w * h < max_aspect_h * w ) \ - { \ - int delta = int( w - max_aspect_w * h / max_aspect_h ) / width_inc * width_inc; \ - if( w - delta >= min_width ) \ - w -= delta; \ - else \ - { \ - int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \ - if( h + delta <= max_height ) \ - h += delta; \ - } \ - } - switch( mode ) - { - case SizemodeAny: -#if 0 // make SizemodeAny equal to SizemodeFixedW - prefer keeping fixed width, - // so that changing aspect ratio to a different value and back keeps the same size (#87298) - { - ASPECT_CHECK_SHRINK_H_GROW_W - ASPECT_CHECK_SHRINK_W_GROW_H - ASPECT_CHECK_GROW_H - ASPECT_CHECK_GROW_W - break; - } -#endif - case SizemodeFixedW: - { - // the checks are order so that attempts to modify height are first - ASPECT_CHECK_GROW_H - ASPECT_CHECK_SHRINK_H_GROW_W - ASPECT_CHECK_SHRINK_W_GROW_H - ASPECT_CHECK_GROW_W - break; - } - case SizemodeFixedH: - { - ASPECT_CHECK_GROW_W - ASPECT_CHECK_SHRINK_W_GROW_H - ASPECT_CHECK_SHRINK_H_GROW_W - ASPECT_CHECK_GROW_H - break; - } - case SizemodeMax: - { - // first checks that try to shrink - ASPECT_CHECK_SHRINK_H_GROW_W - ASPECT_CHECK_SHRINK_W_GROW_H - ASPECT_CHECK_GROW_W - ASPECT_CHECK_GROW_H - break; - } - } -#undef ASPECT_CHECK_SHRINK_H_GROW_W -#undef ASPECT_CHECK_SHRINK_W_GROW_H -#undef ASPECT_CHECK_GROW_W -#undef ASPECT_CHECK_GROW_H - w += xSizeHint.base_width; - h += xSizeHint.base_height; - } - if( !rules()->checkStrictGeometry( false )) - { - // disobey increments and aspect when maximized - if( maximizeMode() & MaximizeHorizontal ) - w = w1; - if( maximizeMode() & MaximizeVertical ) - h = h1; - } - - if( !noframe ) - { - w += border_left + border_right; - h += border_top + border_bottom; - } - return rules()->checkSize( TQSize( w, h )); - } - -/*! - Gets the client's normal WM hints and reconfigures itself respectively. - */ -void Client::getWmNormalHints() - { - long msize; - if (XGetWMNormalHints(qt_xdisplay(), window(), &xSizeHint, &msize) == 0 ) - xSizeHint.flags = 0; - // set defined values for the fields, even if they're not in flags - - if( ! ( xSizeHint.flags & PMinSize )) - xSizeHint.min_width = xSizeHint.min_height = 0; - if( xSizeHint.flags & PBaseSize ) - { - // PBaseSize is a fallback for PMinSize according to ICCCM 4.1.2.3 - // The other way around PMinSize is not a complete fallback for PBaseSize, - // so that's not handled here. - if( ! ( xSizeHint.flags & PMinSize )) - { - xSizeHint.min_width = xSizeHint.base_width; - xSizeHint.min_height = xSizeHint.base_height; - } - } - else - xSizeHint.base_width = xSizeHint.base_height = 0; - if( ! ( xSizeHint.flags & PMaxSize )) - xSizeHint.max_width = xSizeHint.max_height = INT_MAX; - else - { - xSizeHint.max_width = QMAX( xSizeHint.max_width, 1 ); - xSizeHint.max_height = QMAX( xSizeHint.max_height, 1 ); - } - if( xSizeHint.flags & PResizeInc ) - { - xSizeHint.width_inc = kMax( xSizeHint.width_inc, 1 ); - xSizeHint.height_inc = kMax( xSizeHint.height_inc, 1 ); - } - else - { - xSizeHint.width_inc = 1; - xSizeHint.height_inc = 1; - } - if( xSizeHint.flags & PAspect ) - { // no dividing by zero - xSizeHint.min_aspect.y = kMax( xSizeHint.min_aspect.y, 1 ); - xSizeHint.max_aspect.y = kMax( xSizeHint.max_aspect.y, 1 ); - } - else - { - xSizeHint.min_aspect.x = 1; - xSizeHint.min_aspect.y = INT_MAX; - xSizeHint.max_aspect.x = INT_MAX; - xSizeHint.max_aspect.y = 1; - } - if( ! ( xSizeHint.flags & PWinGravity )) - xSizeHint.win_gravity = NorthWestGravity; - if( isManaged()) - { // update to match restrictions - TQSize new_size = adjustedSize(); - if( new_size != size() && !isFullScreen()) - { - TQRect orig_geometry = geometry(); - resizeWithChecks( new_size ); - if( ( !isSpecialWindow() || isToolbar()) && !isFullScreen()) - { - // try to keep the window in its xinerama screen if possible, - // if that fails at least keep it visible somewhere - TQRect area = workspace()->clientArea( MovementArea, this ); - if( area.contains( orig_geometry )) - keepInArea( area ); - area = workspace()->clientArea( WorkArea, this ); - if( area.contains( orig_geometry )) - keepInArea( area ); - } - } - } - updateAllowedActions(); // affects isResizeable() - } - -TQSize Client::minSize() const - { - return rules()->checkMinSize( TQSize( xSizeHint.min_width, xSizeHint.min_height )); - } - -TQSize Client::maxSize() const - { - return rules()->checkMaxSize( TQSize( xSizeHint.max_width, xSizeHint.max_height )); - } - -/*! - Auxiliary function to inform the client about the current window - configuration. - - */ -void Client::sendSyntheticConfigureNotify() - { - XConfigureEvent c; - c.type = ConfigureNotify; - c.send_event = True; - c.event = window(); - c.window = window(); - c.x = x() + clientPos().x(); - c.y = y() + clientPos().y(); - c.width = clientSize().width(); - c.height = clientSize().height(); - c.border_width = 0; - c.above = None; - c.override_redirect = 0; - XSendEvent( qt_xdisplay(), c.event, TRUE, StructureNotifyMask, (XEvent*)&c ); - } - -const TQPoint Client::calculateGravitation( bool invert, int gravity ) const - { - int dx, dy; - dx = dy = 0; - - if( gravity == 0 ) // default (nonsense) value for the argument - gravity = xSizeHint.win_gravity; - -// dx, dy specify how the client window moves to make space for the frame - switch (gravity) - { - case NorthWestGravity: // move down right - default: - dx = border_left; - dy = border_top; - break; - case NorthGravity: // move right - dx = 0; - dy = border_top; - break; - case NorthEastGravity: // move down left - dx = -border_right; - dy = border_top; - break; - case WestGravity: // move right - dx = border_left; - dy = 0; - break; - case CenterGravity: - break; // will be handled specially - case StaticGravity: // don't move - dx = 0; - dy = 0; - break; - case EastGravity: // move left - dx = -border_right; - dy = 0; - break; - case SouthWestGravity: // move up right - dx = border_left ; - dy = -border_bottom; - break; - case SouthGravity: // move up - dx = 0; - dy = -border_bottom; - break; - case SouthEastGravity: // move up left - dx = -border_right; - dy = -border_bottom; - break; - } - if( gravity != CenterGravity ) - { // translate from client movement to frame movement - dx -= border_left; - dy -= border_top; - } - else - { // center of the frame will be at the same position client center without frame would be - dx = - ( border_left + border_right ) / 2; - dy = - ( border_top + border_bottom ) / 2; - } - if( !invert ) - return TQPoint( x() + dx, y() + dy ); - else - return TQPoint( x() - dx, y() - dy ); - } - -void Client::configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool ) - { - if( gravity == 0 ) // default (nonsense) value for the argument - gravity = xSizeHint.win_gravity; - if( value_mask & ( CWX | CWY )) - { - TQPoint new_pos = calculateGravitation( true, gravity ); // undo gravitation - if ( value_mask & CWX ) - new_pos.setX( rx ); - if ( value_mask & CWY ) - new_pos.setY( ry ); - - // clever(?) workaround for applications like xv that want to set - // the location to the current location but miscalculate the - // frame size due to twin being a double-reparenting window - // manager - if ( new_pos.x() == x() + clientPos().x() && new_pos.y() == y() + clientPos().y() - && gravity == NorthWestGravity && !from_tool ) - { - new_pos.setX( x()); - new_pos.setY( y()); - } - - int nw = clientSize().width(); - int nh = clientSize().height(); - if ( value_mask & CWWidth ) - nw = rw; - if ( value_mask & CWHeight ) - nh = rh; - TQSize ns = sizeForClientSize( TQSize( nw, nh ) ); - new_pos = rules()->checkPosition( new_pos ); - - // TODO what to do with maximized windows? - if ( maximizeMode() != MaximizeFull - || ns != size()) - { - TQRect orig_geometry = geometry(); - GeometryUpdatesPostponer blocker( this ); - move( new_pos ); - plainResize( ns ); - setGeometry( TQRect( calculateGravitation( false, gravity ), size())); - updateFullScreenHack( TQRect( new_pos, TQSize( nw, nh ))); - TQRect area = workspace()->clientArea( WorkArea, this ); - if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen() - && area.contains( orig_geometry )) - keepInArea( area ); - - // this is part of the kicker-xinerama-hack... it should be - // safe to remove when kicker gets proper ExtendedStrut support; - // see Workspace::updateClientArea() and - // Client::adjustedClientArea() - if (hasStrut ()) - workspace() -> updateClientArea (); - } - } - - if ( value_mask & (CWWidth | CWHeight ) - && ! ( value_mask & ( CWX | CWY )) ) // pure resize - { - int nw = clientSize().width(); - int nh = clientSize().height(); - if ( value_mask & CWWidth ) - nw = rw; - if ( value_mask & CWHeight ) - nh = rh; - TQSize ns = sizeForClientSize( TQSize( nw, nh ) ); - - if( ns != size()) // don't restore if some app sets its own size again - { - TQRect orig_geometry = geometry(); - GeometryUpdatesPostponer blocker( this ); - int save_gravity = xSizeHint.win_gravity; - xSizeHint.win_gravity = gravity; - resizeWithChecks( ns ); - xSizeHint.win_gravity = save_gravity; - updateFullScreenHack( TQRect( calculateGravitation( true, xSizeHint.win_gravity ), TQSize( nw, nh ))); - if( !from_tool && ( !isSpecialWindow() || isToolbar()) && !isFullScreen()) - { - // try to keep the window in its xinerama screen if possible, - // if that fails at least keep it visible somewhere - TQRect area = workspace()->clientArea( MovementArea, this ); - if( area.contains( orig_geometry )) - keepInArea( area ); - area = workspace()->clientArea( WorkArea, this ); - if( area.contains( orig_geometry )) - keepInArea( area ); - } - } - } - // No need to send synthetic configure notify event here, either it's sent together - // with geometry change, or there's no need to send it. - // Handling of the real ConfigureRequest event forces sending it, as there it's necessary. - } - -void Client::resizeWithChecks( int w, int h, ForceGeometry_t force ) - { - if( shade_geometry_change ) - assert( false ); - else if( isShade()) - { - if( h == border_top + border_bottom ) - { - kdWarning() << "Shaded geometry passed for size:" << endl; - kdWarning() << kdBacktrace() << endl; - } - } - int newx = x(); - int newy = y(); - TQRect area = workspace()->clientArea( WorkArea, this ); - // don't allow growing larger than workarea - if( w > area.width()) - w = area.width(); - if( h > area.height()) - h = area.height(); - TQSize tmp = adjustedSize( TQSize( w, h )); // checks size constraints, including min/max size - w = tmp.width(); - h = tmp.height(); - switch( xSizeHint.win_gravity ) - { - case NorthWestGravity: // top left corner doesn't move - default: - break; - case NorthGravity: // middle of top border doesn't move - newx = ( newx + width() / 2 ) - ( w / 2 ); - break; - case NorthEastGravity: // top right corner doesn't move - newx = newx + width() - w; - break; - case WestGravity: // middle of left border doesn't move - newy = ( newy + height() / 2 ) - ( h / 2 ); - break; - case CenterGravity: // middle point doesn't move - newx = ( newx + width() / 2 ) - ( w / 2 ); - newy = ( newy + height() / 2 ) - ( h / 2 ); - break; - case StaticGravity: // top left corner of _client_ window doesn't move - // since decoration doesn't change, equal to NorthWestGravity - break; - case EastGravity: // // middle of right border doesn't move - newx = newx + width() - w; - newy = ( newy + height() / 2 ) - ( h / 2 ); - break; - case SouthWestGravity: // bottom left corner doesn't move - newy = newy + height() - h; - break; - case SouthGravity: // middle of bottom border doesn't move - newx = ( newx + width() / 2 ) - ( w / 2 ); - newy = newy + height() - h; - break; - case SouthEastGravity: // bottom right corner doesn't move - newx = newx + width() - w; - newy = newy + height() - h; - break; - } - // if it would be moved outside of workarea, keep it inside, - // see also Client::computeWorkareaDiff() - if( workarea_diff_x != INT_MIN && w <= area.width()) // was inside and can still fit - { - if( newx < area.left()) - newx = area.left(); - if( newx + w > area.right() + 1 ) - newx = area.right() + 1 - w; - assert( newx >= area.left() && newx + w <= area.right() + 1 ); // width was checked above - } - if( workarea_diff_y != INT_MIN && h <= area.height()) // was inside and can still fit - { - if( newy < area.top()) - newy = area.top(); - if( newy + h > area.bottom() + 1 ) - newy = area.bottom() + 1 - h; - assert( newy >= area.top() && newy + h <= area.bottom() + 1 ); // height was checked above - } - setGeometry( newx, newy, w, h, force ); - } - -// _NET_MOVERESIZE_WINDOW -void Client::NETMoveResizeWindow( int flags, int x, int y, int width, int height ) - { - int gravity = flags & 0xff; - int value_mask = 0; - if( flags & ( 1 << 8 )) - value_mask |= CWX; - if( flags & ( 1 << 9 )) - value_mask |= CWY; - if( flags & ( 1 << 10 )) - value_mask |= CWWidth; - if( flags & ( 1 << 11 )) - value_mask |= CWHeight; - configureRequest( value_mask, x, y, width, height, gravity, true ); - } - -/*! - Returns whether the window is moveable or has a fixed - position. - */ -bool Client::isMovable() const - { - if( !motif_may_move || isFullScreen()) - return false; - if( isSpecialWindow() && !isSplash() && !isToolbar()) // allow moving of splashscreens :) - return false; - if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() ) - return false; - if( rules()->checkPosition( invalidPoint ) != invalidPoint ) // forced position - return false; - return true; - } - -/*! - Returns whether the window is resizable or has a fixed size. - */ -bool Client::isResizable() const - { - if( !motif_may_resize || isFullScreen()) - return false; - if( isSpecialWindow() ) - return false; - if( maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows() ) - return false; - if( rules()->checkSize( TQSize()).isValid()) // forced size - return false; - - TQSize min = minSize(); - TQSize max = maxSize(); - return min.width() < max.width() || min.height() < max.height(); - } - -/* - Returns whether the window is maximizable or not - */ -bool Client::isMaximizable() const - { - if( isModalSystemNotification()) - return false; - { // isMovable() and isResizable() may be false for maximized windows - // with moving/resizing maximized windows disabled - TemporaryAssign< MaximizeMode > tmp( max_mode, MaximizeRestore ); - if( !isMovable() || !isResizable() || isToolbar()) // SELI isToolbar() ? - return false; - } - if ( maximizeMode() != MaximizeRestore ) - return TRUE; - TQSize max = maxSize(); -#if 0 - if( max.width() < 32767 || max.height() < 32767 ) // sizes are 16bit with X - return false; -#else - // apparently there are enough apps which specify some arbitrary value - // for their maximum size just for the fun of it - TQSize areasize = workspace()->clientArea( MaximizeArea, this ).size(); - if( max.width() < areasize.width() || max.height() < areasize.height()) - return false; -#endif - return true; - } - - -/*! - Reimplemented to inform the client about the new window position. - */ -void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force ) - { - // this code is also duplicated in Client::plainResize() - // Ok, the shading geometry stuff. Generally, code doesn't care about shaded geometry, - // simply because there are too many places dealing with geometry. Those places - // ignore shaded state and use normal geometry, which they usually should get - // from adjustedSize(). Such geometry comes here, and if the window is shaded, - // the geometry is used only for client_size, since that one is not used when - // shading. Then the frame geometry is adjusted for the shaded geometry. - // This gets more complicated in the case the code does only something like - // setGeometry( geometry()) - geometry() will return the shaded frame geometry. - // Such code is wrong and should be changed to handle the case when the window is shaded, - // for example using Client::clientSize(). - if( shade_geometry_change ) - ; // nothing - else if( isShade()) - { - if( h == border_top + border_bottom ) - { - kdDebug() << "Shaded geometry passed for size:" << endl; - kdDebug() << kdBacktrace() << endl; - } - else - { - client_size = TQSize( w - border_left - border_right, h - border_top - border_bottom ); - h = border_top + border_bottom; - } - } - else - { - client_size = TQSize( w - border_left - border_right, h - border_top - border_bottom ); - } - if( force == NormalGeometrySet && frame_geometry == TQRect( x, y, w, h )) - return; - frame_geometry = TQRect( x, y, w, h ); - updateWorkareaDiffs(); - if( postpone_geometry_updates != 0 ) - { - pending_geometry_update = true; - return; - } - resizeDecoration( TQSize( w, h )); - XMoveResizeWindow( qt_xdisplay(), frameId(), x, y, w, h ); -// resizeDecoration( TQSize( w, h )); - if( !isShade()) - { - TQSize cs = clientSize(); - XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(), - cs.width(), cs.height()); - XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height()); - } - updateShape(); - // SELI TODO won't this be too expensive? - updateWorkareaDiffs(); - sendSyntheticConfigureNotify(); - updateWindowRules(); - checkMaximizeGeometry(); - workspace()->checkActiveScreen( this ); - } - -void Client::plainResize( int w, int h, ForceGeometry_t force ) - { - // this code is also duplicated in Client::setGeometry(), and it's also commented there - if( shade_geometry_change ) - ; // nothing - else if( isShade()) - { - if( h == border_top + border_bottom ) - { - kdDebug() << "Shaded geometry passed for size:" << endl; - kdDebug() << kdBacktrace() << endl; - } - else - { - client_size = TQSize( w - border_left - border_right, h - border_top - border_bottom ); - h = border_top + border_bottom; - } - } - else - { - client_size = TQSize( w - border_left - border_right, h - border_top - border_bottom ); - } - if( TQSize( w, h ) != rules()->checkSize( TQSize( w, h ))) - { - kdDebug() << "forced size fail:" << TQSize( w,h ) << ":" << rules()->checkSize( TQSize( w, h )) << endl; - kdDebug() << kdBacktrace() << endl; - } - if( force == NormalGeometrySet && frame_geometry.size() == TQSize( w, h )) - return; - frame_geometry.setSize( TQSize( w, h )); - updateWorkareaDiffs(); - if( postpone_geometry_updates != 0 ) - { - pending_geometry_update = true; - return; - } - resizeDecoration( TQSize( w, h )); - XResizeWindow( qt_xdisplay(), frameId(), w, h ); -// resizeDecoration( TQSize( w, h )); - if( !isShade()) - { - TQSize cs = clientSize(); - XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(), - cs.width(), cs.height()); - XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height()); - } - updateShape(); - updateWorkareaDiffs(); - sendSyntheticConfigureNotify(); - updateWindowRules(); - checkMaximizeGeometry(); - workspace()->checkActiveScreen( this ); - } - -/*! - Reimplemented to inform the client about the new window position. - */ -void Client::move( int x, int y, ForceGeometry_t force ) - { - if( force == NormalGeometrySet && frame_geometry.topLeft() == TQPoint( x, y )) - return; - frame_geometry.moveTopLeft( TQPoint( x, y )); - updateWorkareaDiffs(); - if( postpone_geometry_updates != 0 ) - { - pending_geometry_update = true; - return; - } - XMoveWindow( qt_xdisplay(), frameId(), x, y ); - sendSyntheticConfigureNotify(); - updateWindowRules(); - checkMaximizeGeometry(); - workspace()->checkActiveScreen( this ); - } - - -void Client::postponeGeometryUpdates( bool postpone ) - { - if( postpone ) - { - if( postpone_geometry_updates == 0 ) - pending_geometry_update = false; - ++postpone_geometry_updates; - } - else - { - if( --postpone_geometry_updates == 0 ) - { - if( pending_geometry_update ) - { - if( isShade()) - setGeometry( TQRect( pos(), adjustedSize()), ForceGeometrySet ); - else - setGeometry( geometry(), ForceGeometrySet ); - pending_geometry_update = false; - } - } - } - } - -void Client::maximize( MaximizeMode m ) - { - setMaximize( m & MaximizeVertical, m & MaximizeHorizontal ); - } - -/*! - Sets the maximization according to \a vertically and \a horizontally - */ -void Client::setMaximize( bool vertically, bool horizontally ) - { // changeMaximize() flips the state, so change from set->flip - changeMaximize( - max_mode & MaximizeVertical ? !vertically : vertically, - max_mode & MaximizeHorizontal ? !horizontally : horizontally, - false ); - } - -void Client::changeMaximize( bool vertical, bool horizontal, bool adjust ) - { - if( !isMaximizable()) - return; - - MaximizeMode old_mode = max_mode; - // 'adjust == true' means to update the size only, e.g. after changing workspace size - if( !adjust ) - { - if( vertical ) - max_mode = MaximizeMode( max_mode ^ MaximizeVertical ); - if( horizontal ) - max_mode = MaximizeMode( max_mode ^ MaximizeHorizontal ); - } - - max_mode = rules()->checkMaximize( max_mode ); - if( !adjust && max_mode == old_mode ) - return; - - GeometryUpdatesPostponer blocker( this ); - - // maximing one way and unmaximizing the other way shouldn't happen - Q_ASSERT( !( vertical && horizontal ) - || ((( max_mode & MaximizeVertical ) != 0 ) == (( max_mode & MaximizeHorizontal ) != 0 ))); - - TQRect clientArea = workspace()->clientArea( MaximizeArea, this ); - - // save sizes for restoring, if maximalizing - if( !adjust && !( y() == clientArea.top() && height() == clientArea.height())) - { - geom_restore.setTop( y()); - geom_restore.setHeight( height()); - } - if( !adjust && !( x() == clientArea.left() && width() == clientArea.width())) - { - geom_restore.setLeft( x()); - geom_restore.setWidth( width()); - } - - if( !adjust ) - { - if(( vertical && !(old_mode & MaximizeVertical )) - || ( horizontal && !( old_mode & MaximizeHorizontal ))) - Notify::raise( Notify::Maximize ); - else - Notify::raise( Notify::UnMaximize ); - } - - if( decoration != NULL ) // decorations may turn off some borders when maximized - decoration->borders( border_left, border_right, border_top, border_bottom ); - - // restore partial maximizations - if ( old_mode==MaximizeFull && max_mode==MaximizeRestore ) - { - if ( maximizeModeRestore()==MaximizeVertical ) - { - max_mode = MaximizeVertical; - maxmode_restore = MaximizeRestore; - } - if ( maximizeModeRestore()==MaximizeHorizontal ) - { - max_mode = MaximizeHorizontal; - maxmode_restore = MaximizeRestore; - } - } - - switch (max_mode) - { - - case MaximizeVertical: - { - if( old_mode & MaximizeHorizontal ) // actually restoring from MaximizeFull - { - if( geom_restore.width() == 0 ) - { // needs placement - plainResize( adjustedSize(TQSize(width(), clientArea.height()), SizemodeFixedH )); - workspace()->placeSmart( this, clientArea ); - } - else - setGeometry( TQRect(TQPoint( geom_restore.x(), clientArea.top()), - adjustedSize(TQSize( geom_restore.width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet); - } - else - setGeometry( TQRect(TQPoint(x(), clientArea.top()), - adjustedSize(TQSize(width(), clientArea.height()), SizemodeFixedH )), ForceGeometrySet); - info->setState( NET::MaxVert, NET::Max ); - break; - } - - case MaximizeHorizontal: - { - if( old_mode & MaximizeVertical ) // actually restoring from MaximizeFull - { - if( geom_restore.height() == 0 ) - { // needs placement - plainResize( adjustedSize(TQSize(clientArea.width(), height()), SizemodeFixedW )); - workspace()->placeSmart( this, clientArea ); - } - else - setGeometry( TQRect( TQPoint(clientArea.left(), geom_restore.y()), - adjustedSize(TQSize(clientArea.width(), geom_restore.height()), SizemodeFixedW )), ForceGeometrySet); - } - else - setGeometry( TQRect( TQPoint(clientArea.left(), y()), - adjustedSize(TQSize(clientArea.width(), height()), SizemodeFixedW )), ForceGeometrySet); - info->setState( NET::MaxHoriz, NET::Max ); - break; - } - - case MaximizeRestore: - { - TQRect restore = geometry(); - // when only partially maximized, geom_restore may not have the other dimension remembered - if( old_mode & MaximizeVertical ) - { - restore.setTop( geom_restore.top()); - restore.setBottom( geom_restore.bottom()); - } - if( old_mode & MaximizeHorizontal ) - { - restore.setLeft( geom_restore.left()); - restore.setRight( geom_restore.right()); - } - if( !restore.isValid()) - { - TQSize s = TQSize( clientArea.width()*2/3, clientArea.height()*2/3 ); - if( geom_restore.width() > 0 ) - s.setWidth( geom_restore.width()); - if( geom_restore.height() > 0 ) - s.setHeight( geom_restore.height()); - plainResize( adjustedSize( s )); - workspace()->placeSmart( this, clientArea ); - restore = geometry(); - if( geom_restore.width() > 0 ) - restore.moveLeft( geom_restore.x()); - if( geom_restore.height() > 0 ) - restore.moveTop( geom_restore.y()); - } - setGeometry( restore, ForceGeometrySet ); - info->setState( 0, NET::Max ); - break; - } - - case MaximizeFull: - { - if( !adjust ) - { - if( old_mode & MaximizeVertical ) - maxmode_restore = MaximizeVertical; - if( old_mode & MaximizeHorizontal ) - maxmode_restore = MaximizeHorizontal; - } - TQSize adjSize = adjustedSize(clientArea.size(), SizemodeMax ); - TQRect r = TQRect(clientArea.topLeft(), adjSize); - setGeometry( r, ForceGeometrySet ); - info->setState( NET::Max, NET::Max ); - break; - } - default: - break; - } - - updateAllowedActions(); - if( decoration != NULL ) - decoration->maximizeChange(); - updateWindowRules(); - } - -void Client::resetMaximize() - { - if( max_mode == MaximizeRestore ) - return; - max_mode = MaximizeRestore; - Notify::raise( Notify::UnMaximize ); - info->setState( 0, NET::Max ); - updateAllowedActions(); - if( decoration != NULL ) - decoration->borders( border_left, border_right, border_top, border_bottom ); - if( isShade()) - setGeometry( TQRect( pos(), sizeForClientSize( clientSize())), ForceGeometrySet ); - else - setGeometry( geometry(), ForceGeometrySet ); - if( decoration != NULL ) - decoration->maximizeChange(); - } - -void Client::checkMaximizeGeometry() - { - // when adding new bail-out conditions here, checkMaximizeGeometry() needs to be called - // when after the condition is no longer true - if( isShade()) - return; - if( isMove() || isResize()) // this is because of the option to disallow moving/resizing of max-ed windows - return; - // Just in case. - static int recursion_protection = 0; - if( recursion_protection > 3 ) - { - kdWarning( 1212 ) << "Check maximize overflow - you loose!" << endl; - kdWarning( 1212 ) << kdBacktrace() << endl; - return; - } - ++recursion_protection; - TQRect max_area = workspace()->clientArea( MaximizeArea, this ); - if( geometry() == max_area ) - { - if( max_mode != MaximizeFull ) - maximize( MaximizeFull ); - } - else if( x() == max_area.left() && width() == max_area.width()) - { - if( max_mode != MaximizeHorizontal ) - maximize( MaximizeHorizontal ); - } - else if( y() == max_area.top() && height() == max_area.height()) - { - if( max_mode != MaximizeVertical ) - maximize( MaximizeVertical ); - } - else if( max_mode != MaximizeRestore ) - { - resetMaximize(); // not maximize( MaximizeRestore ), that'd change geometry - this is called from setGeometry() - } - --recursion_protection; - } - -bool Client::isFullScreenable( bool fullscreen_hack ) const - { - if( !rules()->checkFullScreen( true )) - return false; - if( fullscreen_hack ) - return isNormalWindow(); - if( rules()->checkStrictGeometry( false )) - { - // the app wouldn't fit exactly fullscreen geometry due its strict geometry requirements - TQRect fsarea = workspace()->clientArea( FullScreenArea, this ); - if( sizeForClientSize( fsarea.size(), SizemodeAny, true ) != fsarea.size()) - return false; - } - // don't check size constrains - some apps request fullscreen despite requesting fixed size - return !isSpecialWindow(); // also better disallow only weird types to go fullscreen - } - -bool Client::userCanSetFullScreen() const - { - if( fullscreen_mode == FullScreenHack ) - return false; - if( !isFullScreenable( false )) - return false; - // isMaximizable() returns false if fullscreen - TemporaryAssign< FullScreenMode > tmp( fullscreen_mode, FullScreenNone ); - return isNormalWindow() && isMaximizable(); - } - -void Client::setFullScreen( bool set, bool user ) - { - if( !isFullScreen() && !set ) - return; - if( fullscreen_mode == FullScreenHack ) - return; - if( user && !userCanSetFullScreen()) - return; - set = rules()->checkFullScreen( set ); - setShade( ShadeNone ); - bool was_fs = isFullScreen(); - if( !was_fs ) - geom_fs_restore = geometry(); - fullscreen_mode = set ? FullScreenNormal : FullScreenNone; - if( was_fs == isFullScreen()) - return; - StackingUpdatesBlocker blocker1( workspace()); - GeometryUpdatesPostponer blocker2( this ); - workspace()->updateClientLayer( this ); // active fullscreens get different layer - info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen ); - updateDecoration( false, false ); - if( isFullScreen()) - setGeometry( workspace()->clientArea( FullScreenArea, this )); - else - { - if( !geom_fs_restore.isNull()) - setGeometry( TQRect( geom_fs_restore.topLeft(), adjustedSize( geom_fs_restore.size()))); - // TODO isShaded() ? - else - { // does this ever happen? - setGeometry( workspace()->clientArea( MaximizeArea, this )); - } - } - updateWindowRules(); - } - -int Client::checkFullScreenHack( const TQRect& geom ) const - { - // if it's noborder window, and has size of one screen or the whole desktop geometry, it's fullscreen hack - if( noBorder() && !isUserNoBorder() && isFullScreenable( true )) - { - if( geom.size() == workspace()->clientArea( FullArea, geom.center(), desktop()).size()) - return 2; // full area fullscreen hack - if( geom.size() == workspace()->clientArea( ScreenArea, geom.center(), desktop()).size()) - return 1; // xinerama-aware fullscreen hack - } - return 0; - } - -void Client::updateFullScreenHack( const TQRect& geom ) - { - int type = checkFullScreenHack( geom ); - if( fullscreen_mode == FullScreenNone && type != 0 ) - { - fullscreen_mode = FullScreenHack; - updateDecoration( false, false ); - TQRect geom; - if( rules()->checkStrictGeometry( false )) - { - geom = type == 2 // 1 - it's xinerama-aware fullscreen hack, 2 - it's full area - ? workspace()->clientArea( FullArea, geom.center(), desktop()) - : workspace()->clientArea( ScreenArea, geom.center(), desktop()); - } - else - geom = workspace()->clientArea( FullScreenArea, geom.center(), desktop()); - setGeometry( geom ); - } - else if( fullscreen_mode == FullScreenHack && type == 0 ) - { - fullscreen_mode = FullScreenNone; - updateDecoration( false, false ); - // whoever called this must setup correct geometry - } - StackingUpdatesBlocker blocker( workspace()); - workspace()->updateClientLayer( this ); // active fullscreens get different layer - } - -static TQRect* visible_bound = 0; -static GeometryTip* geometryTip = 0; - -void Client::drawbound( const TQRect& geom ) - { - assert( visible_bound == NULL ); - visible_bound = new TQRect( geom ); - doDrawbound( *visible_bound, false ); - } - -void Client::clearbound() - { - if( visible_bound == NULL ) - return; - doDrawbound( *visible_bound, true ); - delete visible_bound; - visible_bound = 0; - } - -void Client::doDrawbound( const TQRect& geom, bool clear ) - { - if( decoration != NULL && decoration->drawbound( geom, clear )) - return; // done by decoration - TQPainter p ( workspace()->desktopWidget() ); - p.setPen( TQPen( Qt::white, 5 ) ); - p.setRasterOp( TQt::XorROP ); - // the line is 5 pixel thick, so compensate for the extra two pixels - // on outside (#88657) - TQRect g = geom; - if( g.width() > 5 ) - { - g.setLeft( g.left() + 2 ); - g.setRight( g.right() - 2 ); - } - if( g.height() > 5 ) - { - g.setTop( g.top() + 2 ); - g.setBottom( g.bottom() - 2 ); - } - p.drawRect( g ); - } - -void Client::positionGeometryTip() - { - assert( isMove() || isResize()); - // Position and Size display - if (options->showGeometryTip()) - { - if( !geometryTip ) - { // save under is not necessary with opaque, and seem to make things slower - bool save_under = ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque ) - || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ); - geometryTip = new GeometryTip( &xSizeHint, save_under ); - } - TQRect wgeom( moveResizeGeom ); // position of the frame, size of the window itself - wgeom.setWidth( wgeom.width() - ( width() - clientSize().width())); - wgeom.setHeight( wgeom.height() - ( height() - clientSize().height())); - if( isShade()) - wgeom.setHeight( 0 ); - geometryTip->setGeometry( wgeom ); - if( !geometryTip->isVisible()) - { - geometryTip->show(); - geometryTip->raise(); - } - } - } - -class EatAllPaintEvents - : public QObject - { - protected: - virtual bool eventFilter( TQObject* o, TQEvent* e ) - { return e->type() == TQEvent::Paint && TQT_BASE_OBJECT(o) != TQT_BASE_OBJECT(geometryTip); } - }; - -static EatAllPaintEvents* eater = 0; - -bool Client::startMoveResize() - { - assert( !moveResizeMode ); - assert( TQWidget::keyboardGrabber() == NULL ); - assert( TQWidget::mouseGrabber() == NULL ); - if( TQApplication::activePopupWidget() != NULL ) - return false; // popups have grab - bool has_grab = false; - // This reportedly improves smoothness of the moveresize operation, - // something with Enter/LeaveNotify events, looks like XFree performance problem or something *shrug* - // (http://lists.kde.org/?t=107302193400001&r=1&w=2) - XSetWindowAttributes attrs; - TQRect r = workspace()->clientArea( FullArea, this ); - move_resize_grab_window = XCreateWindow( qt_xdisplay(), workspace()->rootWin(), r.x(), r.y(), - r.width(), r.height(), 0, CopyFromParent, InputOnly, CopyFromParent, 0, &attrs ); - XMapRaised( qt_xdisplay(), move_resize_grab_window ); - if( XGrabPointer( qt_xdisplay(), move_resize_grab_window, False, - ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, - GrabModeAsync, GrabModeAsync, move_resize_grab_window, cursor.handle(), GET_QT_X_TIME() ) == Success ) - has_grab = true; - if( XGrabKeyboard( qt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, GET_QT_X_TIME() ) == Success ) - has_grab = true; - if( !has_grab ) // at least one grab is necessary in order to be able to finish move/resize - { - XDestroyWindow( qt_xdisplay(), move_resize_grab_window ); - move_resize_grab_window = None; - return false; - } - if ( maximizeMode() != MaximizeRestore ) - resetMaximize(); - removeShadow(); - moveResizeMode = true; - workspace()->setClientIsMoving(this); - initialMoveResizeGeom = moveResizeGeom = geometry(); - checkUnrestrictedMoveResize(); - // rule out non opaque windows from useless translucency settings, maybe resizes? - if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove)) - setShadowSize(0); - if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){ - savedOpacity_ = opacity_; - setOpacity(options->translucentMovingWindows, options->movingWindowOpacity); - } - if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque ) - || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) ) - { - grabXServer(); - kapp->sendPostedEvents(); - // we have server grab -> nothing should cause paint events - // unfortunately, that's not completely true, Qt may generate - // paint events on some widgets due to FocusIn(?) - // eat them, otherwise XOR painting will be broken (#58054) - // paint events for the geometrytip need to be allowed, though - eater = new EatAllPaintEvents; -// not needed anymore? kapp->installEventFilter( eater ); - } - Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart ); - return true; - } - -void Client::finishMoveResize( bool cancel ) - { - leaveMoveResize(); - if( cancel ) - setGeometry( initialMoveResizeGeom ); - else - setGeometry( moveResizeGeom ); - checkMaximizeGeometry(); -// FRAME update(); - Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd ); - } - -void Client::leaveMoveResize() - { - // rule out non opaque windows from useless translucency settings, maybe resizes? - if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque) - setOpacity(true, savedOpacity_); - if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove)) - updateShadowSize(); - clearbound(); - if (geometryTip) - { - geometryTip->hide(); - delete geometryTip; - geometryTip = NULL; - } - if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque ) - || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) ) - ungrabXServer(); - XUngrabKeyboard( qt_xdisplay(), GET_QT_X_TIME() ); - XUngrabPointer( qt_xdisplay(), GET_QT_X_TIME() ); - XDestroyWindow( qt_xdisplay(), move_resize_grab_window ); - move_resize_grab_window = None; - workspace()->setClientIsMoving(0); - if( move_faked_activity ) - workspace()->unfakeActivity( this ); - move_faked_activity = false; - moveResizeMode = false; - delete eater; - eater = 0; - if (options->shadowEnabled(isActive())) - { - drawIntersectingShadows(); - updateOpacityCache(); - } - } - -// This function checks if it actually makes sense to perform a restricted move/resize. -// If e.g. the titlebar is already outside of the workarea, there's no point in performing -// a restricted move resize, because then e.g. resize would also move the window (#74555). -// NOTE: Most of it is duplicated from handleMoveResize(). -void Client::checkUnrestrictedMoveResize() - { - if( unrestrictedMoveResize ) - return; - TQRect desktopArea = workspace()->clientArea( WorkArea, moveResizeGeom.center(), desktop()); - int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge; - // restricted move/resize - keep at least part of the titlebar always visible - // how much must remain visible when moved away in that direction - left_marge = KMIN( 100 + border_right, moveResizeGeom.width()); - right_marge = KMIN( 100 + border_left, moveResizeGeom.width()); - // width/height change with opaque resizing, use the initial ones - titlebar_marge = initialMoveResizeGeom.height(); - top_marge = border_bottom; - bottom_marge = border_top; - if( isResize()) - { - if( moveResizeGeom.bottom() < desktopArea.top() + top_marge ) - unrestrictedMoveResize = true; - if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge ) - unrestrictedMoveResize = true; - if( moveResizeGeom.right() < desktopArea.left() + left_marge ) - unrestrictedMoveResize = true; - if( moveResizeGeom.left() > desktopArea.right() - right_marge ) - unrestrictedMoveResize = true; - if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() ) // titlebar mustn't go out - unrestrictedMoveResize = true; - } - if( isMove()) - { - if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 ) // titlebar mustn't go out - unrestrictedMoveResize = true; - // no need to check top_marge, titlebar_marge already handles it - if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge ) - unrestrictedMoveResize = true; - if( moveResizeGeom.right() < desktopArea.left() + left_marge ) - unrestrictedMoveResize = true; - if( moveResizeGeom.left() > desktopArea.right() - right_marge ) - unrestrictedMoveResize = true; - } - } - -void Client::handleMoveResize( int x, int y, int x_root, int y_root ) - { - if(( mode == PositionCenter && !isMovable()) - || ( mode != PositionCenter && ( isShade() || !isResizable()))) - return; - - if ( !moveResizeMode ) - { - TQPoint p( TQPoint( x, y ) - moveOffset ); - if (p.manhattanLength() >= 6) - { - if( !startMoveResize()) - { - buttonDown = false; - setCursor( mode ); - return; - } - } - else - return; - } - - // ShadeHover or ShadeActive, ShadeNormal was already avoided above - if ( mode != PositionCenter && shade_mode != ShadeNone ) - setShade( ShadeNone ); - - TQPoint globalPos( x_root, y_root ); - // these two points limit the geometry rectangle, i.e. if bottomleft resizing is done, - // the bottomleft corner should be at is at (topleft.x(), bottomright().y()) - TQPoint topleft = globalPos - moveOffset; - TQPoint bottomright = globalPos + invertedMoveOffset; - TQRect previousMoveResizeGeom = moveResizeGeom; - - // TODO move whole group when moving its leader or when the leader is not mapped? - - // compute bounds - // NOTE: This is duped in checkUnrestrictedMoveResize(). - TQRect desktopArea = workspace()->clientArea( WorkArea, globalPos, desktop()); - int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge; - if( unrestrictedMoveResize ) // unrestricted, just don't let it go out completely - left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5; - else // restricted move/resize - keep at least part of the titlebar always visible - { - // how much must remain visible when moved away in that direction - left_marge = KMIN( 100 + border_right, moveResizeGeom.width()); - right_marge = KMIN( 100 + border_left, moveResizeGeom.width()); - // width/height change with opaque resizing, use the initial ones - titlebar_marge = initialMoveResizeGeom.height(); - top_marge = border_bottom; - bottom_marge = border_top; - } - - bool update = false; - if( isResize()) - { - // first resize (without checking constraints), then snap, then check bounds, then check constraints - TQRect orig = initialMoveResizeGeom; - Sizemode sizemode = SizemodeAny; - switch ( mode ) - { - case PositionTopLeft: - moveResizeGeom = TQRect( topleft, orig.bottomRight() ) ; - break; - case PositionBottomRight: - moveResizeGeom = TQRect( orig.topLeft(), bottomright ) ; - break; - case PositionBottomLeft: - moveResizeGeom = TQRect( TQPoint( topleft.x(), orig.y() ), TQPoint( orig.right(), bottomright.y()) ) ; - break; - case PositionTopRight: - moveResizeGeom = TQRect( TQPoint( orig.x(), topleft.y() ), TQPoint( bottomright.x(), orig.bottom()) ) ; - break; - case PositionTop: - moveResizeGeom = TQRect( TQPoint( orig.left(), topleft.y() ), orig.bottomRight() ) ; - sizemode = SizemodeFixedH; // try not to affect height - break; - case PositionBottom: - moveResizeGeom = TQRect( orig.topLeft(), TQPoint( orig.right(), bottomright.y() ) ) ; - sizemode = SizemodeFixedH; - break; - case PositionLeft: - moveResizeGeom = TQRect( TQPoint( topleft.x(), orig.top() ), orig.bottomRight() ) ; - sizemode = SizemodeFixedW; - break; - case PositionRight: - moveResizeGeom = TQRect( orig.topLeft(), TQPoint( bottomright.x(), orig.bottom() ) ) ; - sizemode = SizemodeFixedW; - break; - case PositionCenter: - default: - assert( false ); - break; - } - - // adjust new size to snap to other windows/borders - moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode ); - - // NOTE: This is duped in checkUnrestrictedMoveResize(). - if( moveResizeGeom.bottom() < desktopArea.top() + top_marge ) - moveResizeGeom.setBottom( desktopArea.top() + top_marge ); - if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge ) - moveResizeGeom.setTop( desktopArea.bottom() - bottom_marge ); - if( moveResizeGeom.right() < desktopArea.left() + left_marge ) - moveResizeGeom.setRight( desktopArea.left() + left_marge ); - if( moveResizeGeom.left() > desktopArea.right() - right_marge ) - moveResizeGeom.setLeft(desktopArea.right() - right_marge ); - if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() ) // titlebar mustn't go out - moveResizeGeom.setTop( desktopArea.top()); - - TQSize size = adjustedSize( moveResizeGeom.size(), sizemode ); - // the new topleft and bottomright corners (after checking size constrains), if they'll be needed - topleft = TQPoint( moveResizeGeom.right() - size.width() + 1, moveResizeGeom.bottom() - size.height() + 1 ); - bottomright = TQPoint( moveResizeGeom.left() + size.width() - 1, moveResizeGeom.top() + size.height() - 1 ); - orig = moveResizeGeom; - switch ( mode ) - { // these 4 corners ones are copied from above - case PositionTopLeft: - moveResizeGeom = TQRect( topleft, orig.bottomRight() ) ; - break; - case PositionBottomRight: - moveResizeGeom = TQRect( orig.topLeft(), bottomright ) ; - break; - case PositionBottomLeft: - moveResizeGeom = TQRect( TQPoint( topleft.x(), orig.y() ), TQPoint( orig.right(), bottomright.y()) ) ; - break; - case PositionTopRight: - moveResizeGeom = TQRect( TQPoint( orig.x(), topleft.y() ), TQPoint( bottomright.x(), orig.bottom()) ) ; - break; - // The side ones can't be copied exactly - if aspect ratios are specified, both dimensions may change. - // Therefore grow to the right/bottom if needed. - // TODO it should probably obey gravity rather than always using right/bottom ? - case PositionTop: - moveResizeGeom = TQRect( TQPoint( orig.left(), topleft.y() ), TQPoint( bottomright.x(), orig.bottom()) ) ; - break; - case PositionBottom: - moveResizeGeom = TQRect( orig.topLeft(), TQPoint( bottomright.x(), bottomright.y() ) ) ; - break; - case PositionLeft: - moveResizeGeom = TQRect( TQPoint( topleft.x(), orig.top() ), TQPoint( orig.right(), bottomright.y())); - break; - case PositionRight: - moveResizeGeom = TQRect( orig.topLeft(), TQPoint( bottomright.x(), bottomright.y() ) ) ; - break; - case PositionCenter: - default: - assert( false ); - break; - } - if( moveResizeGeom.size() != previousMoveResizeGeom.size()) - update = true; - } - else if( isMove()) - { - assert( mode == PositionCenter ); - // first move, then snap, then check bounds - moveResizeGeom.moveTopLeft( topleft ); - moveResizeGeom.moveTopLeft( workspace()->adjustClientPosition( this, moveResizeGeom.topLeft() ) ); - // NOTE: This is duped in checkUnrestrictedMoveResize(). - if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 ) // titlebar mustn't go out - moveResizeGeom.moveBottom( desktopArea.top() + titlebar_marge - 1 ); - // no need to check top_marge, titlebar_marge already handles it - if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge ) - moveResizeGeom.moveTop( desktopArea.bottom() - bottom_marge ); - if( moveResizeGeom.right() < desktopArea.left() + left_marge ) - moveResizeGeom.moveRight( desktopArea.left() + left_marge ); - if( moveResizeGeom.left() > desktopArea.right() - right_marge ) - moveResizeGeom.moveLeft(desktopArea.right() - right_marge ); - if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft()) - update = true; - } - else - assert( false ); - - if( update ) - { - if( rules()->checkMoveResizeMode - ( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque ) - { - setGeometry( moveResizeGeom ); - positionGeometryTip(); - } - else if( rules()->checkMoveResizeMode - ( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent ) - { - clearbound(); // it's necessary to move the geometry tip when there's no outline - positionGeometryTip(); // shown, otherwise it would cause tqrepaint problems in case - drawbound( moveResizeGeom ); // they overlap; the paint event will come after this, - } // so the geometry tip will be painted above the outline - } - if ( isMove() ) - workspace()->clientMoved(globalPos, GET_QT_X_TIME()); - } - - -} // namespace |