summaryrefslogtreecommitdiffstats
path: root/kwin/geometry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kwin/geometry.cpp')
-rw-r--r--kwin/geometry.cpp2649
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