summaryrefslogtreecommitdiffstats
path: root/kwin/client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kwin/client.cpp')
-rw-r--r--kwin/client.cpp2845
1 files changed, 0 insertions, 2845 deletions
diff --git a/kwin/client.cpp b/kwin/client.cpp
deleted file mode 100644
index fbd2d75aa..000000000
--- a/kwin/client.cpp
+++ /dev/null
@@ -1,2845 +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.
-******************************************************************/
-
-#include "client.h"
-
-#include <math.h>
-
-#include <tqapplication.h>
-#include <tqpainter.h>
-#include <tqdatetime.h>
-#include <tqimage.h>
-#include <kprocess.h>
-#include <unistd.h>
-#include <kstandarddirs.h>
-#include <tqwhatsthis.h>
-#include <twin.h>
-#include <kiconloader.h>
-#include <stdlib.h>
-
-#include "bridge.h"
-#include "group.h"
-#include "workspace.h"
-#include "atoms.h"
-#include "notifications.h"
-#include "rules.h"
-
-#include <X11/extensions/shape.h>
-
-// put all externs before the namespace statement to allow the linker
-// to resolve them properly
-
-extern Atom qt_wm_state;
-extern Atom qt_window_role;
-extern Atom qt_sm_client_id;
-
-// wait 200 ms before drawing shadow after move/resize
-static const int SHADOW_DELAY = 200;
-
-namespace KWinInternal
-{
-
-/* TODO: Remove this once X has real translucency.
- *
- * A list of the regions covered by all shadows and the Clients to which they
- * belong. Used to redraw shadows when a window overlapping or underlying a
- * shadow is moved, resized, or hidden.
- */
-struct ShadowRegion
- {
- TQRegion region;
- Client *client;
- };
-static TQValueList<ShadowRegion> shadowRegions;
-
-/*
-
- Creating a client:
- - only by calling Workspace::createClient()
- - it creates a new client and calls manage() for it
-
- Destroying a client:
- - destroyClient() - only when the window itself has been destroyed
- - releaseWindow() - the window is kept, only the client itself is destroyed
-
-*/
-
-
-/*!
- \class Client client.h
-
- \brief The Client class encapsulates a window decoration frame.
-
-*/
-
-/*!
- This ctor is "dumb" - it only initializes data. All the real initialization
- is done in manage().
- */
-Client::Client( Workspace *ws )
- : TQObject( NULL ),
- client( None ),
- wrapper( None ),
- frame( None ),
- decoration( NULL ),
- wspace( ws ),
- bridge( new Bridge( this )),
- move_faked_activity( false ),
- move_resize_grab_window( None ),
- transient_for( NULL ),
- transient_for_id( None ),
- original_transient_for_id( None ),
- in_group( NULL ),
- window_group( None ),
- in_layer( UnknownLayer ),
- ping_timer( NULL ),
- process_killer( NULL ),
- user_time( CurrentTime ), // not known yet
- allowed_actions( 0 ),
- postpone_geometry_updates( 0 ),
- pending_geometry_update( false ),
- shade_geometry_change( false ),
- border_left( 0 ),
- border_right( 0 ),
- border_top( 0 ),
- border_bottom( 0 ),
- opacity_( 0 ),
- demandAttentionKNotifyTimer( NULL )
-// SELI do all as initialization
- {
- autoRaiseTimer = 0;
- shadeHoverTimer = 0;
-
- shadowDelayTimer = new TQTimer(this);
- opacityCache = &activeOpacityCache;
- shadowAfterClient = NULL;
- shadowWidget = NULL;
- shadowMe = true;
- connect(shadowDelayTimer, TQT_SIGNAL(timeout()), TQT_SLOT(drawShadow()));
-
- // set the initial mapping state
- mapping_state = WithdrawnState;
- desk = 0; // no desktop yet
-
- mode = PositionCenter;
- buttonDown = FALSE;
- moveResizeMode = FALSE;
-
- info = NULL;
-
- shade_mode = ShadeNone;
- active = FALSE;
- deleting = false;
- keep_above = FALSE;
- keep_below = FALSE;
- is_tqshape = FALSE;
- motif_noborder = false;
- motif_may_move = TRUE;
- motif_may_resize = TRUE;
- motif_may_close = TRUE;
- fullscreen_mode = FullScreenNone;
- skip_taskbar = FALSE;
- original_skip_taskbar = false;
- minimized = false;
- hidden = false;
- modal = false;
- noborder = false;
- user_noborder = false;
- urgency = false;
- ignore_focus_stealing = false;
- demands_attention = false;
- check_active_modal = false;
-
- Pdeletewindow = 0;
- Ptakefocus = 0;
- Ptakeactivity = 0;
- Pcontexthelp = 0;
- Pping = 0;
- input = FALSE;
- skip_pager = FALSE;
-
- max_mode = MaximizeRestore;
- maxmode_restore = MaximizeRestore;
-
- cmap = None;
-
- frame_geometry = TQRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
- client_size = TQSize( 100, 100 );
- custom_opacity = false;
- rule_opacity_active = 0;; //translucency rules
- rule_opacity_inactive = 0; //dito.
-
- // SELI initialize xsizehints??
- }
-
-/*!
- "Dumb" destructor.
- */
-Client::~Client()
- {
- assert(!moveResizeMode);
- assert( client == None );
- assert( frame == None && wrapper == None );
- assert( decoration == NULL );
- assert( postpone_geometry_updates == 0 );
- assert( !check_active_modal );
- delete info;
- delete bridge;
- }
-
-// use destroyClient() or releaseWindow(), Client instances cannot be deleted directly
-void Client::deleteClient( Client* c, allowed_t )
- {
- delete c;
- }
-
-/*!
- Releases the window. The client has done its job and the window is still existing.
- */
-void Client::releaseWindow( bool on_shutdown )
- {
- assert( !deleting );
- deleting = true;
- workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
- StackingUpdatesBlocker blocker( workspace());
- if (!custom_opacity) setOpacity(FALSE);
- if (moveResizeMode)
- leaveMoveResize();
- removeShadow();
- drawIntersectingShadows();
- finishWindowRules();
- ++postpone_geometry_updates;
- // grab X during the release to make removing of properties, setting to withdrawn state
- // and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2)
- grabXServer();
- setMappingState( WithdrawnState );
- setModal( false ); // otherwise its mainwindow wouldn't get focus
- hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
- if( !on_shutdown )
- workspace()->clientHidden( this );
- XUnmapWindow( qt_xdisplay(), frameId()); // destroying decoration would cause ugly visual effect
- destroyDecoration();
- cleanGrouping();
- if( !on_shutdown )
- {
- workspace()->removeClient( this, Allowed );
- // only when the window is being unmapped, not when closing down KWin
- // (NETWM sections 5.5,5.7)
- info->setDesktop( 0 );
- desk = 0;
- info->setState( 0, info->state()); // reset all state flags
- }
- XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_user_creation_time);
- XDeleteProperty( qt_xdisplay(), client, atoms->net_frame_extents );
- XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_frame_strut );
- XReparentWindow( qt_xdisplay(), client, workspace()->rootWin(), x(), y());
- XRemoveFromSaveSet( qt_xdisplay(), client );
- XSelectInput( qt_xdisplay(), client, NoEventMask );
- if( on_shutdown )
- { // map the window, so it can be found after another WM is started
- XMapWindow( qt_xdisplay(), client );
- // TODO preserve minimized, shaded etc. state?
- }
- else
- {
- // Make sure it's not mapped if the app unmapped it (#65279). The app
- // may do map+unmap before we initially map the window by calling rawShow() from manage().
- XUnmapWindow( qt_xdisplay(), client );
- }
- client = None;
- XDestroyWindow( qt_xdisplay(), wrapper );
- wrapper = None;
- XDestroyWindow( qt_xdisplay(), frame );
- frame = None;
- --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
- checkNonExistentClients();
- deleteClient( this, Allowed );
- ungrabXServer();
- }
-
-// like releaseWindow(), but this one is called when the window has been already destroyed
-// (e.g. the application closed it)
-void Client::destroyClient()
- {
- assert( !deleting );
- deleting = true;
- workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
- StackingUpdatesBlocker blocker( workspace());
- if (moveResizeMode)
- leaveMoveResize();
- removeShadow();
- drawIntersectingShadows();
- finishWindowRules();
- ++postpone_geometry_updates;
- setModal( false );
- hidden = true; // so that it's not considered visible anymore
- workspace()->clientHidden( this );
- destroyDecoration();
- cleanGrouping();
- workspace()->removeClient( this, Allowed );
- client = None; // tqinvalidate
- XDestroyWindow( qt_xdisplay(), wrapper );
- wrapper = None;
- XDestroyWindow( qt_xdisplay(), frame );
- frame = None;
- --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
- checkNonExistentClients();
- deleteClient( this, Allowed );
- }
-
-void Client::updateDecoration( bool check_workspace_pos, bool force )
- {
- if( !force && (( decoration == NULL && noBorder())
- || ( decoration != NULL && !noBorder())))
- return;
- bool do_show = false;
- postponeGeometryUpdates( true );
- if( force )
- destroyDecoration();
- if( !noBorder())
- {
- setMask( TQRegion()); // reset tqshape mask
- decoration = workspace()->createDecoration( bridge );
- // TODO check decoration's minimum size?
- decoration->init();
- decoration->widget()->installEventFilter( this );
- XReparentWindow( qt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
- decoration->widget()->lower();
- decoration->borders( border_left, border_right, border_top, border_bottom );
- options->onlyDecoTranslucent ?
- setDecoHashProperty(border_top, border_right, border_bottom, border_left):
- unsetDecoHashProperty();
- int save_workarea_diff_x = workarea_diff_x;
- int save_workarea_diff_y = workarea_diff_y;
- move( calculateGravitation( false ));
- plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
- workarea_diff_x = save_workarea_diff_x;
- workarea_diff_y = save_workarea_diff_y;
- do_show = true;
- }
- else
- destroyDecoration();
- if( check_workspace_pos )
- checkWorkspacePosition();
- postponeGeometryUpdates( false );
- if( do_show )
- decoration->widget()->show();
- updateFrameExtents();
- updateOpacityCache();
- }
-
-void Client::destroyDecoration()
- {
- if( decoration != NULL )
- {
- delete decoration;
- decoration = NULL;
- TQPoint grav = calculateGravitation( true );
- border_left = border_right = border_top = border_bottom = 0;
- setMask( TQRegion()); // reset tqshape mask
- int save_workarea_diff_x = workarea_diff_x;
- int save_workarea_diff_y = workarea_diff_y;
- plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
- move( grav );
- workarea_diff_x = save_workarea_diff_x;
- workarea_diff_y = save_workarea_diff_y;
- }
- }
-
-void Client::checkBorderSizes()
- {
- if( decoration == NULL )
- return;
- int new_left, new_right, new_top, new_bottom;
- decoration->borders( new_left, new_right, new_top, new_bottom );
- if( new_left == border_left && new_right == border_right
- && new_top == border_top && new_bottom == border_bottom )
- return;
- GeometryUpdatesPostponer blocker( this );
- move( calculateGravitation( true ));
- border_left = new_left;
- border_right = new_right;
- border_top = new_top;
- border_bottom = new_bottom;
- if (border_left != new_left ||
- border_right != new_right ||
- border_top != new_top ||
- border_bottom != new_bottom)
- options->onlyDecoTranslucent ?
- setDecoHashProperty(new_top, new_right, new_bottom, new_left):
- unsetDecoHashProperty();
- move( calculateGravitation( false ));
- plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
- checkWorkspacePosition();
- }
-
-void Client::detectNoBorder()
- {
- if( Shape::hasShape( window()))
- {
- noborder = true;
- return;
- }
- switch( windowType())
- {
- case NET::Desktop :
- case NET::Dock :
- case NET::TopMenu :
- case NET::Splash :
- noborder = true;
- break;
- case NET::Unknown :
- case NET::Normal :
- case NET::Toolbar :
- case NET::Menu :
- case NET::Dialog :
- case NET::Utility :
- noborder = false;
- break;
- default:
- assert( false );
- }
- // NET::Override is some strange beast without clear definition, usually
- // just meaning "noborder", so let's treat it only as such flag, and ignore it as
- // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it)
- if( info->windowType( SUPPORTED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
- noborder = true;
- }
-
-void Client::detectShapable()
- {
- if( Shape::hasShape( window()))
- return;
- switch( windowType())
- {
- case NET::Desktop :
- case NET::Dock :
- case NET::TopMenu :
- case NET::Splash :
- break;
- case NET::Unknown :
- case NET::Normal :
- case NET::Toolbar :
- case NET::Menu :
- case NET::Dialog :
- case NET::Utility :
- setShapable(FALSE);
- break;
- default:
- assert( false );
- }
- }
-
-void Client::updateFrameExtents()
- {
- NETStrut strut;
- strut.left = border_left;
- strut.right = border_right;
- strut.top = border_top;
- strut.bottom = border_bottom;
- info->setFrameExtents( strut );
- }
-
-// Resizes the decoration, and makes sure the decoration widget gets resize event
-// even if the size hasn't changed. This is needed to make sure the decoration
-// re-layouts (e.g. when options()->moveResizeMaximizedWindows() changes,
-// the decoration may turn on/off some borders, but the actual size
-// of the decoration stays the same).
-void Client::resizeDecoration( const TQSize& s )
- {
- if( decoration == NULL )
- return;
- TQSize oldsize = decoration->widget()->size();
- decoration->resize( s );
- if( oldsize == s )
- {
- TQResizeEvent e( s, oldsize );
- TQApplication::sendEvent( decoration->widget(), &e );
- }
- if (!moveResizeMode && options->shadowEnabled(isActive()))
- {
- // If the user is manually resizing, let Client::leaveMoveResize()
- // decide when to redraw the shadow
- updateOpacityCache();
- }
- }
-
-bool Client::noBorder() const
- {
- return noborder || isFullScreen() || user_noborder || motif_noborder;
- }
-
-bool Client::userCanSetNoBorder() const
- {
- return !noborder && !isFullScreen() && !isShade();
- }
-
-bool Client::isUserNoBorder() const
- {
- return user_noborder;
- }
-
-void Client::setUserNoBorder( bool set )
- {
- if( !userCanSetNoBorder())
- return;
- set = rules()->checkNoBorder( set );
- if( user_noborder == set )
- return;
- user_noborder = set;
- updateDecoration( true, false );
- updateWindowRules();
- }
-
-bool Client::isModalSystemNotification() const
- {
- unsigned char *data = 0;
- Atom actual;
- int format, result;
- unsigned long n, left;
- result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_system_modal_notification, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
- if (result == Success && data != None && format == 32 )
- {
- return TRUE;
- }
- return FALSE;
- }
-
-void Client::updateShape()
- {
- // workaround for #19644 - tqshaped windows shouldn't have decoration
- if( tqshape() && !noBorder())
- {
- noborder = true;
- updateDecoration( true );
- }
- updateOpacityCache();
- if ( tqshape() )
- {
- XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
- clientPos().x(), clientPos().y(),
- window(), ShapeBounding, ShapeSet);
- setShapable(TRUE);
- }
- // !tqshape() mask setting is done in setMask() when the decoration
- // calls it or when the decoration is created/destroyed
-
- if( Shape::version() >= 0x11 ) // 1.1, has input tqshape support
- { // There appears to be no way to find out if a window has input
- // tqshape set or not, so always propagate the input tqshape
- // (it's the same like the bounding tqshape by default).
- // Also, build the tqshape using a helper window, not directly
- // in the frame window, because the sequence set-tqshape-to-frame,
- // remove-tqshape-of-client, add-input-tqshape-of-client has the problem
- // that after the second step there's a hole in the input tqshape
- // until the real tqshape of the client is added and that can make
- // the window lose focus (which is a problem with mouse focus policies)
- static Window helper_window = None;
- if( helper_window == None )
- helper_window = XCreateSimpleWindow( qt_xdisplay(), qt_xrootwin(),
- 0, 0, 1, 1, 0, 0, 0 );
- XResizeWindow( qt_xdisplay(), helper_window, width(), height());
- XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput, 0, 0,
- frameId(), ShapeBounding, ShapeSet );
- XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
- clientPos().x(), clientPos().y(),
- window(), ShapeBounding, ShapeSubtract );
- XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
- clientPos().x(), clientPos().y(),
- window(), ShapeInput, ShapeUnion );
- XShapeCombineShape( qt_xdisplay(), frameId(), ShapeInput, 0, 0,
- helper_window, ShapeInput, ShapeSet );
- }
- }
-
-void Client::setMask( const TQRegion& reg, int mode )
- {
- _mask = reg;
- if( reg.isNull())
- XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
- None, ShapeSet );
- else if( mode == X::Unsorted )
- XShapeCombineRegion( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
- reg.handle(), ShapeSet );
- else
- {
- TQMemArray< TQRect > rects = reg.tqrects();
- XRectangle* xrects = new XRectangle[ rects.count() ];
- for( unsigned int i = 0;
- i < rects.count();
- ++i )
- {
- xrects[ i ].x = rects[ i ].x();
- xrects[ i ].y = rects[ i ].y();
- xrects[ i ].width = rects[ i ].width();
- xrects[ i ].height = rects[ i ].height();
- }
- XShapeCombineRectangles( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
- xrects, rects.count(), ShapeSet, mode );
- delete[] xrects;
- }
- updateShape();
- }
-
-TQRegion Client::mask() const
- {
- if( _mask.isEmpty())
- return TQRegion( 0, 0, width(), height());
- return _mask;
- }
-
-void Client::setShapable(bool b)
- {
- long tmp = b?1:0;
- XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
- }
-
-void Client::hideClient( bool hide )
- {
- if( hidden == hide )
- return;
- hidden = hide;
- updateVisibility();
- }
-
-/*!
- Returns whether the window is minimizable or not
- */
-bool Client::isMinimizable() const
- {
- if( isSpecialWindow())
- return false;
- if( isModalSystemNotification())
- return false;
- if( isTransient())
- { // #66868 - let other xmms windows be minimized when the mainwindow is minimized
- bool shown_mainwindow = false;
- ClientList mainclients = mainClients();
- for( ClientList::ConstIterator it = mainclients.begin();
- it != mainclients.end();
- ++it )
- {
- if( (*it)->isShown( true ))
- shown_mainwindow = true;
- }
- if( !shown_mainwindow )
- return true;
- }
- // this is here because kicker's taskbar doesn't provide separate entries
- // for windows with an explicitly given parent
- // TODO perhaps this should be redone
- if( transientFor() != NULL )
- return false;
- if( !wantsTabFocus()) // SELI - NET::Utility? why wantsTabFocus() - skiptaskbar? ?
- return false;
- return true;
- }
-
-/*!
- Returns whether the window is kept above or not
- */
-bool Client::keepAbove() const
- {
- if( isModalSystemNotification())
- return true;
- return keep_above;
- }
-
-/*!
- Minimizes this client plus its transients
- */
-void Client::minimize( bool avoid_animation )
- {
- if ( !isMinimizable() || isMinimized())
- return;
-
- Notify::raise( Notify::Minimize );
-
- // SELI mainClients().isEmpty() ??? - and in unminimize() too
- if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
- animateMinimizeOrUnminimize( true ); // was visible or shaded
-
- minimized = true;
-
- updateVisibility();
- updateAllowedActions();
- workspace()->updateMinimizedOfTransients( this );
- updateWindowRules();
- workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
- }
-
-void Client::unminimize( bool avoid_animation )
- {
- if( !isMinimized())
- return;
-
- Notify::raise( Notify::UnMinimize );
- minimized = false;
- if( isOnCurrentDesktop() && isShown( true ))
- {
- if( mainClients().isEmpty() && !avoid_animation )
- animateMinimizeOrUnminimize( FALSE );
- }
- updateVisibility();
- updateAllowedActions();
- workspace()->updateMinimizedOfTransients( this );
- updateWindowRules();
- }
-
-extern bool blockAnimation;
-
-void Client::animateMinimizeOrUnminimize( bool minimize )
- {
- if ( blockAnimation )
- return;
- if ( !options->animateMinimize )
- return;
-
- if( decoration != NULL && decoration->animateMinimize( minimize ))
- return; // decoration did it
-
- // the function is a bit tricky since it will ensure that an
- // animation action needs always the same time regardless of the
- // performance of the machine or the X-Server.
-
- float lf,rf,tf,bf,step;
-
- int speed = options->animateMinimizeSpeed;
- if ( speed > 10 )
- speed = 10;
- if ( speed < 0 )
- speed = 0;
-
- step = 40. * (11 - speed );
-
- NETRect r = info->iconGeometry();
- TQRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
- if ( !icongeom.isValid() )
- return;
-
- TQPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
-
- TQRect before, after;
- if ( minimize )
- {
- before = TQRect( x(), y(), width(), pm.height() );
- after = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
- }
- else
- {
- before = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
- after = TQRect( x(), y(), width(), pm.height() );
- }
-
- lf = (after.left() - before.left())/step;
- rf = (after.right() - before.right())/step;
- tf = (after.top() - before.top())/step;
- bf = (after.bottom() - before.bottom())/step;
-
- grabXServer();
-
- TQRect area = before;
- TQRect area2;
- TQPixmap pm2;
-
- TQTime t;
- t.start();
- float diff;
-
- TQPainter p ( workspace()->desktopWidget() );
- bool need_to_clear = FALSE;
- TQPixmap pm3;
- do
- {
- if (area2 != area)
- {
- pm = animationPixmap( area.width() );
- pm2 = TQPixmap::grabWindow( qt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
- p.drawPixmap( area.x(), area.y(), pm );
- if ( need_to_clear )
- {
- p.drawPixmap( area2.x(), area2.y(), pm3 );
- need_to_clear = FALSE;
- }
- area2 = area;
- }
- XFlush(qt_xdisplay());
- XSync( qt_xdisplay(), FALSE );
- diff = t.elapsed();
- if (diff > step)
- diff = step;
- area.setLeft(before.left() + int(diff*lf));
- area.setRight(before.right() + int(diff*rf));
- area.setTop(before.top() + int(diff*tf));
- area.setBottom(before.bottom() + int(diff*bf));
- if (area2 != area )
- {
- if ( area2.intersects( area ) )
- p.drawPixmap( area2.x(), area2.y(), pm2 );
- else
- { // no overlap, we can clear later to avoid flicker
- pm3 = pm2;
- need_to_clear = TRUE;
- }
- }
- } while ( t.elapsed() < step);
- if (area2 == area || need_to_clear )
- p.drawPixmap( area2.x(), area2.y(), pm2 );
-
- p.end();
- ungrabXServer();
- }
-
-
-/*!
- The pixmap shown during (un)minimalization animation
- */
-TQPixmap Client::animationPixmap( int w )
- {
- TQFont font = options->font(isActive());
- TQFontMetrics fm( font );
- TQPixmap pm( w, fm.lineSpacing() );
- pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
- TQPainter p( &pm );
- p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
- p.setFont(options->font(isActive()));
- p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
- return pm;
- }
-
-
-bool Client::isShadeable() const
- {
- return !isSpecialWindow() && !noBorder();
- }
-
-void Client::setShade( ShadeMode mode )
- {
- if( !isShadeable())
- return;
- if( isModalSystemNotification())
- return;
- mode = rules()->checkShade( mode );
- if( shade_mode == mode )
- return;
- bool was_shade = isShade();
- ShadeMode was_shade_mode = shade_mode;
- shade_mode = mode;
- if( was_shade == isShade())
- {
- if( decoration != NULL ) // decoration may want to update after e.g. hover-shade changes
- decoration->shadeChange();
- return; // no real change in shaded state
- }
-
- if( shade_mode == ShadeNormal )
- {
- if ( isShown( true ) && isOnCurrentDesktop())
- Notify::raise( Notify::ShadeUp );
- }
- else if( shade_mode == ShadeNone )
- {
- if( isShown( true ) && isOnCurrentDesktop())
- Notify::raise( Notify::ShadeDown );
- }
-
- assert( decoration != NULL ); // noborder windows can't be shaded
- GeometryUpdatesPostponer blocker( this );
- // decorations may turn off some borders when shaded
- decoration->borders( border_left, border_right, border_top, border_bottom );
-
- int as = options->animateShade? 10 : 1;
-// TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere
- if ( isShade())
- { // shade_mode == ShadeNormal
- // we're about to shade, texx xcompmgr to prepare
- long _shade = 1;
- XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
- // shade
- int h = height();
- shade_geometry_change = true;
- TQSize s( sizeForClientSize( TQSize( clientSize())));
- s.setHeight( border_top + border_bottom );
- XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
- XUnmapWindow( qt_xdisplay(), wrapper );
- XUnmapWindow( qt_xdisplay(), client );
- XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
- //as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it
- //done xcompmgr workaround
-// FRAME tqrepaint( FALSE );
-// bool wasStaticContents = testWFlags( WStaticContents );
-// setWFlags( WStaticContents );
- int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
- do
- {
- h -= step;
- XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
- resizeDecoration( TQSize( s.width(), h ));
- TQApplication::syncX();
- } while ( h > s.height() + step );
-// if ( !wasStaticContents )
-// clearWFlags( WStaticContents );
- plainResize( s );
- shade_geometry_change = false;
- if( isActive())
- {
- if( was_shade_mode == ShadeHover )
- workspace()->activateNextClient( this );
- else
- workspace()->focusToNull();
- }
- // tell xcompmgr shade's done
- _shade = 2;
- XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
- }
- else
- {
- int h = height();
- shade_geometry_change = true;
- TQSize s( sizeForClientSize( clientSize()));
-// FRAME bool wasStaticContents = testWFlags( WStaticContents );
-// setWFlags( WStaticContents );
- int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
- do
- {
- h += step;
- XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
- resizeDecoration( TQSize( s.width(), h ));
- // assume a border
- // we do not have time to wait for X to send us paint events
-// FRAME tqrepaint( 0, h - step-5, width(), step+5, TRUE);
- TQApplication::syncX();
- } while ( h < s.height() - step );
-// if ( !wasStaticContents )
-// clearWFlags( WStaticContents );
- shade_geometry_change = false;
- plainResize( s );
- if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
- setActive( TRUE );
- XMapWindow( qt_xdisplay(), wrapperId());
- XMapWindow( qt_xdisplay(), window());
- XDeleteProperty (qt_xdisplay(), client, atoms->net_wm_window_shade);
- if (options->shadowEnabled(false))
- {
- for (ClientList::ConstIterator it = transients().begin();
- it != transients().end(); ++it)
- {
- (*it)->removeShadow();
- (*it)->drawDelayedShadow();
- }
- }
-
- if ( isActive() )
- workspace()->requestFocus( this );
- }
- checkMaximizeGeometry();
- info->setState( isShade() ? NET::Shaded : 0, NET::Shaded );
- info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
- updateVisibility();
- updateAllowedActions();
- workspace()->updateMinimizedOfTransients( this );
- decoration->shadeChange();
- updateWindowRules();
- }
-
-void Client::shadeHover()
- {
- setShade( ShadeHover );
- cancelShadeHover();
- }
-
-void Client::cancelShadeHover()
- {
- delete shadeHoverTimer;
- shadeHoverTimer = 0;
- }
-
-void Client::toggleShade()
- {
- // if the mode is ShadeHover or ShadeActive, cancel shade too
- setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
- }
-
-void Client::updateVisibility()
- {
- if( deleting )
- return;
- bool show = true;
- if( hidden )
- {
- setMappingState( IconicState );
- info->setState( NET::Hidden, NET::Hidden );
- setSkipTaskbar( true, false ); // also hide from taskbar
- rawHide();
- show = false;
- }
- else
- {
- setSkipTaskbar( original_skip_taskbar, false );
- }
- if( minimized )
- {
- setMappingState( IconicState );
- info->setState( NET::Hidden, NET::Hidden );
- rawHide();
- show = false;
- }
- if( show )
- info->setState( 0, NET::Hidden );
- if( !isOnCurrentDesktop())
- {
- setMappingState( IconicState );
- rawHide();
- show = false;
- }
- if( show )
- {
- bool belongs_to_desktop = false;
- for( ClientList::ConstIterator it = group()->members().begin();
- it != group()->members().end();
- ++it )
- if( (*it)->isDesktop())
- {
- belongs_to_desktop = true;
- break;
- }
- if( !belongs_to_desktop && workspace()->showingDesktop())
- workspace()->resetShowingDesktop( true );
- if( isShade())
- setMappingState( IconicState );
- else
- setMappingState( NormalState );
- rawShow();
- }
- }
-
-void Client::setShadowed(bool shadowed)
-{
- bool wasShadowed;
-
- wasShadowed = isShadowed();
- shadowMe = options->shadowEnabled(isActive()) ? shadowed : false;
-
- if (shadowMe) {
- if (!wasShadowed)
- drawShadow();
- }
- else {
- if (wasShadowed) {
- removeShadow();
-
- if (!activeOpacityCache.isNull())
- activeOpacityCache.resize(0);
- if (!inactiveOpacityCache.isNull())
- inactiveOpacityCache.resize(0);
- }
- }
-}
-
-void Client::updateOpacityCache()
-{
- if (!activeOpacityCache.isNull())
- activeOpacityCache.resize(0);
- if (!inactiveOpacityCache.isNull())
- inactiveOpacityCache.resize(0);
-
- if (!moveResizeMode) {
- // If the user is manually resizing, let Client::finishMoveResize()
- // decide when to redraw the shadow
- removeShadow();
- drawIntersectingShadows();
- if (options->shadowEnabled(isActive()))
- drawDelayedShadow();
- }
-}
-
-/*!
- Redraw shadows that were previously occluding or occluded by this window,
- to avoid visual glitches.
- */
-void Client::drawIntersectingShadows() {
- //Client *reshadowClient;
- TQRegion region;
- //TQPtrList<Client> reshadowClients;
- TQValueList<Client *> reshadowClients;
- TQValueListIterator<ShadowRegion> it;
- TQValueListIterator<Client *> it2;
-
- if (!options->shadowEnabled(false))
- // No point in redrawing overlapping/overlapped shadows if only the
- // active window has a shadow.
- return;
-
- region = tqshapeBoundingRegion;
-
- // Generate list of Clients whose shadows need to be redrawn. That is,
- // those that are currently intersecting or intersected by other windows or
- // shadows.
- for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
- if ((isOnAllDesktops() || (*it).client->isOnCurrentDesktop()) &&
- !(*it).region.intersect(region).isEmpty())
- reshadowClients.append((*it).client);
-
- // Redraw shadows for each of the Clients in the list generated above
- for (it2 = reshadowClients.begin(); it2 != reshadowClients.end();
- ++it2) {
- (*it2)->removeShadow();
- (*it2)->drawDelayedShadow();
- }
-}
-
-/*!
- Redraw shadows that are above the current window in the stacking order.
- Furthermore, redraw them in the same order as they come in the stacking order
- from bottom to top.
- */
-void Client::drawOverlappingShadows(bool waitForMe)
-{
- Client *aClient;
- TQRegion region;
- TQValueList<Client *> reshadowClients;
- ClientList stacking_order;
- ClientList::ConstIterator it;
- TQValueListIterator<ShadowRegion> it2;
- TQValueListIterator<Client *> it3;
-
- if (!options->shadowEnabled(false))
- // No point in redrawing overlapping/overlapped shadows if only the
- // active window has a shadow.
- return;
-
- region = tqshapeBoundingRegion;
-
- stacking_order = workspace()->stackingOrder();
- for (it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
- // Find the position of this window in the stacking order.
- if ((*it) == this)
- break;
- }
- ++it;
- while (it != stacking_order.end()) {
- if ((*it)->windowType() == NET::Dock) {
- // This function is only interested in windows whose shadows don't
- // have weird stacking rules.
- ++it;
- continue;
- }
-
- // Generate list of Clients whose shadows need to be redrawn. That is,
- // those that are currently overlapping or overlapped by other windows
- // or shadows. The list should be in order from bottom to top in the
- // stacking order.
- for (it2 = shadowRegions.begin(); it2 != shadowRegions.end(); ++it2) {
- if ((*it2).client == (*it)) {
- if ((isOnAllDesktops() || (*it2).client->isOnCurrentDesktop())
- && !(*it2).region.intersect(region).isEmpty())
- reshadowClients.append((*it2).client);
- }
- }
- ++it;
- }
-
- // Redraw shadows for each of the Clients in the list generated above
- for (it3 = reshadowClients.begin(); it3 != reshadowClients.end(); ++it3) {
- (*it3)->removeShadow();
- if (it3 == reshadowClients.begin()) {
- if (waitForMe)
- (*it3)->drawShadowAfter(this);
- else
- (*it3)->drawDelayedShadow();
- }
- else {
- --it3;
- aClient = (*it3);
- ++it3;
- (*it3)->drawShadowAfter(aClient);
- }
- }
-}
-
-/*!
- Draw shadow after some time has elapsed, to give recently exposed windows a
- chance to tqrepaint before a shadow gradient is drawn over them.
- */
-void Client::drawDelayedShadow()
-{
- shadowDelayTimer->stop();
- shadowDelayTimer->start(SHADOW_DELAY, true);
-}
-
-/*!
- Draw shadow immediately after the specified Client's shadow finishes drawing.
- */
-void Client::drawShadowAfter(Client *after)
-{
- shadowAfterClient = after;
- connect(after, TQT_SIGNAL(shadowDrawn()), TQT_SLOT(drawShadow()));
-}
-
-/*!
- Draw a shadow under this window and XShape the shadow accordingly.
- */
-void Client::drawShadow()
-{
- Window shadows[2];
- XRectangle *tqshapes;
- int i, count, ordering;
-
- // If we are waiting for another Client's shadow to be drawn, stop waiting now
- if (shadowAfterClient != NULL) {
- disconnect(shadowAfterClient, TQT_SIGNAL(shadowDrawn()), this, TQT_SLOT(drawShadow()));
- shadowAfterClient = NULL;
- }
-
- if (!isOnCurrentDesktop())
- return;
-
- /* Store this window's ShapeBoundingRegion even if shadows aren't drawn for
- * this type of window. Otherwise, drawIntersectingShadows() won't update
- * properly when this window is moved/resized/hidden/closed.
- */
- tqshapes = XShapeGetRectangles(qt_xdisplay(), frameId(), ShapeBounding,
- &count, &ordering);
- if (!tqshapes)
- // XShape extension not supported
- tqshapeBoundingRegion = TQRegion(x(), y(), width(), height());
- else {
- tqshapeBoundingRegion = TQRegion();
- for (i = 0; i < count; i++) {
- // Translate XShaped window into a TQRegion
- TQRegion tqshapeRectangle(tqshapes[i].x, tqshapes[i].y, tqshapes[i].width,
- tqshapes[i].height);
- tqshapeBoundingRegion += tqshapeRectangle;
- }
- if (isShade())
- // Since XResize() doesn't change a window's XShape regions, ensure that
- // tqshapeBoundingRegion is not taller than the window's shaded height,
- // or the bottom shadow will appear to be missing
- tqshapeBoundingRegion &= TQRegion(0, 0, width(), height());
- tqshapeBoundingRegion.translate(x(), y());
- }
-
- if (!isShadowed() || hidden || isMinimized() ||
- maximizeMode() == MaximizeFull ||
- !options->shadowWindowType(windowType())) {
- XFree(tqshapes);
-
- // Tell whatever Clients are listening that this Client's shadow has been drawn.
- // It hasn't, but there's no sense waiting for something that won't happen.
- emit shadowDrawn();
-
- return;
- }
-
- removeShadow();
-
- TQMemArray<QRgb> pixelData;
- TQPixmap shadowPixmap;
- TQRect shadow;
- TQRegion exposedRegion;
- ShadowRegion shadowRegion;
- int thickness, xOffset, yOffset;
-
- thickness = options->shadowThickness(isActive());
- xOffset = options->shadowXOffset(isActive());
- yOffset = options->shadowYOffset(isActive());
- opacityCache = active? &activeOpacityCache : &inactiveOpacityCache;
-
- shadow.setRect(x() - thickness + xOffset, y() - thickness + yOffset,
- width() + thickness * 2, height() + thickness * 2);
- shadowPixmap.resize(shadow.size());
-
- // Create a fake drop-down shadow effect via blended Xwindows
- shadowWidget = new TQWidget(0, 0, (WFlags)(WStyle_Customize | WX11BypassWM));
- shadowWidget->setGeometry(shadow);
- XSelectInput(qt_xdisplay(), shadowWidget->winId(),
- ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
- shadowWidget->installEventFilter(this);
-
- if (!tqshapes) {
- // XShape extension not supported
- exposedRegion = getExposedRegion(tqshapeBoundingRegion, shadow.x(),
- shadow.y(), shadow.width(), shadow.height(), thickness,
- xOffset, yOffset);
- shadowRegion.region = exposedRegion;
- shadowRegion.client = this;
- shadowRegions.append(shadowRegion);
-
- if (opacityCache->isNull())
- imposeRegionShadow(shadowPixmap, tqshapeBoundingRegion,
- exposedRegion, thickness,
- options->shadowOpacity(isActive()));
- else
- imposeCachedShadow(shadowPixmap, exposedRegion);
- }
- else {
- TQMemArray<TQRect> exposedRects;
- TQMemArray<TQRect>::Iterator it, itEnd;
- XRectangle *shadowShapes;
-
- exposedRegion = getExposedRegion(tqshapeBoundingRegion, shadow.x(),
- shadow.y(), shadow.width(), shadow.height(), thickness,
- xOffset, yOffset);
- shadowRegion.region = exposedRegion;
- shadowRegion.client = this;
- shadowRegions.append(shadowRegion);
-
- // XShape the shadow
- exposedRects = exposedRegion.tqrects();
- i = 0;
- itEnd = exposedRects.end();
- shadowShapes = new XRectangle[exposedRects.count()];
- for (it = exposedRects.begin(); it != itEnd; ++it) {
- shadowShapes[i].x = (*it).x();
- shadowShapes[i].y = (*it).y();
- shadowShapes[i].width = (*it).width();
- shadowShapes[i].height = (*it).height();
- i++;
- }
- XShapeCombineRectangles(qt_xdisplay(), shadowWidget->winId(),
- ShapeBounding, -x() + thickness - xOffset,
- -y() + thickness - yOffset, shadowShapes, i, ShapeSet,
- Unsorted);
- delete [] shadowShapes;
-
- if (opacityCache->isNull())
- imposeRegionShadow(shadowPixmap, tqshapeBoundingRegion,
- exposedRegion, thickness,
- options->shadowOpacity(isActive()));
- else
- imposeCachedShadow(shadowPixmap, exposedRegion);
- }
-
- XFree(tqshapes);
-
- // Set the background pixmap
- //shadowPixmap.convertFromImage(shadowImage);
- shadowWidget->setErasePixmap(shadowPixmap);
-
- // Restack shadows under this window so that shadows drawn for a newly
- // focused (but not raised) window don't overlap any windows above it.
- if (isDock()) {
- ClientList stacking_order = workspace()->stackingOrder();
- for (ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
- if ((*it)->isDesktop())
- {
- ++it;
- shadows[0] = (*it)->frameId();
- shadows[1] = shadowWidget->winId();
- }
- }
- else {
- shadows[0] = frameId();
- if (shadowWidget != NULL)
- shadows[1] = shadowWidget->winId();
- }
-
- XRestackWindows(qt_xdisplay(), shadows, 2);
-
- // Don't use TQWidget::show() so we don't confuse QEffects, thus causing
- // broken focus.
- XMapWindow(qt_xdisplay(), shadowWidget->winId());
-
- // Tell whatever Clients are listening that this Client's shadow has been drawn.
- emit shadowDrawn();
-}
-
-/*!
- Remove shadow under this window.
- */
-void Client::removeShadow()
-{
- TQValueList<ShadowRegion>::Iterator it;
-
- shadowDelayTimer->stop();
-
- if (shadowWidget != NULL) {
- for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
- if ((*it).client == this) {
- shadowRegions.remove(it);
- break;
- }
- delete shadowWidget;
- shadowWidget = NULL;
- }
-}
-
-/*!
- Calculate regions in which the shadow will be visible given the window's
- origin, height and width and the shadow's thickness, and X- and Y-offsets.
- */
-TQRegion Client::getExposedRegion(TQRegion occludedRegion, int x, int y, int w,
- int h, int thickness, int xOffset, int yOffset)
-{
- TQRegion exposedRegion;
-
- exposedRegion = TQRegion(x, y, w, h);
- exposedRegion -= occludedRegion;
-
- if (thickness > 0) {
- // Limit exposedRegion to include only where a shadow of the specified
- // thickness will be drawn
- TQMemArray<TQRect> occludedRects;
- TQMemArray<TQRect>::Iterator it, itEnd;
- TQRegion shadowRegion;
-
- occludedRects = occludedRegion.tqrects();
- itEnd = occludedRects.end();
- for (it = occludedRects.begin(); it != itEnd; ++it) {
- // Expand each of the occluded region's tqshape rectangles to contain
- // where a shadow of the specified thickness will be drawn. Create
- // a new TQRegion that contains the expanded occluded region
- it->setTop(it->top() - thickness + yOffset);
- it->setLeft(it->left() - thickness + xOffset);
- it->setRight(it->right() + thickness + xOffset);
- it->setBottom(it->bottom() + thickness + yOffset);
- shadowRegion += TQRegion(*it);
- }
- exposedRegion -= exposedRegion - shadowRegion;
- }
-
- return exposedRegion;
-}
-
-/*!
- Draw shadow gradient around this window using cached opacity values.
- */
-void Client::imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed)
-{
- QRgb pixel;
- double opacity;
- int red, green, blue, pixelRed, pixelGreen, pixelBlue;
- int subW, subH, w, h, x, y, zeroX, zeroY;
- TQImage image;
- TQMemArray<TQRect>::Iterator it, itEnd;
- TQMemArray<TQRect> rectangles;
- TQPixmap subPixmap;
- Window rootWindow;
- int thickness, windowX, windowY, xOffset, yOffset;
-
- rectangles = exposed.tqrects();
- rootWindow = qt_xrootwin();
- thickness = options->shadowThickness(isActive());
- windowX = this->x();
- windowY = this->y();
- xOffset = options->shadowXOffset(isActive());
- yOffset = options->shadowYOffset(isActive());
- options->shadowColour(isActive()).rgb(&red, &green, &blue);
- w = pixmap.width();
- h = pixmap.height();
-
- itEnd = rectangles.end();
- for (it = rectangles.begin(); it != itEnd; ++it) {
- subW = (*it).width();
- subH = (*it).height();
- subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
- subW, subH);
- zeroX = (*it).x() - windowX + thickness - xOffset;
- zeroY = (*it).y() - windowY + thickness - yOffset;
- image = subPixmap.convertToImage();
-
- for (x = 0; x < subW; x++) {
- for (y = 0; y < subH; y++) {
- opacity = (*(opacityCache))[(zeroY + y) * w + zeroX + x];
- pixel = image.pixel(x, y);
- pixelRed = tqRed(pixel);
- pixelGreen = tqGreen(pixel);
- pixelBlue = tqBlue(pixel);
- image.setPixel(x, y,
- tqRgb((int)(pixelRed + (red - pixelRed) * opacity),
- (int)(pixelGreen + (green - pixelGreen) * opacity),
- (int)(pixelBlue + (blue - pixelBlue) * opacity)));
- }
- }
-
- subPixmap.convertFromImage(image);
- bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
- }
-}
-
-/*!
- Draw shadow around this window using calculated opacity values.
- */
-void Client::imposeRegionShadow(TQPixmap &pixmap, TQRegion occluded,
- TQRegion exposed, int thickness, double maxOpacity)
-{
- register int distance, intersectCount, i, j, x, y;
- QRgb pixel;
- double decay, factor, opacity;
- int red, green, blue, pixelRed, pixelGreen, pixelBlue;
- int halfMaxIntersects, lineIntersects, maxIntersects, maxY;
- int irBottom, irLeft, irRight, irTop, yIncrement;
- int subW, subH, w, h, zeroX, zeroY;
- TQImage image;
- TQMemArray<TQRect>::Iterator it, itEnd;
- TQMemArray<TQRect> rectangles;
- TQPixmap subPixmap;
- Window rootWindow;
- int windowX, windowY, xOffset, yOffset;
-
- rectangles = exposed.tqrects();
- rootWindow = qt_xrootwin();
- windowX = this->x();
- windowY = this->y();
- xOffset = options->shadowXOffset(isActive());
- yOffset = options->shadowYOffset(isActive());
- options->shadowColour(isActive()).rgb(&red, &green, &blue);
- maxIntersects = thickness * thickness * 4 + (thickness * 4) + 1;
- halfMaxIntersects = maxIntersects / 2;
- lineIntersects = thickness * 2 + 1;
- factor = maxIntersects / maxOpacity;
- decay = (lineIntersects / 0.0125 - factor) / pow((double)maxIntersects, 3.0);
- w = pixmap.width();
- h = pixmap.height();
- xOffset = options->shadowXOffset(isActive());
- yOffset = options->shadowYOffset(isActive());
-
- opacityCache->resize(0);
- opacityCache->resize(w * h);
- occluded.translate(-windowX + thickness, -windowY + thickness);
-
- itEnd = rectangles.end();
- for (it = rectangles.begin(); it != itEnd; ++it) {
- subW = (*it).width();
- subH = (*it).height();
- subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
- subW, subH);
- maxY = subH;
- zeroX = (*it).x() - windowX + thickness - xOffset;
- zeroY = (*it).y() - windowY + thickness - yOffset;
- image = subPixmap.convertToImage();
-
- intersectCount = 0;
- opacity = -1;
- y = 0;
- yIncrement = 1;
- for (x = 0; x < subW; x++) {
- irLeft = zeroX + x - thickness;
- irRight = zeroX + x + thickness;
-
- while (y != maxY) {
- // horizontal row about to leave the intersect region, not
- // necessarily the top row
- irTop = zeroY + y - thickness * yIncrement;
- // horizontal row that just came into the intersect region,
- // not necessarily the bottom row
- irBottom = zeroY + y + thickness * yIncrement;
-
- if (opacity == -1) {
- // If occluded pixels caused an intersect count to be
- // skipped, recount it
- intersectCount = 0;
-
- for (j = irTop; j != irBottom; j += yIncrement) {
- // irTop is not necessarily larger than irBottom and
- // yIncrement isn't necessarily positive
- for (i = irLeft; i <= irRight; i++) {
- if (occluded.contains(TQPoint(i, j)))
- intersectCount++;
- }
- }
- }
- else {
- if (intersectCount < 0)
- intersectCount = 0;
-
- for (i = irLeft; i <= irRight; i++) {
- if (occluded.contains(TQPoint(i, irBottom)))
- intersectCount++;
- }
- }
-
- distance = maxIntersects - intersectCount;
- opacity = intersectCount / (factor + pow((double)distance, 3.0) * decay);
-
- (*(opacityCache))[(zeroY + y) * w + zeroX + x] = opacity;
- pixel = image.pixel(x, y);
- pixelRed = tqRed(pixel);
- pixelGreen = tqGreen(pixel);
- pixelBlue = tqBlue(pixel);
- image.setPixel(x, y,
- tqRgb((int)(pixelRed + (red - pixelRed) * opacity),
- (int)(pixelGreen + (green - pixelGreen) * opacity),
- (int)(pixelBlue + (blue - pixelBlue) * opacity)));
-
- for (i = irLeft; i <= irRight; i++) {
- if (occluded.contains(TQPoint(i, irTop)))
- intersectCount--;
- }
-
- y += yIncrement;
- }
- y -= yIncrement;
-
- irTop += yIncrement;
- for (j = irTop; j != irBottom; j += yIncrement) {
- if (occluded.contains(TQPoint(irLeft, j)))
- intersectCount--;
- }
- irRight++;
- for (j = irTop; j != irBottom; j += yIncrement) {
- if (occluded.contains(TQPoint(irRight, j)))
- intersectCount++;
- }
-
- yIncrement *= -1;
- if (yIncrement < 0)
- // Scan Y-axis bottom-up for next X-coordinate iteration
- maxY = -1;
- else
- // Scan Y-axis top-down for next X-coordinate iteration
- maxY = subH;
- }
-
- subPixmap.convertFromImage(image);
- bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
- }
-}
-
-/*!
- Sets the client window's mapping state. Possible values are
- WithdrawnState, IconicState, NormalState.
- */
-void Client::setMappingState(int s)
- {
- assert( client != None );
- assert( !deleting || s == WithdrawnState );
- if( mapping_state == s )
- return;
- bool was_unmanaged = ( mapping_state == WithdrawnState );
- mapping_state = s;
- if( mapping_state == WithdrawnState )
- {
- XDeleteProperty( qt_xdisplay(), window(), qt_wm_state );
- return;
- }
- assert( s == NormalState || s == IconicState );
-
- unsigned long data[2];
- data[0] = (unsigned long) s;
- data[1] = (unsigned long) None;
- XChangeProperty(qt_xdisplay(), window(), qt_wm_state, qt_wm_state, 32,
- PropModeReplace, (unsigned char *)data, 2);
-
- if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry
- postponeGeometryUpdates( false );
- }
-
-/*!
- Reimplemented to map the managed window in the window wrapper.
- Proper mapping state should be set before showing the client.
- */
-void Client::rawShow()
- {
- if( decoration != NULL )
- decoration->widget()->show(); // not really necessary, but let it know the state
- XMapWindow( qt_xdisplay(), frame );
- if( !isShade())
- {
- XMapWindow( qt_xdisplay(), wrapper );
- XMapWindow( qt_xdisplay(), client );
- }
- if (options->shadowEnabled(isActive()))
- drawDelayedShadow();
- }
-
-/*!
- Reimplemented to unmap the managed window in the window wrapper.
- Also informs the workspace.
- Proper mapping state should be set before hiding the client.
-*/
-void Client::rawHide()
- {
-// Here it may look like a race condition, as some other client might try to unmap
-// the window between these two XSelectInput() calls. However, they're supposed to
-// use XWithdrawWindow(), which also sends a synthetic event to the root window,
-// which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
-// will be missed is also very minimal, so I don't think it's needed to grab the server
-// here.
- removeShadow();
- drawIntersectingShadows();
- XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
- XUnmapWindow( qt_xdisplay(), frame );
- XUnmapWindow( qt_xdisplay(), wrapper );
- XUnmapWindow( qt_xdisplay(), client );
- XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
- if( decoration != NULL )
- decoration->widget()->hide(); // not really necessary, but let it know the state
- workspace()->clientHidden( this );
- }
-
-void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
- {
- XEvent ev;
- long mask;
-
- memset(&ev, 0, sizeof(ev));
- ev.xclient.type = ClientMessage;
- ev.xclient.window = w;
- ev.xclient.message_type = a;
- ev.xclient.format = 32;
- ev.xclient.data.l[0] = protocol;
- ev.xclient.data.l[1] = GET_QT_X_TIME();
- ev.xclient.data.l[2] = data1;
- ev.xclient.data.l[3] = data2;
- ev.xclient.data.l[4] = data3;
- mask = 0L;
- if (w == qt_xrootwin())
- mask = SubstructureRedirectMask; /* magic! */
- XSendEvent(qt_xdisplay(), w, False, mask, &ev);
- }
-
-/*
- Returns whether the window may be closed (have a close button)
- */
-bool Client::isCloseable() const
- {
- if( isModalSystemNotification())
- return false;
- return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
- }
-
-/*!
- Closes the window by either sending a delete_window message or
- using XKill.
- */
-void Client::closeWindow()
- {
- if( !isCloseable())
- return;
- // Update user time, because the window may create a confirming dialog.
- updateUserTime();
- if ( Pdeletewindow )
- {
- Notify::raise( Notify::Close );
- sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
- pingWindow();
- }
- else
- {
- // client will not react on wm_delete_window. We have not choice
- // but destroy his connection to the XServer.
- killWindow();
- }
- }
-
-
-/*!
- Kills the window via XKill
- */
-void Client::killWindow()
- {
- kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
- // not sure if we need an Notify::Kill or not.. until then, use
- // Notify::Close
- Notify::raise( Notify::Close );
-
- if( isDialog())
- Notify::raise( Notify::TransDelete );
- if( isNormalWindow())
- Notify::raise( Notify::Delete );
- killProcess( false );
- // always kill this client at the server
- XKillClient(qt_xdisplay(), window() );
- destroyClient();
- }
-
-// send a ping to the window using _NET_WM_PING if possible
-// if it doesn't respond within a reasonable time, it will be
-// killed
-void Client::pingWindow()
- {
- if( !Pping )
- return; // can't ping :(
- if( options->killPingTimeout == 0 )
- return; // turned off
- if( ping_timer != NULL )
- return; // pinging already
- ping_timer = new TQTimer( this );
- connect( ping_timer, TQT_SIGNAL( timeout()), TQT_SLOT( pingTimeout()));
- ping_timer->start( options->killPingTimeout, true );
- ping_timestamp = GET_QT_X_TIME();
- workspace()->sendPingToWindow( window(), ping_timestamp );
- }
-
-void Client::gotPing( Time timestamp )
- {
- // just plain compare is not good enough because of 64bit and truncating and whatnot
- if( NET::timestampCompare( timestamp, ping_timestamp ) != 0 )
- return;
- delete ping_timer;
- ping_timer = NULL;
- if( process_killer != NULL )
- {
- process_killer->kill();
- delete process_killer;
- process_killer = NULL;
- }
- }
-
-void Client::pingTimeout()
- {
- kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
- delete ping_timer;
- ping_timer = NULL;
- killProcess( true, ping_timestamp );
- }
-
-void Client::killProcess( bool ask, Time timestamp )
- {
- if( process_killer != NULL )
- return;
- Q_ASSERT( !ask || timestamp != CurrentTime );
- TQCString machine = wmClientMachine( true );
- pid_t pid = info->pid();
- if( pid <= 0 || machine.isEmpty()) // needed properties missing
- return;
- kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
- if( !ask )
- {
- if( machine != "localhost" )
- {
- KProcess proc;
- proc << "xon" << machine << "kill" << pid;
- proc.start( KProcess::DontCare );
- }
- else
- ::kill( pid, SIGTERM );
- }
- else
- { // SELI TODO handle the window created by handler specially (on top,urgent?)
- process_killer = new KProcess( this );
- *process_killer << KStandardDirs::findExe( "twin_killer_helper" )
- << "--pid" << TQCString().setNum( pid ) << "--hostname" << machine
- << "--windowname" << caption().utf8()
- << "--applicationname" << resourceClass()
- << "--wid" << TQCString().setNum( window())
- << "--timestamp" << TQCString().setNum( timestamp );
- connect( process_killer, TQT_SIGNAL( processExited( KProcess* )),
- TQT_SLOT( processKillerExited()));
- if( !process_killer->start( KProcess::NotifyOnExit ))
- {
- delete process_killer;
- process_killer = NULL;
- return;
- }
- }
- }
-
-void Client::processKillerExited()
- {
- kdDebug( 1212 ) << "Killer exited" << endl;
- delete process_killer;
- process_killer = NULL;
- }
-
-void Client::setSkipTaskbar( bool b, bool from_outside )
- {
- int was_wants_tab_focus = wantsTabFocus();
- if( from_outside )
- {
- b = rules()->checkSkipTaskbar( b );
- original_skip_taskbar = b;
- }
- if ( b == skipTaskbar() )
- return;
- skip_taskbar = b;
- info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
- updateWindowRules();
- if( was_wants_tab_focus != wantsTabFocus())
- workspace()->updateFocusChains( this,
- isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
- }
-
-void Client::setSkipPager( bool b )
- {
- b = rules()->checkSkipPager( b );
- if ( b == skipPager() )
- return;
- skip_pager = b;
- info->setState( b?NET::SkipPager:0, NET::SkipPager );
- updateWindowRules();
- }
-
-void Client::setModal( bool m )
- { // Qt-3.2 can have even modal normal windows :(
- if( modal == m )
- return;
- modal = m;
- if( !modal )
- return;
- // changing modality for a mapped window is weird (?)
- // _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
- }
-
-void Client::setDesktop( int desktop )
- {
- if( desktop != NET::OnAllDesktops ) // do range check
- desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
- desktop = rules()->checkDesktop( desktop );
- if( desk == desktop )
- return;
- int was_desk = desk;
- desk = desktop;
- info->setDesktop( desktop );
- if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
- { // onAllDesktops changed
- if ( isShown( true ))
- Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
- workspace()->updateOnAllDesktopsOfTransients( this );
- }
- if( decoration != NULL )
- decoration->desktopChange();
- workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
- updateVisibility();
- updateWindowRules();
- }
-
-void Client::setOnAllDesktops( bool b )
- {
- if(( b && isOnAllDesktops())
- || ( !b && !isOnAllDesktops()))
- return;
- if( b )
- setDesktop( NET::OnAllDesktops );
- else
- setDesktop( workspace()->currentDesktop());
- }
-
-bool Client::isOnCurrentDesktop() const
- {
- return isOnDesktop( workspace()->currentDesktop());
- }
-
-int Client::screen() const
- {
- if( !options->xineramaEnabled )
- return 0;
- return workspace()->screenNumber( geometry().center());
- }
-
-bool Client::isOnScreen( int screen ) const
- {
- if( !options->xineramaEnabled )
- return screen == 0;
- return workspace()->screenGeometry( screen ).intersects( geometry());
- }
-
-// performs activation and/or raising of the window
-void Client::takeActivity( int flags, bool handled, allowed_t )
- {
- if( !handled || !Ptakeactivity )
- {
- if( flags & ActivityFocus )
- takeFocus( Allowed );
- if( flags & ActivityRaise )
- workspace()->raiseClient( this );
- return;
- }
-
-#ifndef NDEBUG
- static Time previous_activity_timestamp;
- static Client* previous_client;
- if( previous_activity_timestamp == GET_QT_X_TIME() && previous_client != this )
- {
- kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
- kdDebug( 1212 ) << kdBacktrace() << endl;
- }
- previous_activity_timestamp = GET_QT_X_TIME();
- previous_client = this;
-#endif
- workspace()->sendTakeActivity( this, GET_QT_X_TIME(), flags );
- }
-
-// performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
-void Client::takeFocus( allowed_t )
- {
-#ifndef NDEBUG
- static Time previous_focus_timestamp;
- static Client* previous_client;
- if( previous_focus_timestamp == GET_QT_X_TIME() && previous_client != this )
- {
- kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
- kdDebug( 1212 ) << kdBacktrace() << endl;
- }
- previous_focus_timestamp = GET_QT_X_TIME();
- previous_client = this;
-#endif
- if ( rules()->checkAcceptFocus( input ))
- {
- XSetInputFocus( qt_xdisplay(), window(), RevertToPointerRoot, GET_QT_X_TIME() );
- }
- if ( Ptakefocus )
- sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
- workspace()->setShouldGetFocus( this );
- }
-
-/*!
- Returns whether the window provides context help or not. If it does,
- you should show a help menu item or a help button like '?' and call
- contextHelp() if this is invoked.
-
- \sa contextHelp()
- */
-bool Client::providesContextHelp() const
- {
- if (isModalSystemNotification())
- return false;
- return Pcontexthelp;
- }
-
-
-/*!
- Invokes context help on the window. Only works if the window
- actually provides context help.
-
- \sa providesContextHelp()
- */
-void Client::showContextHelp()
- {
- if ( Pcontexthelp )
- {
- sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
- TQWhatsThis::enterWhatsThisMode(); // SELI?
- }
- }
-
-
-/*!
- Fetches the window's caption (WM_NAME property). It will be
- stored in the client's caption().
- */
-void Client::fetchName()
- {
- setCaption( readName());
- }
-
-TQString Client::readName() const
- {
- if ( info->name() && info->name()[ 0 ] != '\0' )
- return TQString::fromUtf8( info->name() );
- else
- return KWin::readNameProperty( window(), XA_WM_NAME );
- }
-
-KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
-
-void Client::setCaption( const TQString& s, bool force )
- {
- if ( s != cap_normal || force )
- {
- bool reset_name = force;
- for( unsigned int i = 0;
- i < s.length();
- ++i )
- if( !s[ i ].isPrint())
- s[ i ] = ' ';
- cap_normal = s;
- bool was_suffix = ( !cap_suffix.isEmpty());
- TQString machine_suffix;
- if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
- machine_suffix = " <@" + wmClientMachine( true ) + ">";
- TQString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
- cap_suffix = machine_suffix + shortcut_suffix;
- if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
- {
- int i = 2;
- do
- {
- cap_suffix = machine_suffix + " <" + TQString::number(i) + ">" + shortcut_suffix;
- i++;
- } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
- info->setVisibleName( caption().utf8() );
- reset_name = false;
- }
- if(( was_suffix && cap_suffix.isEmpty()
- || reset_name )) // if it was new window, it may have old value still set, if the window is reused
- {
- info->setVisibleName( "" ); // remove
- info->setVisibleIconName( "" ); // remove
- }
- else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
- info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
-
- if( isManaged() && decoration != NULL )
- decoration->captionChange();
- }
- }
-
-void Client::updateCaption()
- {
- setCaption( cap_normal, true );
- }
-
-void Client::fetchIconicName()
- {
- TQString s;
- if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
- s = TQString::fromUtf8( info->iconName() );
- else
- s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
- if ( s != cap_iconic )
- {
- bool was_set = !cap_iconic.isEmpty();
- cap_iconic = s;
- if( !cap_suffix.isEmpty())
- {
- if( !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
- info->setVisibleIconName( ( s + cap_suffix ).utf8() );
- else if( was_set )
- info->setVisibleIconName( "" ); //remove
- }
- }
- }
-
-/*!\reimp
- */
-TQString Client::caption( bool full ) const
- {
- return full ? cap_normal + cap_suffix : cap_normal;
- }
-
-void Client::getWMHints()
- {
- XWMHints *hints = XGetWMHints(qt_xdisplay(), window() );
- input = true;
- window_group = None;
- urgency = false;
- if ( hints )
- {
- if( hints->flags & InputHint )
- input = hints->input;
- if( hints->flags & WindowGroupHint )
- window_group = hints->window_group;
- urgency = ( hints->flags & UrgencyHint ) ? true : false; // true/false needed, it's uint bitfield
- XFree( (char*)hints );
- }
- checkGroup();
- updateUrgency();
- updateAllowedActions(); // group affects isMinimizable()
- }
-
-void Client::getMotifHints()
- {
- bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
- Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
- motif_noborder = mnoborder;
- if( !hasNETSupport()) // NETWM apps should set type and size constraints
- {
- motif_may_resize = mresize; // this should be set using minsize==maxsize, but oh well
- motif_may_move = mmove;
- }
- else
- motif_may_resize = motif_may_move = true;
- // mminimize; - ignore, bogus - e.g. shading or sending to another desktop is "minimizing" too
- // mmaximize; - ignore, bogus - maximizing is basically just resizing
- motif_may_close = mclose; // motif apps like to crash when they set this hint and WM closes them anyway
- if( isManaged())
- updateDecoration( true ); // check if noborder state has changed
- }
-
-void Client::readIcons( Window win, TQPixmap* icon, TQPixmap* miniicon )
- {
- // get the icons, allow scaling
- if( icon != NULL )
- *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
- if( miniicon != NULL )
- if( icon == NULL || !icon->isNull())
- *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
- else
- *miniicon = TQPixmap();
- }
-
-void Client::getIcons()
- {
- // first read icons from the window itself
- readIcons( window(), &icon_pix, &miniicon_pix );
- if( icon_pix.isNull())
- { // then try window group
- icon_pix = group()->icon();
- miniicon_pix = group()->miniIcon();
- }
- if( icon_pix.isNull() && isTransient())
- { // then mainclients
- ClientList mainclients = mainClients();
- for( ClientList::ConstIterator it = mainclients.begin();
- it != mainclients.end() && icon_pix.isNull();
- ++it )
- {
- icon_pix = (*it)->icon();
- miniicon_pix = (*it)->miniIcon();
- }
- }
- if( icon_pix.isNull())
- { // and if nothing else, load icon from classhint or xapp icon
- icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
- miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
- }
- if( isManaged() && decoration != NULL )
- decoration->iconChange();
- }
-
-void Client::getWindowProtocols()
- {
- Atom *p;
- int i,n;
-
- Pdeletewindow = 0;
- Ptakefocus = 0;
- Ptakeactivity = 0;
- Pcontexthelp = 0;
- Pping = 0;
-
- if (XGetWMProtocols(qt_xdisplay(), window(), &p, &n))
- {
- for (i = 0; i < n; i++)
- if (p[i] == atoms->wm_delete_window)
- Pdeletewindow = 1;
- else if (p[i] == atoms->wm_take_focus)
- Ptakefocus = 1;
- else if (p[i] == atoms->net_wm_take_activity)
- Ptakeactivity = 1;
- else if (p[i] == atoms->net_wm_context_help)
- Pcontexthelp = 1;
- else if (p[i] == atoms->net_wm_ping)
- Pping = 1;
- if (n>0)
- XFree(p);
- }
- }
-
-static int nullErrorHandler(Display *, XErrorEvent *)
- {
- return 0;
- }
-
-/*!
- Returns WM_WINDOW_ROLE property for a given window.
- */
-TQCString Client::staticWindowRole(WId w)
- {
- return getStringProperty(w, qt_window_role).lower();
- }
-
-/*!
- Returns SM_CLIENT_ID property for a given window.
- */
-TQCString Client::staticSessionId(WId w)
- {
- return getStringProperty(w, qt_sm_client_id);
- }
-
-/*!
- Returns WM_COMMAND property for a given window.
- */
-TQCString Client::staticWmCommand(WId w)
- {
- return getStringProperty(w, XA_WM_COMMAND, ' ');
- }
-
-/*!
- Returns WM_CLIENT_LEADER property for a given window.
- */
-Window Client::staticWmClientLeader(WId w)
- {
- Atom type;
- int format, status;
- unsigned long nitems = 0;
- unsigned long extra = 0;
- unsigned char *data = 0;
- Window result = w;
- XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
- status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
- FALSE, XA_WINDOW, &type, &format,
- &nitems, &extra, &data );
- XSetErrorHandler(oldHandler);
- if (status == Success )
- {
- if (data && nitems > 0)
- result = *((Window*) data);
- XFree(data);
- }
- return result;
- }
-
-
-void Client::getWmClientLeader()
- {
- wmClientLeaderWin = staticWmClientLeader(window());
- }
-
-/*!
- Returns sessionId for this client,
- taken either from its window or from the leader window.
- */
-TQCString Client::sessionId()
- {
- TQCString result = staticSessionId(window());
- if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
- result = staticSessionId(wmClientLeaderWin);
- return result;
- }
-
-/*!
- Returns command property for this client,
- taken either from its window or from the leader window.
- */
-TQCString Client::wmCommand()
- {
- TQCString result = staticWmCommand(window());
- if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
- result = staticWmCommand(wmClientLeaderWin);
- return result;
- }
-
-void Client::getWmClientMachine()
- {
- client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
- if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
- client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
- if( client_machine.isEmpty())
- client_machine = "localhost";
- }
-
-/*!
- Returns client machine for this client,
- taken either from its window or from the leader window.
-*/
-TQCString Client::wmClientMachine( bool use_localhost ) const
- {
- TQCString result = client_machine;
- if( use_localhost )
- { // special name for the local machine (localhost)
- if( result != "localhost" && isLocalMachine( result ))
- result = "localhost";
- }
- return result;
- }
-
-/*!
- Returns client leader window for this client.
- Returns the client window itself if no leader window is defined.
-*/
-Window Client::wmClientLeader() const
- {
- if (wmClientLeaderWin)
- return wmClientLeaderWin;
- return window();
- }
-
-bool Client::wantsTabFocus() const
- {
- return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
- }
-
-
-bool Client::wantsInput() const
- {
- return rules()->checkAcceptFocus( input || Ptakefocus );
- }
-
-bool Client::isDesktop() const
- {
- return windowType() == NET::Desktop;
- }
-
-bool Client::isDock() const
- {
- return windowType() == NET::Dock;
- }
-
-bool Client::isTopMenu() const
- {
- return windowType() == NET::TopMenu;
- }
-
-
-bool Client::isMenu() const
- {
- return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
- }
-
-bool Client::isToolbar() const
- {
- return windowType() == NET::Toolbar;
- }
-
-bool Client::isSplash() const
- {
- return windowType() == NET::Splash;
- }
-
-bool Client::isUtility() const
- {
- return windowType() == NET::Utility;
- }
-
-bool Client::isDialog() const
- {
- return windowType() == NET::Dialog;
- }
-
-bool Client::isNormalWindow() const
- {
- return windowType() == NET::Normal;
- }
-
-bool Client::isSpecialWindow() const
- {
- return isDesktop() || isDock() || isSplash() || isTopMenu()
- || isToolbar(); // TODO
- }
-
-NET::WindowType Client::windowType( bool direct, int supported_types ) const
- {
- NET::WindowType wt = info->windowType( supported_types );
- if( direct )
- return wt;
- NET::WindowType wt2 = rules()->checkType( wt );
- if( wt != wt2 )
- {
- wt = wt2;
- info->setWindowType( wt ); // force hint change
- }
- // hacks here
- if( wt == NET::Menu )
- {
- // ugly hack to support the times when NET::Menu meant NET::TopMenu
- // if it's as wide as the screen, not very high and has its upper-left
- // corner a bit above the screen's upper-left cornet, it's a topmenu
- if( x() == 0 && y() < 0 && y() > -10 && height() < 100
- && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
- wt = NET::TopMenu;
- }
- // TODO change this to rule
- const char* const oo_prefix = "openoffice.org"; // TQCString has no startsWith()
- // oo_prefix is lowercase, because resourceClass() is forced to be lowercase
- if( tqstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
- wt = NET::Normal; // see bug #66065
- if( wt == NET::Unknown ) // this is more or less suggested in NETWM spec
- wt = isTransient() ? NET::Dialog : NET::Normal;
- return wt;
- }
-
-/*!
- Sets an appropriate cursor tqshape for the logical mouse position \a m
-
- */
-void Client::setCursor( Position m )
- {
- if( !isResizable() || isShade())
- {
- m = PositionCenter;
- }
- switch ( m )
- {
- case PositionTopLeft:
- case PositionBottomRight:
- setCursor( tqsizeFDiagCursor );
- break;
- case PositionBottomLeft:
- case PositionTopRight:
- setCursor( tqsizeBDiagCursor );
- break;
- case PositionTop:
- case PositionBottom:
- setCursor( tqsizeVerCursor );
- break;
- case PositionLeft:
- case PositionRight:
- setCursor( tqsizeHorCursor );
- break;
- default:
- if( buttonDown && isMovable())
- setCursor( tqsizeAllCursor );
- else
- setCursor( tqarrowCursor );
- break;
- }
- }
-
-// TODO mit nejake checkCursor(), ktere se zavola v manage() a pri vecech, kdy by se kurzor mohl zmenit?
-void Client::setCursor( const TQCursor& c )
- {
- if( c.handle() == cursor.handle())
- return;
- cursor = c;
- if( decoration != NULL )
- decoration->widget()->setCursor( cursor );
- XDefineCursor( qt_xdisplay(), frameId(), cursor.handle());
- }
-
-Client::Position Client::mousePosition( const TQPoint& p ) const
- {
- if( decoration != NULL )
- return decoration->mousePosition( p );
- return PositionCenter;
- }
-
-void Client::updateAllowedActions( bool force )
- {
- if( !isManaged() && !force )
- return;
- unsigned long old_allowed_actions = allowed_actions;
- allowed_actions = 0;
- if( isMovable())
- allowed_actions |= NET::ActionMove;
- if( isResizable())
- allowed_actions |= NET::ActionResize;
- if( isMinimizable())
- allowed_actions |= NET::ActionMinimize;
- if( isShadeable())
- allowed_actions |= NET::ActionShade;
- // sticky state not supported
- if( isMaximizable())
- allowed_actions |= NET::ActionMax;
- if( userCanSetFullScreen())
- allowed_actions |= NET::ActionFullScreen;
- allowed_actions |= NET::ActionChangeDesktop; // always (pagers shouldn't show Docks etc.)
- if( isCloseable())
- allowed_actions |= NET::ActionClose;
- if( old_allowed_actions == allowed_actions )
- return;
- // TODO this could be delayed and compressed - it's only for pagers etc. anyway
- info->setAllowedActions( allowed_actions );
- // TODO this should also tell the decoration, so that it can update the buttons
- }
-
-void Client::autoRaise()
- {
- workspace()->raiseClient( this );
- cancelAutoRaise();
- }
-
-void Client::cancelAutoRaise()
- {
- delete autoRaiseTimer;
- autoRaiseTimer = 0;
- }
-
-void Client::setOpacity(bool translucent, uint opacity)
- {
- if (isDesktop())
- return; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling
-// qWarning("setting opacity for %d",qt_xdisplay());
- //rule out activated translulcency with 100% opacity
- if (!translucent || opacity == 0xFFFFFFFF)
- {
- opacity_ = 0xFFFFFFFF;
- XDeleteProperty (qt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
- XDeleteProperty (qt_xdisplay(), window(), atoms->net_wm_window_opacity); // ??? frameId() is necessary for visible changes, window() is the winId() that would be set by apps - we set both to be sure the app knows what's currently displayd
- }
- else{
- if(opacity == opacity_)
- return;
- opacity_ = opacity;
- long data = opacity; // 32bit XChangeProperty needs long
- XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
- XChangeProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
- }
- }
-
-void Client::setShadowSize(uint shadowSize)
- {
- // ignoring all individual settings - if we control a window, we control it's shadow
- // TODO somehow handle individual settings for docks (besides custom sizes)
- long data = shadowSize;
- XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
- }
-
-void Client::updateOpacity()
-// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
- {
- if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
- return;
- if (isActive())
- {
- if( ruleOpacityActive() )
- setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
- else
- setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
- if (isBMP())
- // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
- {
- ClientList tmpGroupMembers = group()->members();
- ClientList activeGroupMembers;
- activeGroupMembers.append(this);
- tmpGroupMembers.remove(this);
- ClientList::Iterator it = tmpGroupMembers.begin();
- while (it != tmpGroupMembers.end())
- // search for next attached and not activated client and repeat if found
- {
- if ((*it) != this && (*it)->isBMP())
- // potential "to activate" client found
- {
-// qWarning("client found");
- if ((*it)->touches(this)) // first test, if the new client touches the just activated one
- {
-// qWarning("found client touches me");
- if( ruleOpacityActive() )
- (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
- else
- (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
-// qWarning("activated, search restarted (1)");
- (*it)->setShadowSize(options->activeWindowShadowSize);
- activeGroupMembers.append(*it);
- tmpGroupMembers.remove(it);
- it = tmpGroupMembers.begin(); // restart, search next client
- continue;
- }
- else
- { // pot. client does not touch c, so we have to search if it touches some other activated client
- bool found = false;
- for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
- {
- if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
- {
-// qWarning("found client touches other active client");
- if( ruleOpacityActive() )
- (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
- else
- (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
- (*it)->setShadowSize(options->activeWindowShadowSize);
- activeGroupMembers.append(*it);
- tmpGroupMembers.remove(it);
- it = tmpGroupMembers.begin(); // reset potential client search
- found = true;
-// qWarning("activated, search restarted (2)");
- break; // skip this loop
- }
- }
- if (found) continue;
- }
- }
- it++;
- }
- }
- else if (isNormalWindow())
- // activate dependend minor windows as well
- {
- for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
- if ((*it)->isDialog() || (*it)->isUtility())
- if( (*it)->ruleOpacityActive() )
- (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
- else
- (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
- }
- }
- else
- {
- if( ruleOpacityInactive() )
- setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
- else
- setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
- options->inactiveWindowOpacity);
- // deactivate dependend minor windows as well
- if (isBMP())
- // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
- {
- ClientList tmpGroupMembers = group()->members();
- ClientList inactiveGroupMembers;
- inactiveGroupMembers.append(this);
- tmpGroupMembers.remove(this);
- ClientList::Iterator it = tmpGroupMembers.begin();
- while ( it != tmpGroupMembers.end() )
- // search for next attached and not activated client and repeat if found
- {
- if ((*it) != this && (*it)->isBMP())
- // potential "to activate" client found
- {
-// qWarning("client found");
- if ((*it)->touches(this)) // first test, if the new client touches the just activated one
- {
-// qWarning("found client touches me");
- if( (*it)->ruleOpacityInactive() )
- (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
- else
- (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
- (*it)->setShadowSize(options->inactiveWindowShadowSize);
-// qWarning("deactivated, search restarted (1)");
- inactiveGroupMembers.append(*it);
- tmpGroupMembers.remove(it);
- it = tmpGroupMembers.begin(); // restart, search next client
- continue;
- }
- else // pot. client does not touch c, so we have to search if it touches some other activated client
- {
- bool found = false;
- for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
- {
- if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
- {
-// qWarning("found client touches other inactive client");
- if( (*it)->ruleOpacityInactive() )
- (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
- else
- (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
- (*it)->setShadowSize(options->inactiveWindowShadowSize);
-// qWarning("deactivated, search restarted (2)");
- inactiveGroupMembers.append(*it);
- tmpGroupMembers.remove(it);
- it = tmpGroupMembers.begin(); // reset potential client search
- found = true;
- break; // skip this loop
- }
- }
- if (found) continue;
- }
- }
- it++;
- }
- }
- else if (isNormalWindow())
- {
- for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
- if ((*it)->isUtility()) //don't deactivate dialogs...
- if( (*it)->ruleOpacityInactive() )
- (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
- else
- (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
- }
- }
- }
-
-void Client::updateShadowSize()
-// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
- {
- if (!(isNormalWindow() || isDialog() || isUtility() ))
- return;
- if (isActive())
- setShadowSize(options->activeWindowShadowSize);
- else
- setShadowSize(options->inactiveWindowShadowSize);
- }
-
-uint Client::ruleOpacityInactive()
- {
- return rule_opacity_inactive;// != 0 ;
- }
-
-uint Client::ruleOpacityActive()
- {
- return rule_opacity_active;// != 0;
- }
-
-bool Client::getWindowOpacity() //query translucency settings from X, returns true if window opacity is set
- {
- unsigned char *data = 0;
- Atom actual;
- int format, result;
- unsigned long n, left;
- result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
- if (result == Success && data != None && format == 32 )
- {
- opacity_ = *reinterpret_cast< long* >( data );
- custom_opacity = true;
-// setOpacity(opacity_ < 0xFFFFFFFF, opacity_);
- XFree ((char*)data);
- return TRUE;
- }
- return FALSE;
- }
-
-void Client::setCustomOpacityFlag(bool custom)
- {
- custom_opacity = custom;
- }
-
-uint Client::opacity()
- {
- return opacity_;
- }
-
-int Client::opacityPercentage()
- {
- return int(100*((double)opacity_/0xffffffff));
- }
-
-bool Client::touches(const Client* c)
-// checks if this client borders c, needed to test beep media player window state
- {
- if (y() == c->y() + c->height()) // this bottom to c
- return TRUE;
- if (y() + height() == c->y()) // this top to c
- return TRUE;
- if (x() == c->x() + c->width()) // this right to c
- return TRUE;
- if (x() + width() == c->x()) // this left to c
- return TRUE;
- return FALSE;
- }
-
-void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
-{
- long data = (topHeight < 255 ? topHeight : 255) << 24 |
- (rightWidth < 255 ? rightWidth : 255) << 16 |
- (bottomHeight < 255 ? bottomHeight : 255) << 8 |
- (leftWidth < 255 ? leftWidth : 255);
- XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
-}
-
-void Client::unsetDecoHashProperty()
-{
- XDeleteProperty( qt_xdisplay(), frameId(), atoms->net_wm_window_decohash);
-}
-
-#ifndef NDEBUG
-kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
- {
- if( cl == NULL )
- return stream << "\'NULL_CLIENT\'";
- return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
- }
-kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
- {
- stream << "LIST:(";
- bool first = true;
- for( ClientList::ConstIterator it = list.begin();
- it != list.end();
- ++it )
- {
- if( !first )
- stream << ":";
- first = false;
- stream << *it;
- }
- stream << ")";
- return stream;
- }
-kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
- {
- stream << "LIST:(";
- bool first = true;
- for( ConstClientList::ConstIterator it = list.begin();
- it != list.end();
- ++it )
- {
- if( !first )
- stream << ":";
- first = false;
- stream << *it;
- }
- stream << ")";
- return stream;
- }
-#endif
-
-TQPixmap * twin_get_menu_pix_hack()
- {
- static TQPixmap p;
- if ( p.isNull() )
- p = SmallIcon( "bx2" );
- return &p;
- }
-
-} // namespace
-
-#include "client.moc"