diff --git a/client.cpp b/client.cpp index 1900dc3f92..ff5bc7d59f 100644 --- a/client.cpp +++ b/client.cpp @@ -145,7 +145,7 @@ Client::Client( Workspace *ws ) hidden = false; modal = false; noborder = false; - user_noborder = false; + app_noborder = false; urgency = false; ignore_focus_stealing = false; demands_attention = false; @@ -420,6 +420,7 @@ void Client::detectNoBorder() if( shape()) { noborder = true; + app_noborder = true; return; } switch( windowType()) @@ -429,6 +430,7 @@ void Client::detectNoBorder() case NET::TopMenu : case NET::Splash : noborder = true; + app_noborder = true; break; case NET::Unknown : case NET::Normal : @@ -445,7 +447,10 @@ void Client::detectNoBorder() // 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_MANAGED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override ) + { noborder = true; + app_noborder = true; + } } void Client::updateFrameExtents() @@ -478,27 +483,22 @@ void Client::resizeDecoration( const QSize& s ) bool Client::noBorder() const { - return noborder || isFullScreen() || user_noborder; + return noborder || isFullScreen(); } bool Client::userCanSetNoBorder() const { - return !noborder && !isFullScreen() && !isShade(); + return !isFullScreen() && !isShade(); } -bool Client::isUserNoBorder() const - { - return user_noborder; - } - -void Client::setUserNoBorder( bool set ) +void Client::setNoBorder( bool set ) { if( !userCanSetNoBorder()) return; set = rules()->checkNoBorder( set ); - if( user_noborder == set ) + if( noborder == set ) return; - user_noborder = set; + noborder = set; updateDecoration( true, false ); updateWindowRules(); } @@ -506,19 +506,20 @@ void Client::setUserNoBorder( bool set ) void Client::updateShape() { // workaround for #19644 - shaped windows shouldn't have decoration - if( shape() && !noBorder()) - { - noborder = true; - updateDecoration( true ); - } if( shape()) { - XShapeCombineShape(display(), frameId(), ShapeBounding, - clientPos().x(), clientPos().y(), - window(), ShapeBounding, ShapeSet); + if( !app_noborder ) // only when shape is detected for the first time, + { // still let the user to override + app_noborder = true; + noborder = true; + updateDecoration( true ); + } } - // !shape() mask setting is done in setMask() when the decoration - // calls it or when the decoration is created/destroyed + if( shape() && noBorder()) + XShapeCombineShape( display(), frameId(), ShapeBounding, + clientPos().x(), clientPos().y(), window(), ShapeBounding, ShapeSet ); + // Decoration mask (i.e. 'else' here) setting is done in setMask() + // when the decoration calls it or when the decoration is created/destroyed updateInputShape(); if( compositing()) addDamageFull(); @@ -528,6 +529,8 @@ void Client::updateShape() static_cast(effects)->windowGeometryShapeChanged( effectWindow(), geometry()); } +static Window shape_helper_window = None; + void Client::updateInputShape() { if( hidden_preview ) // sets it to none, don't change @@ -542,34 +545,43 @@ void Client::updateInputShape() // that after the second step there's a hole in the input shape // until the real shape of the client is added and that can make // the window lose focus (which is a problem with mouse focus policies) - - // TODO it seems there is, after all - XShapeGetRectangles() - static Window helper_window = None; - if( helper_window == None ) - helper_window = XCreateSimpleWindow( display(), rootWindow(), + // TODO it seems there is, after all - XShapeGetRectangles() - but maybe this is better + if( shape_helper_window == None ) + shape_helper_window = XCreateSimpleWindow( display(), rootWindow(), 0, 0, 1, 1, 0, 0, 0 ); - XResizeWindow( display(), helper_window, width(), height()); - XShapeCombineShape( display(), helper_window, ShapeInput, 0, 0, + XResizeWindow( display(), shape_helper_window, width(), height()); + XShapeCombineShape( display(), shape_helper_window, ShapeInput, 0, 0, frameId(), ShapeBounding, ShapeSet ); - XShapeCombineShape( display(), helper_window, ShapeInput, + XShapeCombineShape( display(), shape_helper_window, ShapeInput, clientPos().x(), clientPos().y(), window(), ShapeBounding, ShapeSubtract ); - XShapeCombineShape( display(), helper_window, ShapeInput, + XShapeCombineShape( display(), shape_helper_window, ShapeInput, clientPos().x(), clientPos().y(), window(), ShapeInput, ShapeUnion ); XShapeCombineShape( display(), frameId(), ShapeInput, 0, 0, - helper_window, ShapeInput, ShapeSet ); + shape_helper_window, ShapeInput, ShapeSet ); } } void Client::setMask( const QRegion& reg, int mode ) { + if( _mask == reg ) + return; _mask = reg; + Window shape_window = frameId(); + if( shape()) + { + // the same way of applying a shape without strange intermediate states like above + if( shape_helper_window == None ) + shape_helper_window = XCreateSimpleWindow( display(), rootWindow(), + 0, 0, 1, 1, 0, 0, 0 ); + shape_window = shape_helper_window; + } if( reg.isEmpty()) - XShapeCombineMask( display(), frameId(), ShapeBounding, 0, 0, + XShapeCombineMask( display(), shape_window, ShapeBounding, 0, 0, None, ShapeSet ); else if( mode == X::Unsorted ) - XShapeCombineRegion( display(), frameId(), ShapeBounding, 0, 0, + XShapeCombineRegion( display(), shape_window, ShapeBounding, 0, 0, reg.handle(), ShapeSet ); else { @@ -584,10 +596,21 @@ void Client::setMask( const QRegion& reg, int mode ) xrects[ i ].width = rects[ i ].width(); xrects[ i ].height = rects[ i ].height(); } - XShapeCombineRectangles( display(), frameId(), ShapeBounding, 0, 0, + XShapeCombineRectangles( display(), shape_window, ShapeBounding, 0, 0, xrects, rects.count(), ShapeSet, mode ); delete[] xrects; } + if( shape()) + { // the rest of the applyign using a temporary window + XRectangle rec = { 0, 0, clientSize().width(), clientSize().height() }; + XShapeCombineRectangles( display(), shape_helper_window, ShapeBounding, + clientPos().x(), clientPos().y(), &rec, 1, ShapeSubtract, Unsorted ); + XShapeCombineShape( display(), shape_helper_window, ShapeBounding, + clientPos().x(), clientPos().y(), + window(), ShapeBounding, ShapeUnion ); + XShapeCombineShape( display(), frameId(), ShapeBounding, 0, 0, + shape_helper_window, ShapeBounding, ShapeSet ); + } if( compositing()) addDamageFull(); if( scene != NULL ) @@ -1446,7 +1469,10 @@ void Client::getMotifHints() bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose; Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose ); if( mnoborder ) + { noborder = true; + app_noborder = true; + } if( !hasNETSupport()) // NETWM apps should set type and size constraints { motif_may_resize = mresize; // this should be set using minsize==maxsize, but oh well diff --git a/client.h b/client.h index 5b744eadd6..45db92af50 100644 --- a/client.h +++ b/client.h @@ -156,10 +156,9 @@ class Client QRect geometryFSRestore() const { return geom_fs_restore; } // only for session saving int fullScreenMode() const { return fullscreen_mode; } // only for session saving - bool isUserNoBorder() const; - void setUserNoBorder( bool set ); - bool userCanSetNoBorder() const; bool noBorder() const; + void setNoBorder( bool set ); + bool userCanSetNoBorder() const; bool skipTaskbar( bool from_outside = false ) const; void setSkipTaskbar( bool set, bool from_outside ); @@ -455,7 +454,7 @@ class Client uint hidden : 1; // forcibly hidden by calling hide() uint modal : 1; // NET::Modal uint noborder : 1; - uint user_noborder : 1; + uint app_noborder : 1; // the app requested no border using something (window type, motif hints) uint urgency : 1; // XWMHints, UrgencyHint uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client uint demands_attention : 1; diff --git a/geometry.cpp b/geometry.cpp index 6246f946bc..b29a7b0307 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -2199,7 +2199,7 @@ void Client::setFullScreen( bool set, bool user ) int Client::checkFullScreenHack( const QRect& 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( noBorder() && app_noborder && isFullScreenable( true )) { if( geom.size() == workspace()->clientArea( FullArea, geom.center(), desktop()).size()) return 2; // full area fullscreen hack diff --git a/manage.cpp b/manage.cpp index 039cecf5f8..1c4dda4776 100644 --- a/manage.cpp +++ b/manage.cpp @@ -140,20 +140,16 @@ bool Client::manage( Window w, bool isMapped ) workspace()->updateClientLayer( this ); SessionInfo* session = workspace()->takeSessionInfo( this ); - - if ( session ) + if( session ) { - if ( session->minimized ) - init_minimize = true; - if( session->userNoBorder ) - setUserNoBorder( true ); + init_minimize = session->minimized; + noborder = session->noBorder; } setShortcut( rules()->checkShortcut( session ? session->shortcut : QString(), true )); init_minimize = rules()->checkMinimize( init_minimize, !isMapped ); - if( rules()->checkNoBorder( false, !isMapped )) - setUserNoBorder( true ); + noborder = rules()->checkNoBorder( noborder, !isMapped ); // initial desktop placement if ( session ) diff --git a/rules.cpp b/rules.cpp index 0e8588dccf..bf4bdfba90 100644 --- a/rules.cpp +++ b/rules.cpp @@ -495,8 +495,8 @@ bool Rules::update( Client* c ) } if( noborderrule == ( SetRule )Remember) { - updated = updated || noborder != c->isUserNoBorder(); - noborder = c->isUserNoBorder(); + updated = updated || noborder != c->noBorder(); + noborder = c->noBorder(); } if (opacityactiverule == ( ForceRule )Force) { @@ -838,7 +838,7 @@ void Client::applyWindowRules() setKeepAbove( keepAbove()); setKeepBelow( keepBelow()); setFullScreen( isFullScreen(), true ); - setUserNoBorder( isUserNoBorder()); + setNoBorder( noBorder()); // FSP // AcceptFocus : if( workspace()->mostRecentlyActivatedClient() == this diff --git a/sm.cpp b/sm.cpp index 95c51b8e44..0addf0847b 100644 --- a/sm.cpp +++ b/sm.cpp @@ -121,7 +121,8 @@ void Workspace::storeSession( KConfig* config, SMSavePhase phase ) cg.writeEntry( QString("keepBelow")+n, c->keepBelow() ); cg.writeEntry( QString("skipTaskbar")+n, c->skipTaskbar( true ) ); cg.writeEntry( QString("skipPager")+n, c->skipPager() ); - cg.writeEntry( QString("userNoBorder")+n, c->isUserNoBorder() ); + // not really just set by user, but name kept for back. comp. reasons + cg.writeEntry( QString("userNoBorder")+n, c->noBorder() ); cg.writeEntry( QString("windowType")+n, windowTypeToTxt( c->windowType())); cg.writeEntry( QString("shortcut")+n, c->shortcut().toString()); cg.writeEntry( QString("stackingOrder")+n, unconstrained_stacking_order.indexOf( c )); @@ -185,7 +186,7 @@ void Workspace::loadSessionInfo() info->keepBelow = cg.readEntry( QString("keepBelow")+n, false ); info->skipTaskbar = cg.readEntry( QString("skipTaskbar")+n, false ); info->skipPager = cg.readEntry( QString("skipPager")+n, false ); - info->userNoBorder = cg.readEntry( QString("userNoBorder")+n, false ); + info->noBorder = cg.readEntry( QString("userNoBorder")+n, false ); info->windowType = txtToWindowType( cg.readEntry( QString("windowType")+n, QString() ).toLatin1()); info->shortcut = cg.readEntry( QString("shortcut")+n, QString() ); info->active = ( active_client == i ); diff --git a/sm.h b/sm.h index b93c2b6240..4acc9fd484 100644 --- a/sm.h +++ b/sm.h @@ -56,7 +56,7 @@ struct SessionInfo bool keepBelow; bool skipTaskbar; bool skipPager; - bool userNoBorder; + bool noBorder; NET::WindowType windowType; QString shortcut; bool active; // means 'was active in the saved session' diff --git a/useractions.cpp b/useractions.cpp index 376e1499f0..ac07a60e27 100644 --- a/useractions.cpp +++ b/useractions.cpp @@ -499,7 +499,7 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op ) c->setFullScreen( !c->isFullScreen(), true ); break; case Options::NoBorderOp: - c->setUserNoBorder( !c->isUserNoBorder()); + c->setNoBorder( !c->noBorder()); break; case Options::KeepAboveOp: {