Merged r970865:1049322 from /branches/work/kwin-tabbing
Adds window tabbing support to KWin. FEATURE: 42023 svn path=/trunk/KDE/kdebase/workspace/; revision=1049334icc-effect-5.14.5
parent
3c63918fd5
commit
a0d07d12a2
|
@ -59,6 +59,7 @@ endif( KWIN_HAVE_COMPOSITING )
|
|||
set(kwin_KDEINIT_SRCS
|
||||
workspace.cpp
|
||||
client.cpp
|
||||
clientgroup.cpp
|
||||
placement.cpp
|
||||
atoms.cpp
|
||||
utils.cpp
|
||||
|
|
|
@ -367,6 +367,13 @@ void Workspace::takeActivity( Client* c, int flags, bool handled )
|
|||
}
|
||||
if( !c->isShown( true )) // shouldn't happen, call activateClient() if needed
|
||||
{
|
||||
int group_size = c->clientGroup()->clients().count();
|
||||
if( group_size > 1 && c->clientGroup()->visible() != c ) // the tab is hidden, make it visible and call this function again
|
||||
{
|
||||
c->clientGroup()->setVisible( c );
|
||||
takeActivity( c, flags, handled );
|
||||
return;
|
||||
}
|
||||
kWarning( 1212 ) << "takeActivity: not shown" ;
|
||||
return;
|
||||
}
|
||||
|
|
60
bridge.cpp
60
bridge.cpp
|
@ -208,4 +208,64 @@ bool Bridge::compositingActive() const
|
|||
return c->workspace()->compositingActive();
|
||||
}
|
||||
|
||||
bool Bridge::isClientGroupActive()
|
||||
{
|
||||
return c->clientGroup()->containsActiveClient();
|
||||
}
|
||||
|
||||
QList< ClientGroupItem > Bridge::clientGroupItems() const
|
||||
{
|
||||
return c->clientGroup()->items();
|
||||
}
|
||||
|
||||
int Bridge::itemId( int index )
|
||||
{
|
||||
const ClientList list = c->clientGroup()->clients();
|
||||
return reinterpret_cast<int>( list.at( index ));
|
||||
}
|
||||
|
||||
int Bridge::visibleClientGroupItem()
|
||||
{
|
||||
return c->clientGroup()->indexOfVisibleClient();
|
||||
}
|
||||
|
||||
void Bridge::setVisibleClientGroupItem( int index )
|
||||
{
|
||||
c->clientGroup()->setVisible( index );
|
||||
}
|
||||
|
||||
void Bridge::moveItemInClientGroup( int index, int before )
|
||||
{
|
||||
c->clientGroup()->move( index, before );
|
||||
}
|
||||
|
||||
void Bridge::moveItemToClientGroup( int itemId, int before )
|
||||
{
|
||||
Client* item = reinterpret_cast<Client*>( itemId );
|
||||
c->workspace()->moveItemToClientGroup( item->clientGroup(), item->clientGroup()->indexOfClient( item ),
|
||||
c->clientGroup(), before );
|
||||
}
|
||||
|
||||
void Bridge::removeFromClientGroup( int index, const QRect& newGeom )
|
||||
{
|
||||
c->clientGroup()->remove( index, newGeom );
|
||||
}
|
||||
|
||||
void Bridge::closeClientGroupItem( int index )
|
||||
{
|
||||
const ClientList list = c->clientGroup()->clients();
|
||||
if( index >= 0 || index <= list.count() )
|
||||
list.at( index )->closeWindow();
|
||||
}
|
||||
|
||||
void Bridge::closeAllInClientGroup()
|
||||
{
|
||||
c->clientGroup()->closeAll();
|
||||
}
|
||||
|
||||
void Bridge::displayClientMenu( int index, const QPoint& pos )
|
||||
{
|
||||
c->clientGroup()->displayClientMenu( index, pos );
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
14
bridge.h
14
bridge.h
|
@ -76,6 +76,20 @@ class Bridge : public KDecorationBridgeUnstable
|
|||
virtual void grabXServer( bool grab );
|
||||
|
||||
virtual bool compositingActive() const;
|
||||
|
||||
// Window tabbing
|
||||
virtual bool isClientGroupActive();
|
||||
virtual QList< ClientGroupItem > clientGroupItems() const;
|
||||
virtual int itemId( int index );
|
||||
virtual int visibleClientGroupItem();
|
||||
virtual void setVisibleClientGroupItem( int index );
|
||||
virtual void moveItemInClientGroup( int index, int before );
|
||||
virtual void moveItemToClientGroup( int itemId, int before );
|
||||
virtual void removeFromClientGroup( int index, const QRect& newGeom );
|
||||
virtual void closeClientGroupItem( int index );
|
||||
virtual void closeAllInClientGroup();
|
||||
virtual void displayClientMenu( int index, const QPoint& pos );
|
||||
|
||||
private:
|
||||
Client* c;
|
||||
};
|
||||
|
|
64
client.cpp
64
client.cpp
|
@ -97,6 +97,7 @@ Client::Client( Workspace* ws )
|
|||
, delayedMoveResizeTimer( NULL )
|
||||
, in_group( NULL )
|
||||
, window_group( None )
|
||||
, client_group( NULL )
|
||||
, in_layer( UnknownLayer )
|
||||
, ping_timer( NULL )
|
||||
, process_killer( NULL )
|
||||
|
@ -244,6 +245,8 @@ void Client::releaseWindow( bool on_shutdown )
|
|||
XUnmapWindow( display(), frameId()); // Destroying decoration would cause ugly visual effect
|
||||
destroyDecoration();
|
||||
cleanGrouping();
|
||||
if( clientGroup() )
|
||||
clientGroup()->remove( this );
|
||||
if( !on_shutdown )
|
||||
{
|
||||
workspace()->removeClient( this, Allowed );
|
||||
|
@ -306,6 +309,8 @@ void Client::destroyClient()
|
|||
workspace()->clientHidden( this );
|
||||
destroyDecoration();
|
||||
cleanGrouping();
|
||||
if( clientGroup() )
|
||||
clientGroup()->remove( this );
|
||||
workspace()->removeClient( this, Allowed );
|
||||
client = None; // invalidate
|
||||
XDestroyWindow( display(), wrapper );
|
||||
|
@ -656,7 +661,7 @@ bool Client::noBorder() const
|
|||
|
||||
bool Client::userCanSetNoBorder() const
|
||||
{
|
||||
return !isFullScreen() && !isShade();
|
||||
return !isFullScreen() && !isShade() && ( clientGroup() == NULL || !(clientGroup()->items().count() > 1));
|
||||
}
|
||||
|
||||
void Client::setNoBorder( bool set )
|
||||
|
@ -849,6 +854,10 @@ void Client::minimize( bool avoid_animation )
|
|||
workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
|
||||
if( effects && !avoid_animation ) // TODO: Shouldn't it tell effects at least about the change?
|
||||
static_cast<EffectsHandlerImpl*>(effects)->windowMinimized( effectWindow());
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
void Client::unminimize( bool avoid_animation )
|
||||
|
@ -864,6 +873,10 @@ void Client::unminimize( bool avoid_animation )
|
|||
updateWindowRules();
|
||||
if( effects && !avoid_animation )
|
||||
static_cast<EffectsHandlerImpl*>( effects )->windowUnminimized( effectWindow() );
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
QRect Client::iconGeometry() const
|
||||
|
@ -967,6 +980,10 @@ void Client::setShade( ShadeMode mode )
|
|||
workspace()->updateMinimizedOfTransients( this );
|
||||
decoration->shadeChange();
|
||||
updateWindowRules();
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
void Client::shadeHover()
|
||||
|
@ -996,7 +1013,7 @@ void Client::updateVisibility()
|
|||
{
|
||||
if( deleting )
|
||||
return;
|
||||
if( hidden )
|
||||
if( hidden && ( clientGroup() == NULL || clientGroup()->visible() == this ))
|
||||
{
|
||||
info->setState( NET::Hidden, NET::Hidden );
|
||||
setSkipTaskbar( true, false ); // Also hide from taskbar
|
||||
|
@ -1006,6 +1023,7 @@ void Client::updateVisibility()
|
|||
internalHide( Allowed );
|
||||
return;
|
||||
}
|
||||
if( clientGroup() == NULL || clientGroup()->visible() == this )
|
||||
setSkipTaskbar( original_skip_taskbar, false ); // Reset from 'hidden'
|
||||
if( minimized )
|
||||
{
|
||||
|
@ -1396,6 +1414,10 @@ void Client::setDesktop( int desktop )
|
|||
workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
|
||||
updateVisibility();
|
||||
updateWindowRules();
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1418,6 +1440,10 @@ void Client::setOnAllDesktops( bool b )
|
|||
setDesktop( NET::OnAllDesktops );
|
||||
else
|
||||
setDesktop( workspace()->currentDesktop());
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1568,9 +1594,12 @@ void Client::setCaption( const QString& _s, bool force )
|
|||
info->setVisibleIconName( ( cap_iconic + cap_suffix ).toUtf8() );
|
||||
|
||||
if( isManaged() && decoration != NULL )
|
||||
{
|
||||
client_group->updateItems();
|
||||
decoration->captionChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::updateCaption()
|
||||
{
|
||||
|
@ -1606,6 +1635,37 @@ QString Client::caption( bool full ) const
|
|||
return full ? cap_normal + cap_suffix : cap_normal;
|
||||
}
|
||||
|
||||
void Client::dontMoveResize()
|
||||
{
|
||||
buttonDown = false;
|
||||
stopDelayedMoveResize();
|
||||
if( moveResizeMode )
|
||||
finishMoveResize( false );
|
||||
}
|
||||
|
||||
void Client::setClientShown( bool shown )
|
||||
{
|
||||
if( !shown )
|
||||
{
|
||||
unmap( Allowed );
|
||||
hidden = true;
|
||||
//updateVisibility();
|
||||
//updateAllowedActions();
|
||||
workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
|
||||
addWorkspaceRepaint( visibleRect() );
|
||||
}
|
||||
else
|
||||
{
|
||||
map( Allowed );
|
||||
hidden = false;
|
||||
updateVisibility();
|
||||
//updateAllowedActions();
|
||||
takeFocus( Allowed );
|
||||
autoRaise();
|
||||
workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
|
||||
}
|
||||
}
|
||||
|
||||
void Client::getWMHints()
|
||||
{
|
||||
XWMHints* hints = XGetWMHints( display(), window() );
|
||||
|
|
33
client.h
33
client.h
|
@ -41,6 +41,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "kdecoration.h"
|
||||
#include "rules.h"
|
||||
#include "toplevel.h"
|
||||
#include "clientgroup.h"
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
#include <X11/extensions/sync.h>
|
||||
|
@ -301,6 +302,24 @@ class Client
|
|||
StrutRect strutRect( StrutArea area ) const;
|
||||
StrutRects strutRects() const;
|
||||
bool hasStrut() const;
|
||||
|
||||
// Tabbing functions
|
||||
ClientGroup* clientGroup() const; // Returns a pointer to client_group
|
||||
void setClientGroup( ClientGroup* group );
|
||||
/*
|
||||
* If shown is true the client is mapped and raised, if false
|
||||
* the client is unmapped and hidden, this function is called
|
||||
* when the tabbing group of the client switches its visible
|
||||
* client.
|
||||
*/
|
||||
void setClientShown( bool shown );
|
||||
/*
|
||||
* When a click is done in the decoration and it calls the group
|
||||
* to change the visible client it starts to move-resize the new
|
||||
* client, this function stops it.
|
||||
*/
|
||||
void dontMoveResize();
|
||||
|
||||
/**
|
||||
* Whether or not the window has a strut that expands through the invisible area of
|
||||
* an xinerama setup where the monitors are not the same resolution.
|
||||
|
@ -570,6 +589,7 @@ class Client
|
|||
QString cap_normal, cap_iconic, cap_suffix;
|
||||
Group* in_group;
|
||||
Window window_group;
|
||||
ClientGroup* client_group;
|
||||
Layer in_layer;
|
||||
QTimer* ping_timer;
|
||||
QProcess* process_killer;
|
||||
|
@ -703,6 +723,16 @@ inline Group* Client::group()
|
|||
return in_group;
|
||||
}
|
||||
|
||||
inline void Client::setClientGroup( ClientGroup* group )
|
||||
{
|
||||
client_group = group;
|
||||
}
|
||||
|
||||
inline ClientGroup* Client::clientGroup() const
|
||||
{
|
||||
return client_group;
|
||||
}
|
||||
|
||||
inline bool Client::isMinimized() const
|
||||
{
|
||||
return minimized;
|
||||
|
@ -715,7 +745,8 @@ inline bool Client::isActive() const
|
|||
|
||||
inline bool Client::isShown( bool shaded_is_shown ) const
|
||||
{
|
||||
return !isMinimized() && ( !isShade() || shaded_is_shown ) && !hidden;
|
||||
return !isMinimized() && ( !isShade() || shaded_is_shown ) && !hidden &&
|
||||
( clientGroup() == NULL || clientGroup()->visible() == this );
|
||||
}
|
||||
|
||||
inline bool Client::isHiddenInternal() const
|
||||
|
|
|
@ -0,0 +1,291 @@
|
|||
/*******************************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "clientgroup.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "effects.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
ClientGroup::ClientGroup( Client *c )
|
||||
: clients_()
|
||||
, items_()
|
||||
, visible_( 0 )
|
||||
, minSize_( 0, 0 )
|
||||
, maxSize_( INT_MAX, INT_MAX )
|
||||
{
|
||||
clients_.append( c );
|
||||
updateItems();
|
||||
updateMinMaxSize();
|
||||
Workspace::self()->addClientGroup( this );
|
||||
c->setClientShown( true ); // Ensure the client is visible
|
||||
c->triggerDecorationRepaint(); // TODO: Required? Maybe for creating new group?
|
||||
}
|
||||
|
||||
ClientGroup::~ClientGroup()
|
||||
{
|
||||
Workspace::self()->removeClientGroup( this );
|
||||
}
|
||||
|
||||
void ClientGroup::add( Client* c, int before, bool becomeVisible )
|
||||
{
|
||||
if( contains( c ) || !c->workspace()->decorationSupportsClientGrouping() )
|
||||
return;
|
||||
|
||||
// Client must not already be grouped
|
||||
assert( c->clientGroup()->clients().size() == 1 );
|
||||
|
||||
// Tabbed windows MUST have a decoration
|
||||
if( c->noBorder() )
|
||||
c->setNoBorder( false );
|
||||
if( clients_[visible_]->noBorder() )
|
||||
clients_[visible_]->setNoBorder( false );
|
||||
|
||||
// Notify effects of merge
|
||||
if( effects != NULL )
|
||||
static_cast<EffectsHandlerImpl*>(effects)->clientGroupItemAdded(
|
||||
c->effectWindow(), clients_[visible_]->effectWindow() );
|
||||
|
||||
// Delete old group and update
|
||||
delete c->clientGroup(); // Delete old group as it's now empty
|
||||
c->setClientGroup( this ); // Let the client know which group it belongs to
|
||||
|
||||
// Actually add to new group
|
||||
if( before >= 0 )
|
||||
{
|
||||
if( visible_ >= before )
|
||||
visible_++;
|
||||
clients_.insert( before, c );
|
||||
}
|
||||
else
|
||||
clients_.append( c );
|
||||
if( !becomeVisible ) // Hide before adding
|
||||
c->setClientShown( false );
|
||||
updateItems();
|
||||
updateMinMaxSize();
|
||||
updateStates( clients_[visible_], c );
|
||||
|
||||
c->setGeometry( clients_[visible_]->geometry() );
|
||||
if( becomeVisible ) // Set visible after settings geometry
|
||||
setVisible( c );
|
||||
|
||||
// Activate the new visible window
|
||||
clients_[visible_]->setActive( true );
|
||||
//clients_[visible_]->takeFocus( Allowed );
|
||||
//clients_[visible_]->workspace()->raiseClient( clients_[visible_] );
|
||||
|
||||
clients_[visible_]->triggerDecorationRepaint();
|
||||
}
|
||||
|
||||
void ClientGroup::remove( int index, const QRect& newGeom )
|
||||
{
|
||||
remove( clients_[index], newGeom );
|
||||
}
|
||||
|
||||
void ClientGroup::remove( Client* c, const QRect& newGeom )
|
||||
{
|
||||
if( !c )
|
||||
return;
|
||||
if( clients_.count() < 2 )
|
||||
{
|
||||
c->setClientGroup( NULL );
|
||||
Workspace::self()->removeClientGroup( this ); // Remove immediately
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
ClientList::const_iterator i;
|
||||
Client* newVisible = clients_[visible_];
|
||||
if( newVisible == c )
|
||||
newVisible = ( visible_ != clients_.size() - 1 ) ? clients_[visible_ + 1] : clients_[visible_ - 1];
|
||||
|
||||
// Notify effects of removal
|
||||
if( effects )
|
||||
static_cast<EffectsHandlerImpl*>(effects)->clientGroupItemRemoved(
|
||||
c->effectWindow(), newVisible->effectWindow() );
|
||||
|
||||
setVisible( newVisible ); // Display new window before removing old one
|
||||
clients_.removeAll( c );
|
||||
visible_ = indexOfClient( newVisible ); // Index may have changed
|
||||
updateItems();
|
||||
updateMinMaxSize();
|
||||
|
||||
c->setClientGroup( new ClientGroup( c ));
|
||||
if( newGeom.isValid() )
|
||||
c->setGeometry( newGeom );
|
||||
|
||||
newVisible->triggerDecorationRepaint();
|
||||
}
|
||||
|
||||
void ClientGroup::removeAll()
|
||||
{
|
||||
while( clients_.count() > 1 )
|
||||
remove( clients_.at( 1 ));
|
||||
}
|
||||
|
||||
void ClientGroup::closeAll()
|
||||
{
|
||||
Client* front;
|
||||
ClientList list( clients_ );
|
||||
while( !list.isEmpty() )
|
||||
{
|
||||
front = list.front();
|
||||
list.pop_front();
|
||||
if( front != clients_[visible_] )
|
||||
front->closeWindow();
|
||||
}
|
||||
clients_[visible_]->closeWindow();
|
||||
}
|
||||
|
||||
void ClientGroup::move( int index, int before )
|
||||
{
|
||||
move( clients_[index], ( before >= 0 && before < clients_.size() ) ? clients_[before] : NULL );
|
||||
}
|
||||
|
||||
void ClientGroup::move( Client* c, Client* before )
|
||||
{
|
||||
if( c == before ) // Impossible to do
|
||||
return;
|
||||
|
||||
Client* wasVisible = clients_[visible_];
|
||||
clients_.removeAll( c );
|
||||
clients_.insert( before ? indexOfClient( before ) : clients_.size(), c );
|
||||
visible_ = indexOfClient( wasVisible );
|
||||
updateItems();
|
||||
|
||||
clients_[visible_]->triggerDecorationRepaint();
|
||||
}
|
||||
|
||||
void ClientGroup::displayClientMenu( int index, const QPoint& pos )
|
||||
{
|
||||
displayClientMenu( clients_[index], pos );
|
||||
}
|
||||
|
||||
void ClientGroup::displayClientMenu( Client* c, const QPoint& pos )
|
||||
{
|
||||
c->workspace()->showWindowMenu( pos, c );
|
||||
}
|
||||
|
||||
bool ClientGroup::containsActiveClient()
|
||||
{
|
||||
return contains( Workspace::self()->activeClient() );
|
||||
}
|
||||
|
||||
void ClientGroup::setVisible( int index )
|
||||
{
|
||||
setVisible( clients_[index] );
|
||||
}
|
||||
|
||||
void ClientGroup::setVisible( Client* c )
|
||||
{
|
||||
if( c == clients_[visible_] || !contains( c ))
|
||||
return;
|
||||
|
||||
// Notify effects of switch
|
||||
if( effects != NULL )
|
||||
static_cast<EffectsHandlerImpl*>(effects)->clientGroupItemSwitched(
|
||||
clients_[visible_]->effectWindow(), c->effectWindow() );
|
||||
|
||||
visible_ = indexOfClient( c );
|
||||
c->setClientShown( true );
|
||||
for( ClientList::const_iterator i = clients_.begin(); i != clients_.end(); i++ )
|
||||
if( (*i) != c )
|
||||
(*i)->setClientShown( false );
|
||||
}
|
||||
|
||||
void ClientGroup::updateStates( Client* main, Client* only )
|
||||
{
|
||||
for( ClientList::const_iterator i = clients_.begin(); i != clients_.end(); i++ )
|
||||
if( (*i) != main && ( !only || (*i) == only ))
|
||||
{
|
||||
if( (*i)->isMinimized() != main->isMinimized() )
|
||||
{
|
||||
if( main->isMinimized() )
|
||||
(*i)->minimize( true );
|
||||
else
|
||||
(*i)->unminimize( true );
|
||||
}
|
||||
if( (*i)->isShade() != main->isShade() )
|
||||
(*i)->setShade( main->isShade() ? ShadeNormal : ShadeNone );
|
||||
if( (*i)->geometry() != main->geometry() )
|
||||
(*i)->setGeometry( main->geometry() );
|
||||
if( (*i)->desktop() != main->desktop() )
|
||||
(*i)->setDesktop( main->desktop() );
|
||||
if( (*i)->isOnAllDesktops() != main->isOnAllDesktops() )
|
||||
(*i)->setOnAllDesktops( main->isOnAllDesktops() );
|
||||
if( (*i)->keepAbove() != main->keepAbove() )
|
||||
(*i)->setKeepAbove( main->keepAbove() );
|
||||
if( (*i)->keepBelow() != main->keepBelow() )
|
||||
(*i)->setKeepBelow( main->keepBelow() );
|
||||
}
|
||||
}
|
||||
|
||||
void ClientGroup::updateItems()
|
||||
{
|
||||
items_.clear();
|
||||
for( ClientList::const_iterator i = clients_.begin(); i != clients_.end(); i++ )
|
||||
{
|
||||
QIcon icon( (*i)->icon() );
|
||||
icon.addPixmap( (*i)->miniIcon() );
|
||||
items_.append( ClientGroupItem( (*i)->caption(), icon ));
|
||||
}
|
||||
}
|
||||
|
||||
void ClientGroup::updateMinMaxSize()
|
||||
{
|
||||
// Determine entire group's minimum and maximum sizes
|
||||
minSize_ = QSize( 0, 0 );
|
||||
maxSize_ = QSize( INT_MAX, INT_MAX );
|
||||
for( ClientList::const_iterator i = clients_.begin(); i != clients_.end(); i++ )
|
||||
{
|
||||
if( (*i)->minSize().width() > minSize_.width() )
|
||||
minSize_.setWidth( (*i)->minSize().width() );
|
||||
if( (*i)->minSize().height() > minSize_.height() )
|
||||
minSize_.setHeight( (*i)->minSize().height() );
|
||||
if( (*i)->maxSize().width() < maxSize_.width() )
|
||||
maxSize_.setWidth( (*i)->maxSize().width() );
|
||||
if( (*i)->maxSize().height() < maxSize_.height() )
|
||||
maxSize_.setHeight( (*i)->maxSize().height() );
|
||||
}
|
||||
if( minSize_.width() > maxSize_.width() ||
|
||||
minSize_.height() > maxSize_.height() )
|
||||
{
|
||||
kWarning(1212) << "ClientGroup's min size is greater than its' max size. Setting max to min.";
|
||||
maxSize_ = minSize_;
|
||||
}
|
||||
|
||||
// Ensure all windows are within these sizes
|
||||
const QSize size = clients_[visible_]->size();
|
||||
QSize newSize(
|
||||
qBound( minSize_.width(), size.width(), maxSize_.width() ),
|
||||
qBound( minSize_.height(), size.height(), maxSize_.height() ));
|
||||
if( newSize != size )
|
||||
for( ClientList::const_iterator i = clients_.begin(); i != clients_.end(); i++ )
|
||||
// TODO: Doesn't affect shaded windows?
|
||||
// There seems to be a race condition when using plainResize() which causes the window
|
||||
// to sometimes be located at new window's location instead of the visible window's location
|
||||
// when a window with a large min size is added to a group with a small window size.
|
||||
(*i)->setGeometry( QRect( clients_[visible_]->pos(), newSize ));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
/*******************************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef KWIN_CLIENTGROUP_H
|
||||
#define KWIN_CLIENTGROUP_H
|
||||
|
||||
#include "kdecoration.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class Client;
|
||||
|
||||
/**
|
||||
* This class represents a group of clients for use in window tabbing. All
|
||||
* clients in the group share the same geometry and state information; I.e if
|
||||
* one client changes then all others should also be changed.
|
||||
*
|
||||
* Workspace::clientGroups is a list of all currently-existing client groups.
|
||||
*
|
||||
* A group MUST contain at least one client and MUST NOT contain multiple
|
||||
* copies of the same client. A client MUST NOT be in two groups at the same
|
||||
* time. All decorated clients SHOULD be in a group, even if it's a group of
|
||||
* one client.
|
||||
*
|
||||
* If a group contains multiple clients then only one will ever be mapped at
|
||||
* any given time.
|
||||
*/
|
||||
class ClientGroup
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new group containing \p c.
|
||||
*/
|
||||
ClientGroup( Client* c );
|
||||
~ClientGroup();
|
||||
|
||||
/**
|
||||
* Adds \p c to the group before \p before in the list. If \p becomeVisible is \i true then
|
||||
* the added client will become also the visible client.
|
||||
*/
|
||||
void add( Client* c, int before = -1, bool becomeVisible = false );
|
||||
/**
|
||||
* Remove the client at index \p index from the group. If \p newGeom is set then the client
|
||||
* will move and resize to the specified geometry, otherwise it will stay where the group
|
||||
* is located.
|
||||
*/
|
||||
void remove( int index, const QRect& newGeom = QRect() );
|
||||
/**
|
||||
* Remove \p c from the group. If \p newGeom is set then the client will move and resize to
|
||||
* the specified geometry, otherwise it will stay where the group is located.
|
||||
*/
|
||||
void remove( Client* c, const QRect& newGeom = QRect() );
|
||||
/**
|
||||
* Remove all clients from this group. Results in all clients except the first being moved
|
||||
to a group of their own.
|
||||
*/
|
||||
void removeAll();
|
||||
/**
|
||||
* Close all clients in this group.
|
||||
*/
|
||||
void closeAll();
|
||||
/**
|
||||
* Move the client at index \p index to the position before the client at index \p before
|
||||
* in the list.
|
||||
*/
|
||||
void move( int index, int before );
|
||||
/**
|
||||
* Move \p c to the position before \p before in the list.
|
||||
*/
|
||||
void move( Client* c, Client* before );
|
||||
/**
|
||||
* Display the right-click client menu belonging to the client at index \p index at the
|
||||
* global coordinates specified by \p pos.
|
||||
*/
|
||||
void displayClientMenu( int index, const QPoint& pos );
|
||||
/**
|
||||
* Display the right-click client menu belonging to \p c at the global coordinates
|
||||
* specified by \p pos.
|
||||
*/
|
||||
void displayClientMenu( Client* c, const QPoint& pos );
|
||||
|
||||
/**
|
||||
* Returns the list index of \p c.
|
||||
*/
|
||||
int indexOfClient( Client* c );
|
||||
/**
|
||||
* Returns the list index of the currently visible client in the group.
|
||||
*/
|
||||
int indexOfVisibleClient();
|
||||
/**
|
||||
* Returns whether or not this group contains \p c.
|
||||
*/
|
||||
bool contains( Client* c );
|
||||
/**
|
||||
* Returns whether or not this group contains the active client.
|
||||
*/
|
||||
bool containsActiveClient();
|
||||
|
||||
/**
|
||||
* Returns the list of all the clients contained in this group in their current order.
|
||||
*/
|
||||
ClientList clients() const;
|
||||
/**
|
||||
* Returns a list of the captions and icons of all the clients contained in this group
|
||||
* in their current order.
|
||||
*/
|
||||
QList< ClientGroupItem > items() const;
|
||||
|
||||
/**
|
||||
* Returns the currently visible client.
|
||||
*/
|
||||
Client* visible();
|
||||
/**
|
||||
* Makes the client at index \p index the visible one in the group.
|
||||
*/
|
||||
void setVisible( int index );
|
||||
/**
|
||||
* Makes \p c the visible client in the group.
|
||||
*/
|
||||
void setVisible( Client* c );
|
||||
|
||||
/**
|
||||
* Returns combined minimum size of all clients in the group.
|
||||
*/
|
||||
QSize minSize() const;
|
||||
/**
|
||||
* Returns combined maximum size of all clients in the group.
|
||||
*/
|
||||
QSize maxSize() const;
|
||||
|
||||
/**
|
||||
* Ensures that all the clients in the group have identical geometries and states using
|
||||
* \p main as the primary client to copy the settings off. If \p only is set then only
|
||||
* that client is updated to match \p main.
|
||||
*/
|
||||
void updateStates( Client* main, Client* only = NULL );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Regenerate the list of client captions and icons.
|
||||
*/
|
||||
void updateItems();
|
||||
/**
|
||||
* Determine the combined minimum and maximum sizes of all clients in the group.
|
||||
*/
|
||||
void updateMinMaxSize();
|
||||
|
||||
ClientList clients_;
|
||||
QList< ClientGroupItem > items_;
|
||||
int visible_;
|
||||
|
||||
QSize minSize_;
|
||||
QSize maxSize_;
|
||||
|
||||
friend class Client;
|
||||
};
|
||||
|
||||
inline int ClientGroup::indexOfClient( Client* c )
|
||||
{
|
||||
return clients_.indexOf( c );
|
||||
}
|
||||
|
||||
inline int ClientGroup::indexOfVisibleClient()
|
||||
{
|
||||
return visible_;
|
||||
}
|
||||
|
||||
inline bool ClientGroup::contains( Client* c )
|
||||
{
|
||||
return clients_.contains( c );
|
||||
}
|
||||
|
||||
inline ClientList ClientGroup::clients() const
|
||||
{
|
||||
return clients_;
|
||||
}
|
||||
|
||||
inline QList< ClientGroupItem > ClientGroup::items() const
|
||||
{
|
||||
return items_;
|
||||
}
|
||||
|
||||
inline Client* ClientGroup::visible()
|
||||
{
|
||||
return clients_[visible_];
|
||||
}
|
||||
|
||||
inline QSize ClientGroup::minSize() const
|
||||
{
|
||||
return minSize_;
|
||||
}
|
||||
|
||||
inline QSize ClientGroup::maxSize() const
|
||||
{
|
||||
return maxSize_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -10,3 +10,4 @@ add_subdirectory( oxygen )
|
|||
add_subdirectory( quartz )
|
||||
add_subdirectory( redmond )
|
||||
add_subdirectory( web )
|
||||
add_subdirectory( tabstrip )
|
||||
|
|
|
@ -9,6 +9,7 @@ set(kwin_oxygen_SRCS
|
|||
oxygen.cpp
|
||||
oxygenbutton.cpp
|
||||
oxygenclient.cpp
|
||||
oxygenclientgroupitemdata.cpp
|
||||
oxygenconfiguration.cpp
|
||||
oxygenexception.cpp
|
||||
oxygenexceptionlist.cpp
|
||||
|
|
|
@ -129,6 +129,7 @@ namespace Oxygen
|
|||
configurationGroup.writeEntry( OxygenConfig::DRAW_SEPARATOR, userInterface_->ui.drawSeparator->isChecked() );
|
||||
configurationGroup.writeEntry( OxygenConfig::DRAW_TITLE_OUTLINE, userInterface_->ui.titleOutline->isChecked() );
|
||||
configurationGroup.writeEntry( OxygenConfig::USE_OXYGEN_SHADOWS, userInterface_->ui.useOxygenShadows->isChecked() );
|
||||
configurationGroup.writeEntry( OxygenConfig::TABS_ENABLED, userInterface_->ui.tabsEnabled->isChecked() );
|
||||
|
||||
// write exceptions
|
||||
userInterface_->ui.exceptions->exceptions().write( *configuration_ );
|
||||
|
@ -191,6 +192,7 @@ namespace Oxygen
|
|||
userInterface_->ui.drawSeparator->setChecked( configuration.drawSeparator() );
|
||||
userInterface_->ui.titleOutline->setChecked( configuration.drawTitleOutline() );
|
||||
userInterface_->ui.useOxygenShadows->setChecked( configuration.useOxygenShadows() );
|
||||
userInterface_->ui.tabsEnabled->setChecked( configuration.tabsEnabled() );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ namespace Oxygen
|
|||
connect( ui.blendColor, SIGNAL(currentIndexChanged(int)), SIGNAL(changed()) );
|
||||
connect( ui.sizeGripMode, SIGNAL(currentIndexChanged(int)), SIGNAL(changed()) );
|
||||
|
||||
connect( ui.tabsEnabled, SIGNAL(clicked()), SIGNAL(changed()) );
|
||||
connect( ui.drawSeparator, SIGNAL(clicked()), SIGNAL(changed()) );
|
||||
connect( ui.titleOutline, SIGNAL(clicked()), SIGNAL(changed()) );
|
||||
connect( ui.useOxygenShadows, SIGNAL(clicked()), SIGNAL(changed()) );
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
@ -86,6 +86,13 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="tabsEnabled">
|
||||
<property name="text">
|
||||
<string>Enable window grouping</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
|
|
|
@ -60,11 +60,7 @@ namespace Oxygen
|
|||
|
||||
//___________________________________________________
|
||||
KDecoration* OxygenFactory::createDecoration(KDecorationBridge* bridge )
|
||||
{
|
||||
OxygenClient* client( new OxygenClient( bridge, this ) );
|
||||
connect( this, SIGNAL( configurationChanged() ), client, SLOT( resetConfiguration() ) );
|
||||
return client->decoration();
|
||||
}
|
||||
{ return (new OxygenClient( bridge, this ))->decoration(); }
|
||||
|
||||
//___________________________________________________
|
||||
bool OxygenFactory::reset(unsigned long changed)
|
||||
|
@ -75,7 +71,6 @@ namespace Oxygen
|
|||
bool configuration_changed = readConfig();
|
||||
setInitialized( true );
|
||||
|
||||
emit configurationChanged();
|
||||
if( configuration_changed || (changed & (SettingDecoration | SettingButtons | SettingBorder)) )
|
||||
{
|
||||
|
||||
|
@ -174,6 +169,10 @@ namespace Oxygen
|
|||
case AbilityUsesAlphaChannel:
|
||||
return true;
|
||||
|
||||
// tabs
|
||||
case AbilityClientGrouping:
|
||||
return defaultConfiguration().tabsEnabled();
|
||||
|
||||
// no colors supported at this time
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -62,7 +62,6 @@ namespace Oxygen
|
|||
// shows the window menu for one tab
|
||||
ButtonItemMenu
|
||||
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(ButtonTypes, ButtonType)
|
||||
|
@ -82,10 +81,6 @@ namespace Oxygen
|
|||
HFRAMESIZE = 4
|
||||
};
|
||||
|
||||
#if !KDE_IS_VERSION(4,3,90)
|
||||
enum{ SettingCompositing = 1 << 6 };
|
||||
#endif
|
||||
|
||||
//! window decoration factory
|
||||
class OxygenFactory: public QObject, public KDecorationFactoryUnstable
|
||||
{
|
||||
|
@ -124,18 +119,13 @@ namespace Oxygen
|
|||
//! get configuration for a give client
|
||||
virtual OxygenConfiguration configuration( const OxygenClient& );
|
||||
|
||||
signals:
|
||||
|
||||
//! configuration has changed
|
||||
void configurationChanged( void );
|
||||
|
||||
private:
|
||||
|
||||
//! read configuration from KConfig
|
||||
bool readConfig();
|
||||
|
||||
//! default configuration
|
||||
const OxygenConfiguration& defaultConfiguration( void )
|
||||
const OxygenConfiguration& defaultConfiguration( void ) const
|
||||
{ return defaultConfiguration_; }
|
||||
|
||||
//! initialization
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include <KColorUtils>
|
||||
#include <KColorScheme>
|
||||
#include <kcommondecoration.h>
|
||||
#include <KDebug>
|
||||
|
||||
namespace Oxygen
|
||||
{
|
||||
|
@ -52,7 +51,7 @@ namespace Oxygen
|
|||
helper_( parent.helper() ),
|
||||
type_(type),
|
||||
forceInactive_( false ),
|
||||
timeLine_( 200, this )
|
||||
timeLine_( 150, this )
|
||||
{
|
||||
setAutoFillBackground(false);
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
|
@ -69,6 +68,7 @@ namespace Oxygen
|
|||
timeLine_.setCurveShape( QTimeLine::EaseInOutCurve );
|
||||
connect( &timeLine_, SIGNAL( frameChanged( int ) ), SLOT( update() ) );
|
||||
connect( &timeLine_, SIGNAL( finished() ), SLOT( update() ) );
|
||||
reset(0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -79,11 +79,11 @@ namespace Oxygen
|
|||
//_______________________________________________
|
||||
QColor OxygenButton::buttonDetailColor(const QPalette &palette)
|
||||
{
|
||||
if( client_.timeLineIsRunning() && !forceInactive_ ) return KColorUtils::mix(
|
||||
if( client_.timeLineIsRunning() && !forceInactive_ && !client_.isForcedActive()) return KColorUtils::mix(
|
||||
buttonDetailColor( palette, false ),
|
||||
buttonDetailColor( palette, true ),
|
||||
client_.opacity() );
|
||||
else return buttonDetailColor( palette, isActive() );
|
||||
else return buttonDetailColor( palette, isActive() || client_.isForcedActive() );
|
||||
}
|
||||
|
||||
//_______________________________________________
|
||||
|
@ -115,6 +115,12 @@ namespace Oxygen
|
|||
return QSize( size, size );
|
||||
}
|
||||
|
||||
//___________________________________________________
|
||||
void OxygenButton::reset( unsigned long )
|
||||
{
|
||||
timeLine_.setDuration( client_.configuration().animationsDuration() );
|
||||
}
|
||||
|
||||
//___________________________________________________
|
||||
void OxygenButton::enterEvent(QEvent *e)
|
||||
{
|
||||
|
|
|
@ -63,10 +63,6 @@ namespace Oxygen
|
|||
//! destructor
|
||||
QSize sizeHint() const;
|
||||
|
||||
//! reset
|
||||
void reset(long unsigned int)
|
||||
{repaint();}
|
||||
|
||||
//! button type
|
||||
ButtonType type( void ) const
|
||||
{ return type_; }
|
||||
|
@ -76,6 +72,9 @@ namespace Oxygen
|
|||
void setForceInactive( const bool& value )
|
||||
{ forceInactive_ = value; }
|
||||
|
||||
//! configuration reset
|
||||
virtual void reset( unsigned long );
|
||||
|
||||
protected:
|
||||
|
||||
//! press event
|
||||
|
|
|
@ -36,14 +36,13 @@
|
|||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
#include <kdeversion.h>
|
||||
#include <KLocale>
|
||||
#include <KColorUtils>
|
||||
#include <KDebug>
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QBitmap>
|
||||
|
||||
namespace Oxygen
|
||||
{
|
||||
|
@ -86,7 +85,11 @@ namespace Oxygen
|
|||
sizeGrip_( 0 ),
|
||||
timeLine_( 200, this ),
|
||||
titleTimeLine_( 200, this ),
|
||||
initialized_( false )
|
||||
initialized_( false ),
|
||||
forceActive_( false ),
|
||||
mouseButton_( Qt::NoButton ),
|
||||
itemData_( this ),
|
||||
sourceItem_( -1 )
|
||||
{}
|
||||
|
||||
//___________________________________________
|
||||
|
@ -109,12 +112,14 @@ namespace Oxygen
|
|||
KCommonDecoration::init();
|
||||
widget()->setAttribute(Qt::WA_NoSystemBackground );
|
||||
widget()->setAutoFillBackground( false );
|
||||
widget()->setAcceptDrops( true );
|
||||
|
||||
// initialize timeLine
|
||||
timeLine_.setFrameRange( maxAnimationIndex/5, maxAnimationIndex );
|
||||
timeLine_.setCurveShape( QTimeLine::EaseOutCurve );
|
||||
connect( &timeLine_, SIGNAL( frameChanged( int ) ), widget(), SLOT( update() ) );
|
||||
connect( &timeLine_, SIGNAL( finished() ), widget(), SLOT( update() ) );
|
||||
connect( &timeLine_, SIGNAL( finished() ), this, SLOT( clearForceActive() ) );
|
||||
|
||||
// initialize titleTimeLine
|
||||
titleTimeLine_.setFrameRange( 0, maxAnimationIndex );
|
||||
|
@ -123,7 +128,8 @@ namespace Oxygen
|
|||
connect( &titleTimeLine_, SIGNAL( finished() ), widget(), SLOT( update() ) );
|
||||
connect( &titleTimeLine_, SIGNAL( finished() ), this, SLOT( updateOldCaption() ) );
|
||||
|
||||
initialized_ = true;
|
||||
// lists
|
||||
connect( &itemData_.timeLine(), SIGNAL( finished() ), this, SLOT( clearTargetItem() ) );
|
||||
|
||||
// in case of preview, one wants to make the label used
|
||||
// for the central widget transparent. This allows one to have
|
||||
|
@ -139,20 +145,57 @@ namespace Oxygen
|
|||
|
||||
}
|
||||
|
||||
resetConfiguration();
|
||||
initialized_ = true;
|
||||
|
||||
// first reset is needed to store Oxygen configuration
|
||||
reset(0);
|
||||
|
||||
}
|
||||
|
||||
//___________________________________________
|
||||
void OxygenClient::reset( unsigned long changed )
|
||||
{
|
||||
KCommonDecorationUnstable::reset( changed );
|
||||
|
||||
// update window mask when compositing is changed
|
||||
if( !initialized_ ) return;
|
||||
if( changed & SettingCompositing )
|
||||
{
|
||||
updateWindowShape();
|
||||
widget()->update();
|
||||
}
|
||||
|
||||
KCommonDecorationUnstable::reset( changed );
|
||||
configuration_ = factory_->configuration( *this );
|
||||
|
||||
// animations duration
|
||||
timeLine_.setDuration( configuration_.animationsDuration() );
|
||||
titleTimeLine_.setDuration( configuration_.animationsDuration() );
|
||||
itemData_.timeLine().setDuration( configuration_.animationsDuration() );
|
||||
|
||||
// should also update animations for buttons
|
||||
resetButtons();
|
||||
|
||||
// also reset tab buttons
|
||||
for( int index = 0; index < itemData_.count(); index++ )
|
||||
{
|
||||
ClientGroupItemData& item( itemData_[index] );
|
||||
if( item.closeButton_ ) { item.closeButton_.data()->reset(0); }
|
||||
}
|
||||
|
||||
// copy current caption to old
|
||||
updateOldCaption();
|
||||
|
||||
// reset tab geometry
|
||||
itemData_.setDirty( true );
|
||||
|
||||
// handle size grip
|
||||
if( configuration_.drawSizeGrip() )
|
||||
{
|
||||
|
||||
if( !hasSizeGrip() ) createSizeGrip();
|
||||
|
||||
} else if( hasSizeGrip() ) deleteSizeGrip();
|
||||
|
||||
}
|
||||
|
||||
//___________________________________________
|
||||
|
@ -175,7 +218,9 @@ namespace Oxygen
|
|||
//_________________________________________________________
|
||||
KCommonDecorationButton *OxygenClient::createButton(::ButtonType type)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
|
||||
case MenuButton:
|
||||
return new OxygenButton(*this, i18n("Menu"), ButtonMenu);
|
||||
|
||||
|
@ -203,9 +248,12 @@ namespace Oxygen
|
|||
case ShadeButton:
|
||||
return new OxygenButton(*this, i18n("Shade Button"), ButtonShade);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
default: break;
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
//_________________________________________________________
|
||||
|
@ -341,11 +389,22 @@ namespace Oxygen
|
|||
}
|
||||
|
||||
//_________________________________________________________
|
||||
QRect OxygenClient::titleBoundingRect( QPainter* painter, const QRect& rect, const QString& caption ) const
|
||||
QRect OxygenClient::titleBoundingRect( const QFont& font, QRect rect, const QString& caption ) const
|
||||
{
|
||||
|
||||
// check bounding rect against titleRect
|
||||
// conflicts can happen only if there is only one item in group
|
||||
if( itemData_.count() == 1 )
|
||||
{
|
||||
QRect titleRect( OxygenClient::titleRect() );
|
||||
if( titleRect.left() > rect.left() ) { rect.setLeft( titleRect.left() ); }
|
||||
if( titleRect.right() < rect.right() ) { rect.setRight( titleRect.right() ); }
|
||||
|
||||
}
|
||||
|
||||
|
||||
// get title bounding rect
|
||||
QRect boundingRect = painter->boundingRect( rect, configuration().titleAlignment() | Qt::AlignVCenter, caption );
|
||||
QRect boundingRect = QFontMetrics( font ).boundingRect( rect, configuration().titleAlignment() | Qt::AlignVCenter, caption );
|
||||
|
||||
// adjust to make sure bounding rect
|
||||
// 1/ has same vertical alignment as original titleRect
|
||||
|
@ -353,6 +412,7 @@ namespace Oxygen
|
|||
boundingRect.setTop( rect.top() );
|
||||
boundingRect.setBottom( rect.bottom() );
|
||||
|
||||
// check bounding rect against input rect
|
||||
if( rect.left() > boundingRect.left() ) { boundingRect.setLeft( rect.left() ); }
|
||||
if( rect.right() < boundingRect.right() ) { boundingRect.setRight( rect.right() ); }
|
||||
|
||||
|
@ -360,6 +420,116 @@ namespace Oxygen
|
|||
|
||||
}
|
||||
|
||||
//_________________________________________________________
|
||||
void OxygenClient::clearTargetItem( void )
|
||||
{
|
||||
|
||||
if( !itemData_.animated() ) return;
|
||||
if( itemData_.animationType() == AnimationLeave )
|
||||
{ itemData_.setDirty( true ); }
|
||||
|
||||
}
|
||||
|
||||
//_________________________________________________________
|
||||
void OxygenClient::updateItemBoundingRects( bool alsoUpdate )
|
||||
{
|
||||
|
||||
// make sure items are not animated
|
||||
itemData_.animate( AnimationNone );
|
||||
|
||||
// maximum available space
|
||||
QRect titleRect( OxygenClient::titleRect() );
|
||||
|
||||
// get tabs
|
||||
int items( clientGroupItems().count() );
|
||||
|
||||
// make sure item data have the correct number of items
|
||||
while( itemData_.count() < items ) itemData_.push_back( ClientGroupItemData() );
|
||||
while( itemData_.count() > items )
|
||||
{
|
||||
if( itemData_.back().closeButton_ ) delete itemData_.back().closeButton_.data();
|
||||
itemData_.pop_back();
|
||||
}
|
||||
|
||||
assert( !itemData_.isEmpty() );
|
||||
|
||||
// create buttons
|
||||
if( itemData_.count() == 1 )
|
||||
{
|
||||
|
||||
// remove button
|
||||
if( itemData_.front().closeButton_ )
|
||||
{ delete itemData_.front().closeButton_.data(); }
|
||||
|
||||
// set active rect
|
||||
itemData_.front().activeRect_ = titleRect.adjusted( 0, -layoutMetric( LM_TitleEdgeTop ), 0, 0 );
|
||||
|
||||
} else {
|
||||
|
||||
int left( titleRect.left() );
|
||||
int width( titleRect.width()/items );
|
||||
for( int index = 0; index < itemData_.count(); index++ )
|
||||
{
|
||||
|
||||
ClientGroupItemData& item(itemData_[index]);
|
||||
|
||||
// make sure button exists
|
||||
if( !item.closeButton_ )
|
||||
{
|
||||
item.closeButton_ = ClientGroupItemData::ButtonPointer( new OxygenButton( *this, "Close this tab", ButtonItemClose ) );
|
||||
item.closeButton_.data()->show();
|
||||
item.closeButton_.data()->installEventFilter( this );
|
||||
}
|
||||
|
||||
// set active rect
|
||||
QRect local( QPoint( left, titleRect.top() ), QSize( width, titleRect.height() ) );
|
||||
local.adjust( 0, -layoutMetric( LM_TitleEdgeTop ), 0, 0 );
|
||||
item.activeRect_ = local;
|
||||
left += width;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( itemData_.count() == 1 )
|
||||
{
|
||||
|
||||
QRect active( itemData_.front().activeRect_ );
|
||||
if( configuration().drawTitleOutline() && isActive() )
|
||||
{
|
||||
|
||||
QRect textRect( titleBoundingRect( options()->font( true, false), active, caption() ) );
|
||||
active.setLeft( textRect.left() - layoutMetric( LM_TitleBorderLeft ) );
|
||||
active.setRight( textRect.right() + layoutMetric( LM_TitleBorderRight ) );
|
||||
|
||||
} else {
|
||||
|
||||
active.setLeft( widget()->rect().left() + layoutMetric( LM_OuterPaddingLeft ) );
|
||||
active.setRight( widget()->rect().right() - layoutMetric( LM_OuterPaddingRight ) );
|
||||
|
||||
}
|
||||
|
||||
// assign to item
|
||||
itemData_.front().reset( active );
|
||||
|
||||
} else {
|
||||
|
||||
for( int index = 0; index < itemData_.count(); index++ )
|
||||
{ itemData_[index].reset( itemData_[index].activeRect_ ); }
|
||||
|
||||
}
|
||||
|
||||
// button activity
|
||||
itemData_.updateButtonActivity( visibleClientGroupItem() );
|
||||
|
||||
// reset buttons location
|
||||
itemData_.updateButtons( alsoUpdate );
|
||||
itemData_.setDirty( false );
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
//_________________________________________________________
|
||||
QColor OxygenClient::titlebarTextColor(const QPalette &palette)
|
||||
{
|
||||
|
@ -391,11 +561,6 @@ namespace Oxygen
|
|||
|
||||
}
|
||||
|
||||
|
||||
//_________________________________________________________
|
||||
QColor OxygenClient::titlebarContrastColor(const QPalette &palette)
|
||||
{ return helper().calcLightColor( palette.color( widget()->window()->backgroundRole() ) ); }
|
||||
|
||||
//_________________________________________________________
|
||||
void OxygenClient::renderWindowBackground( QPainter* painter, const QRect& rect, const QWidget* widget, const QPalette& palette ) const
|
||||
{
|
||||
|
@ -421,7 +586,7 @@ namespace Oxygen
|
|||
{
|
||||
|
||||
// check if outline is needed
|
||||
if( !( isActive() && configuration().drawTitleOutline() ) ) return;
|
||||
if( clientGroupItems().count() < 2 && !itemData_.animated() && !( isActive() && configuration().drawTitleOutline() ) ) return;
|
||||
|
||||
// get coordinates relative to the client area
|
||||
// this is annoying. One could use mapTo if this was taking const QWidget* and not
|
||||
|
@ -453,6 +618,22 @@ namespace Oxygen
|
|||
// title height
|
||||
int titleHeight( layoutMetric( LM_TitleEdgeTop ) + layoutMetric( LM_TitleEdgeBottom ) + layoutMetric( LM_TitleHeight ) );
|
||||
|
||||
// make titlebar background darker for tabbed, non-outline window
|
||||
if( ( clientGroupItems().count() >= 2 || itemData_.animated() ) && !(configuration().drawTitleOutline() && isActive() ) )
|
||||
{
|
||||
|
||||
QPoint topLeft( r.topLeft()-position );
|
||||
QRect rect( topLeft, QSize( r.width(), titleHeight ) );
|
||||
|
||||
QLinearGradient lg( rect.topLeft(), rect.bottomLeft() );
|
||||
lg.setColorAt( 0, helper().alphaColor( Qt::black, 0.05 ) );
|
||||
lg.setColorAt( 1, helper().alphaColor( Qt::black, 0.10 ) );
|
||||
painter->setBrush( lg );
|
||||
painter->setPen( Qt::NoPen );
|
||||
painter->drawRect( rect );
|
||||
|
||||
}
|
||||
|
||||
// horizontal line
|
||||
{
|
||||
int shadowSize = 7;
|
||||
|
@ -470,7 +651,7 @@ namespace Oxygen
|
|||
|
||||
}
|
||||
|
||||
if( configuration().drawTitleOutline() )
|
||||
if( configuration().drawTitleOutline() && isActive() )
|
||||
{
|
||||
|
||||
// save mask and frame to where
|
||||
|
@ -592,7 +773,7 @@ namespace Oxygen
|
|||
// center (for active windows only)
|
||||
{
|
||||
painter->save();
|
||||
int offset = 2;
|
||||
int offset = 1;
|
||||
int voffset = 1;
|
||||
QRect adjustedRect( rect.adjusted( offset, voffset, -offset, 1 ) );
|
||||
|
||||
|
@ -608,7 +789,7 @@ namespace Oxygen
|
|||
|
||||
// shadow
|
||||
int shadowSize = 7;
|
||||
int offset = -2;
|
||||
int offset = -3;
|
||||
int voffset = 5-shadowSize;
|
||||
QRect adjustedRect( rect.adjusted(offset, voffset, -offset, shadowSize) );
|
||||
helper().slab( palette.color( widget()->backgroundRole() ), 0, shadowSize )->render( adjustedRect, painter, TileSet::Top|TileSet::Left|TileSet::Right );
|
||||
|
@ -668,6 +849,135 @@ namespace Oxygen
|
|||
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
void OxygenClient::renderItem( QPainter* painter, int index, const QPalette& palette )
|
||||
{
|
||||
|
||||
const ClientGroupItemData& item( itemData_[index] );
|
||||
|
||||
// see if tag is active
|
||||
int itemCount( itemData_.count() );
|
||||
|
||||
//
|
||||
if( !item.boundingRect_.isValid() ) return;
|
||||
|
||||
// create rect in which text is to be drawn
|
||||
QRect textRect( item.boundingRect_.adjusted( 0, layoutMetric( LM_TitleEdgeTop )-1, 0, -1 ) );
|
||||
|
||||
// add extra space needed for title outline
|
||||
if( itemCount > 1 || itemData_.animated() )
|
||||
{ textRect.adjust( layoutMetric( LM_TitleBorderLeft ), 0, -layoutMetric(LM_TitleBorderRight), 0 ); }
|
||||
|
||||
// add extra space for the button
|
||||
if( itemCount > 1 )
|
||||
{ textRect.adjust( 0, 0, - configuration().buttonSize() - layoutMetric(LM_TitleEdgeRight), 0 ); }
|
||||
|
||||
// check if current item is active
|
||||
bool active( index == visibleClientGroupItem() );
|
||||
|
||||
// get current item caption and update text rect
|
||||
const QList< ClientGroupItem >& items( clientGroupItems() );
|
||||
QString caption( itemCount == 1 ? OxygenClient::caption() : items[index].title() );
|
||||
|
||||
// title outline
|
||||
if( itemCount == 1 ) {
|
||||
|
||||
textRect = titleBoundingRect( painter->font(), textRect, caption );
|
||||
if( itemData_.animated() ) {
|
||||
|
||||
renderTitleOutline( painter, item.boundingRect_, palette );
|
||||
|
||||
} else if( isActive() && configuration().drawTitleOutline() ) {
|
||||
|
||||
// adjusts boundingRect accordingly
|
||||
QRect boundingRect( item.boundingRect_ );
|
||||
boundingRect.setLeft( textRect.left() - layoutMetric( LM_TitleBorderLeft ) );
|
||||
boundingRect.setRight( textRect.right() + layoutMetric( LM_TitleBorderRight ) );
|
||||
|
||||
// render bounding rect around it with extra margins
|
||||
renderTitleOutline( painter, boundingRect, palette );
|
||||
|
||||
}
|
||||
|
||||
} else if( active ) {
|
||||
|
||||
// in multiple tabs render title outline in all cases
|
||||
renderTitleOutline( painter, item.boundingRect_, palette );
|
||||
|
||||
}
|
||||
|
||||
// render text
|
||||
if( active || itemCount == 1 )
|
||||
{
|
||||
|
||||
// for active tab, current caption is "merged" with old caption, if any
|
||||
renderTitleText(
|
||||
painter, textRect,
|
||||
titlebarTextColor( palette ),
|
||||
titlebarContrastColor( palette ) );
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
QColor background( backgroundPalette( widget(), palette ).color( widget()->window()->backgroundRole() ) );
|
||||
|
||||
// add extra shade (as used in renderWindowBorder
|
||||
if( !( isActive() && configuration().drawTitleOutline() ) )
|
||||
{ background = KColorUtils::mix( background, Qt::black, 0.10 ); }
|
||||
|
||||
// otherwise current caption is rendered directly
|
||||
renderTitleText(
|
||||
painter, textRect, caption,
|
||||
titlebarTextColor( backgroundPalette( widget(), palette ), false ),
|
||||
titlebarContrastColor( background ) );
|
||||
|
||||
}
|
||||
|
||||
// render separators between inactive tabs
|
||||
if( !( active || itemCount == 1 ) )
|
||||
{
|
||||
|
||||
// separators
|
||||
// draw Left separator
|
||||
QColor color( backgroundPalette( widget(), palette ).window().color() );
|
||||
if( index != visibleClientGroupItem() && ( ( index == 0 && buttonsLeftWidth() > 0 ) || itemData_.isTarget( index ) ) )
|
||||
{
|
||||
|
||||
QRect local( item.boundingRect_.topLeft()+QPoint(0,2), QSize( 2, item.boundingRect_.height()-3 ) );
|
||||
helper().drawSeparator( painter, local, color, Qt::Vertical);
|
||||
|
||||
}
|
||||
|
||||
// draw right separator
|
||||
if(
|
||||
( index == itemCount-1 && buttonsRightWidth() > 0 ) ||
|
||||
( index+1 < itemCount && ( itemData_.isTarget( index+1 ) ||
|
||||
index+1 != visibleClientGroupItem() ) ) )
|
||||
{
|
||||
|
||||
QRect local( item.boundingRect_.topRight()+QPoint(0,2), QSize( 2, item.boundingRect_.height()-3 ) );
|
||||
helper().drawSeparator( painter, local, color, Qt::Vertical);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
void OxygenClient::renderTargetRect( QPainter* p, const QPalette& palette )
|
||||
{
|
||||
if( itemData_.targetRect().isNull() || itemData_.timeLineIsRunning() ) return;
|
||||
|
||||
p->save();
|
||||
QColor color = palette.color(QPalette::Highlight);
|
||||
p->setPen(KColorUtils::mix(color, palette.color(QPalette::Active, QPalette::WindowText)));
|
||||
p->setBrush( helper().alphaColor( color, 0.5 ) );
|
||||
p->drawRect( itemData_.targetRect().adjusted( 4, 2, -4, -2 ) );
|
||||
p->restore();
|
||||
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
void OxygenClient::renderFloatFrame( QPainter* painter, const QRect& frame, const QPalette& palette ) const
|
||||
{
|
||||
|
@ -812,7 +1122,7 @@ namespace Oxygen
|
|||
|
||||
if( configuration().drawTitleOutline() )
|
||||
{
|
||||
if( timeLineIsRunning() )
|
||||
if( timeLineIsRunning() && !isForcedActive() )
|
||||
{
|
||||
|
||||
QColor inactiveColor( backgroundColor( widget, palette, false ) );
|
||||
|
@ -821,7 +1131,7 @@ namespace Oxygen
|
|||
palette.setColor( widget->window()->backgroundRole(), mixed );
|
||||
palette.setColor( QPalette::Button, mixed );
|
||||
|
||||
} else if( isActive() ) {
|
||||
} else if( isActive() || isForcedActive() ) {
|
||||
|
||||
QColor color = options()->color( KDecorationDefines::ColorTitleBar, true );
|
||||
palette.setColor( widget->window()->backgroundRole(), color );
|
||||
|
@ -863,30 +1173,75 @@ namespace Oxygen
|
|||
|
||||
}
|
||||
|
||||
|
||||
//___________________________________________
|
||||
void OxygenClient::resetConfiguration( void )
|
||||
//______________________________________________________________________________
|
||||
bool OxygenClient::eventFilter( QObject* object, QEvent* event )
|
||||
{
|
||||
|
||||
if( !initialized_ ) return;
|
||||
// all dedicated event filtering is here to handle multiple tabs.
|
||||
// if tabs are disabled, do nothing
|
||||
if( !configuration().tabsEnabled() )
|
||||
{ return KCommonDecorationUnstable::eventFilter( object, event ); }
|
||||
|
||||
configuration_ = factory_->configuration( *this );
|
||||
|
||||
// animations duration
|
||||
timeLine_.setDuration( configuration_.animationsDuration() );
|
||||
titleTimeLine_.setDuration( configuration_.animationsDuration() );
|
||||
|
||||
// need to update old caption
|
||||
updateOldCaption();
|
||||
|
||||
// handle size grip
|
||||
if( configuration_.drawSizeGrip() )
|
||||
bool state = false;
|
||||
switch( event->type() )
|
||||
{
|
||||
|
||||
if( !hasSizeGrip() ) createSizeGrip();
|
||||
case QEvent::Show:
|
||||
if( widget() == object )
|
||||
{ itemData_.setDirty( true ); }
|
||||
break;
|
||||
|
||||
} else if( hasSizeGrip() ) deleteSizeGrip();
|
||||
case QEvent::MouseButtonPress:
|
||||
if( widget() == object )
|
||||
{ state = mousePressEvent( static_cast< QMouseEvent* >( event ) ); }
|
||||
break;
|
||||
|
||||
case QEvent::MouseButtonRelease:
|
||||
if( widget() == object ) state = mouseReleaseEvent( static_cast< QMouseEvent* >( event ) );
|
||||
else if( OxygenButton *btn = qobject_cast< OxygenButton* >( object ) )
|
||||
{
|
||||
if( static_cast< QMouseEvent* >( event )->button() == Qt::LeftButton )
|
||||
{ state = closeItem( btn ); }
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case QEvent::MouseMove:
|
||||
state = mouseMoveEvent( static_cast< QMouseEvent* >( event ) );
|
||||
break;
|
||||
|
||||
case QEvent::DragEnter:
|
||||
if( widget() == object )
|
||||
{ state = dragEnterEvent( static_cast< QDragEnterEvent* >( event ) ); }
|
||||
break;
|
||||
|
||||
case QEvent::DragMove:
|
||||
if( widget() == object )
|
||||
{ state = dragMoveEvent( static_cast< QDragMoveEvent* >( event ) ); }
|
||||
break;
|
||||
|
||||
case QEvent::DragLeave:
|
||||
if( widget() == object )
|
||||
{ state = dragLeaveEvent( static_cast< QDragLeaveEvent* >( event ) ); }
|
||||
break;
|
||||
|
||||
case QEvent::Drop:
|
||||
if( widget() == object )
|
||||
{ state = dropEvent( static_cast< QDropEvent* >( event ) ); }
|
||||
break;
|
||||
|
||||
default: break;
|
||||
|
||||
}
|
||||
return state || KCommonDecorationUnstable::eventFilter( object, event );
|
||||
|
||||
}
|
||||
|
||||
//_________________________________________________________
|
||||
void OxygenClient::resizeEvent( QResizeEvent* event )
|
||||
{
|
||||
itemData_.setDirty( true );
|
||||
KCommonDecorationUnstable::resizeEvent( event );
|
||||
}
|
||||
|
||||
//_________________________________________________________
|
||||
|
@ -915,7 +1270,7 @@ namespace Oxygen
|
|||
{
|
||||
|
||||
TileSet *tileSet( 0 );
|
||||
if( configuration().useOxygenShadows() && timeLineIsRunning() )
|
||||
if( configuration().useOxygenShadows() && timeLineIsRunning() && !isForcedActive() )
|
||||
{
|
||||
|
||||
int frame = timeLine_.currentFrame();
|
||||
|
@ -969,6 +1324,14 @@ namespace Oxygen
|
|||
|
||||
}
|
||||
|
||||
// make sure ItemData and clientGroupItems are synchronized
|
||||
/*
|
||||
this needs to be done before calling RenderWindowBorder
|
||||
since some painting in there depend on the clientGroups state
|
||||
*/
|
||||
if( itemData_.isDirty() || itemData_.count() != clientGroupItems().count() )
|
||||
{ updateItemBoundingRects( false ); }
|
||||
|
||||
// window background
|
||||
renderWindowBackground( &painter, frame, widget(), backgroundPalette( widget(), palette ) );
|
||||
renderWindowBorder( &painter, frame, widget(), palette );
|
||||
|
@ -985,13 +1348,9 @@ namespace Oxygen
|
|||
painter.save();
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
|
||||
// float frame
|
||||
renderFloatFrame( &painter, frame, palette );
|
||||
|
||||
// clipping
|
||||
if( compositingActive() ) painter.setClipping(false);
|
||||
|
||||
// resize handles
|
||||
renderDots( &painter, frame, QColor(0, 0, 0, 66) );
|
||||
painter.restore();
|
||||
|
@ -1002,27 +1361,335 @@ namespace Oxygen
|
|||
|
||||
// title bounding rect
|
||||
painter.setFont( options()->font(isActive(), false) );
|
||||
QRect boundingRect( titleBoundingRect( &painter, caption() ) );
|
||||
if( isActive() && configuration().drawTitleOutline() )
|
||||
{
|
||||
renderTitleOutline( &painter, boundingRect.adjusted(
|
||||
-layoutMetric( LM_TitleBorderLeft ),
|
||||
-layoutMetric( LM_TitleEdgeTop ),
|
||||
layoutMetric( LM_TitleBorderRight ), 0 ), palette );
|
||||
}
|
||||
|
||||
// title text
|
||||
renderTitleText( &painter, boundingRect,
|
||||
titlebarTextColor( palette ),
|
||||
titlebarContrastColor( palette ) );
|
||||
// draw ClientGroupItems
|
||||
int itemCount( itemData_.count() );
|
||||
for( int i = 0; i < itemCount; i++ ) renderItem( &painter, i, palette );
|
||||
|
||||
// draw target rect
|
||||
renderTargetRect( &painter, widget()->palette() );
|
||||
|
||||
// separator
|
||||
if( drawSeparator() ) renderSeparator(&painter, frame, widget(), color );
|
||||
if( itemCount == 1 && !itemData_.animated() && drawSeparator() )
|
||||
{ renderSeparator(&painter, frame, widget(), color ); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//_____________________________________________________________
|
||||
bool OxygenClient::mousePressEvent( QMouseEvent* event )
|
||||
{
|
||||
|
||||
QPoint point = event->pos();
|
||||
if( itemClicked( point ) < 0 ) return false;
|
||||
|
||||
bool accepted( false );
|
||||
if( event->button() == Qt::MidButton )
|
||||
{
|
||||
|
||||
dragPoint_ = point;
|
||||
mouseButton_ = Qt::MidButton;
|
||||
accepted = true;
|
||||
|
||||
} else if( event->button() == Qt::LeftButton ) {
|
||||
|
||||
mouseButton_ = Qt::LeftButton;
|
||||
|
||||
} else if( event->button() == Qt::RightButton ) {
|
||||
|
||||
mouseButton_ = Qt::RightButton;
|
||||
accepted = true;
|
||||
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
|
||||
//_____________________________________________________________
|
||||
bool OxygenClient::mouseReleaseEvent( QMouseEvent* event )
|
||||
{
|
||||
|
||||
bool accepted( false );
|
||||
if( ( mouseButton_ == Qt::LeftButton && event->button() == Qt::LeftButton ) ||
|
||||
( mouseButton_ == Qt::MidButton && event->button() == Qt::MidButton ) )
|
||||
{
|
||||
|
||||
QPoint point = event->pos();
|
||||
|
||||
int visibleItem = visibleClientGroupItem();
|
||||
int itemClicked( OxygenClient::itemClicked( point ) );
|
||||
if( itemClicked >= 0 && visibleItem != itemClicked )
|
||||
{
|
||||
setVisibleClientGroupItem( itemClicked );
|
||||
setForceActive( true );
|
||||
accepted = true;
|
||||
}
|
||||
|
||||
} else if( mouseButton_ == Qt::RightButton && event->button() == Qt::RightButton ) {
|
||||
|
||||
QPoint point = event->pos();
|
||||
int itemClicked( OxygenClient::itemClicked( point ) );
|
||||
displayClientMenu( itemClicked, widget()->mapToGlobal( event->pos() ) );
|
||||
|
||||
}
|
||||
|
||||
mouseButton_ = Qt::NoButton;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
//_____________________________________________________________
|
||||
bool OxygenClient::mouseMoveEvent( QMouseEvent* event )
|
||||
{
|
||||
|
||||
// check button and distance to drag point
|
||||
if( configuration().hideTitleBar() || mouseButton_ == Qt::NoButton || ( event->pos() - dragPoint_ ).manhattanLength() <= QApplication::startDragDistance() )
|
||||
{ return false; }
|
||||
|
||||
bool accepted( false );
|
||||
if( mouseButton_ == Qt::MidButton )
|
||||
{
|
||||
|
||||
QPoint point = event->pos();
|
||||
int itemClicked( OxygenClient::itemClicked( point ) );
|
||||
if( itemClicked < 0 ) return false;
|
||||
|
||||
QDrag *drag = new QDrag( widget() );
|
||||
QMimeData *groupData = new QMimeData();
|
||||
groupData->setData( clientGroupItemDragMimeType(), QString().setNum( itemId( itemClicked )).toAscii() );
|
||||
drag->setMimeData( groupData );
|
||||
sourceItem_ = OxygenClient::itemClicked( dragPoint_ );
|
||||
|
||||
// get tab geometry
|
||||
QRect geometry;
|
||||
geometry = itemData_[itemClicked].boundingRect_;
|
||||
|
||||
// remove space used for buttons
|
||||
if( itemData_.count() >= 0 )
|
||||
{ geometry.adjust( 0, 0, - configuration().buttonSize() - layoutMetric(LM_TitleEdgeRight), 0 ); }
|
||||
|
||||
drag->setPixmap( itemDragPixmap( itemClicked, geometry ) );
|
||||
|
||||
// note: the pixmap is moved just above the pointer on purpose
|
||||
// because overlapping pixmap and pointer slows down the pixmap alot.
|
||||
//drag->setHotSpot( QPoint( event->pos().x() - geometry.left(), geometry.height() ) );
|
||||
drag->setHotSpot( QPoint( event->pos().x() - geometry.left(), -1 ) );
|
||||
drag->exec( Qt::MoveAction );
|
||||
|
||||
// detach tab from window
|
||||
if( drag->target() == 0 && itemData_.count() > 1 )
|
||||
{
|
||||
removeFromClientGroup( sourceItem_,
|
||||
widget()->frameGeometry().adjusted(
|
||||
layoutMetric( LM_OuterPaddingLeft ),
|
||||
layoutMetric( LM_OuterPaddingTop ),
|
||||
-layoutMetric( LM_OuterPaddingRight ),
|
||||
-layoutMetric( LM_OuterPaddingBottom )
|
||||
).translated( QCursor::pos() - event->pos() +
|
||||
QPoint( layoutMetric( LM_OuterPaddingLeft ), layoutMetric( LM_OuterPaddingTop )))
|
||||
);
|
||||
}
|
||||
|
||||
accepted = true;
|
||||
|
||||
}
|
||||
|
||||
// reset button
|
||||
mouseButton_ = Qt::NoButton;
|
||||
return accepted;
|
||||
|
||||
}
|
||||
|
||||
//_____________________________________________________________
|
||||
bool OxygenClient::dragEnterEvent( QDragEnterEvent* event )
|
||||
{
|
||||
|
||||
// check if drag enter is allowed
|
||||
if( !event->mimeData()->hasFormat( clientGroupItemDragMimeType() ) || configuration().hideTitleBar() ) return false;
|
||||
|
||||
//
|
||||
event->acceptProposedAction();
|
||||
if( event->source() != widget() )
|
||||
{
|
||||
|
||||
QPoint position( event->pos() );
|
||||
itemData_.animate( AnimationEnter, itemClicked( position, true ) );
|
||||
|
||||
} else if( itemData_.count() > 1 ) {
|
||||
|
||||
QPoint position( event->pos() );
|
||||
int itemClicked( OxygenClient::itemClicked( position, false ) );
|
||||
itemData_.animate( AnimationTypes( AnimationEnter|AnimationSameTarget ), itemClicked );
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//_____________________________________________________________
|
||||
bool OxygenClient::dragLeaveEvent( QDragLeaveEvent* )
|
||||
{
|
||||
|
||||
if( itemData_.animationType() & AnimationSameTarget )
|
||||
{
|
||||
|
||||
itemData_.animate( Oxygen::AnimationTypes(AnimationLeave|AnimationSameTarget), sourceItem_ );
|
||||
|
||||
} else if( itemData_.animated() ) {
|
||||
|
||||
|
||||
itemData_.animate( AnimationLeave );
|
||||
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//_____________________________________________________________
|
||||
bool OxygenClient::dragMoveEvent( QDragMoveEvent* event )
|
||||
{
|
||||
|
||||
// check format
|
||||
if( !event->mimeData()->hasFormat( clientGroupItemDragMimeType() ) ) return false;
|
||||
if( event->source() != widget() )
|
||||
{
|
||||
|
||||
QPoint position( event->pos() );
|
||||
itemData_.animate( AnimationMove, itemClicked( position, true ) );
|
||||
|
||||
} else if( itemData_.count() > 1 ) {
|
||||
|
||||
QPoint position( event->pos() );
|
||||
int itemClicked( OxygenClient::itemClicked( position, false ) );
|
||||
itemData_.animate( AnimationTypes( AnimationMove|AnimationSameTarget ), itemClicked );
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
//_____________________________________________________________
|
||||
bool OxygenClient::dropEvent( QDropEvent* event )
|
||||
{
|
||||
|
||||
QPoint point = event->pos();
|
||||
itemData_.animate( AnimationNone );
|
||||
|
||||
const QMimeData *groupData = event->mimeData();
|
||||
if( !groupData->hasFormat( clientGroupItemDragMimeType() ) ) return false;
|
||||
|
||||
if( widget() == event->source() )
|
||||
{
|
||||
|
||||
int from = OxygenClient::itemClicked( dragPoint_ );
|
||||
int itemClicked( OxygenClient::itemClicked( point, false ) );
|
||||
|
||||
if( itemClicked > from )
|
||||
{
|
||||
itemClicked++;
|
||||
if( itemClicked >= clientGroupItems().count() )
|
||||
{ itemClicked = -1; }
|
||||
}
|
||||
|
||||
moveItemInClientGroup( from, itemClicked );
|
||||
itemData_.setDirty( true );
|
||||
widget()->update();
|
||||
|
||||
} else {
|
||||
|
||||
setForceActive( true );
|
||||
int itemClicked( OxygenClient::itemClicked( point, true ) );
|
||||
int source = QString( groupData->data( clientGroupItemDragMimeType() ) ).toInt();
|
||||
moveItemToClientGroup( source, itemClicked );
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//_____________________________________________________________
|
||||
bool OxygenClient::closeItem( const OxygenButton* button )
|
||||
{
|
||||
|
||||
for( int i=0; i < itemData_.count(); i++ )
|
||||
{
|
||||
if( button == itemData_[i].closeButton_.data() )
|
||||
{
|
||||
closeClientGroupItem( i );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
//________________________________________________________________
|
||||
QPixmap OxygenClient::itemDragPixmap( int index, const QRect& geometry )
|
||||
{
|
||||
bool itemValid( index >= 0 && index < clientGroupItems().count() );
|
||||
|
||||
QPixmap pixmap( geometry.size() );
|
||||
QPainter painter( &pixmap );
|
||||
painter.setRenderHints(QPainter::SmoothPixmapTransform|QPainter::Antialiasing);
|
||||
|
||||
painter.translate( -geometry.topLeft() );
|
||||
|
||||
// render window background
|
||||
renderWindowBackground( &painter, geometry, widget(), widget()->palette() );
|
||||
|
||||
// darken background if item is inactive
|
||||
bool itemActive = !( itemValid && index != visibleClientGroupItem() );
|
||||
if( !itemActive )
|
||||
{
|
||||
|
||||
QLinearGradient lg( geometry.topLeft(), geometry.bottomLeft() );
|
||||
lg.setColorAt( 0, helper().alphaColor( Qt::black, 0.05 ) );
|
||||
lg.setColorAt( 1, helper().alphaColor( Qt::black, 0.10 ) );
|
||||
painter.setBrush( lg );
|
||||
painter.setPen( Qt::NoPen );
|
||||
painter.drawRect( geometry );
|
||||
|
||||
}
|
||||
|
||||
// render title text
|
||||
painter.setFont( options()->font(isActive(), false) );
|
||||
QRect textRect( geometry.adjusted( 0, layoutMetric( LM_TitleEdgeTop )-1, 0, -1 ) );
|
||||
|
||||
if( itemValid )
|
||||
{ textRect.adjust( layoutMetric( LM_TitleBorderLeft ), 0, -layoutMetric(LM_TitleBorderRight), 0 ); }
|
||||
|
||||
QString caption( itemValid ? clientGroupItems()[index].title() : OxygenClient::caption() );
|
||||
renderTitleText( &painter, textRect, caption, titlebarTextColor( widget()->palette(), isActive() && itemActive ) );
|
||||
|
||||
// floating frame
|
||||
helper().drawFloatFrame(
|
||||
&painter, geometry, widget()->palette().window().color(),
|
||||
true, false,
|
||||
KDecoration::options()->color(ColorTitleBar)
|
||||
);
|
||||
|
||||
painter.end();
|
||||
|
||||
// create pixmap mask
|
||||
QBitmap bitmap( geometry.size() );
|
||||
{
|
||||
bitmap.clear();
|
||||
QPainter painter( &bitmap );
|
||||
QPainterPath path;
|
||||
path.addRegion( helper().roundedMask( geometry.translated( -geometry.topLeft() ) ) );
|
||||
painter.fillPath( path, Qt::color1 );
|
||||
}
|
||||
|
||||
pixmap.setMask( bitmap );
|
||||
return pixmap;
|
||||
|
||||
}
|
||||
|
||||
//_________________________________________________________________
|
||||
void OxygenClient::createSizeGrip( void )
|
||||
{
|
||||
|
|
|
@ -28,13 +28,15 @@
|
|||
// IN THE SOFTWARE.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <kcommondecoration.h>
|
||||
#include <QtCore/QTimeLine>
|
||||
|
||||
#include "oxygen.h"
|
||||
#include "oxygenclientgroupitemdata.h"
|
||||
#include "oxygenconfiguration.h"
|
||||
#include "lib/helper.h"
|
||||
|
||||
#include <kcommondecoration.h>
|
||||
#include <QtCore/QTimeLine>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
namespace Oxygen
|
||||
{
|
||||
|
||||
|
@ -72,6 +74,10 @@ namespace Oxygen
|
|||
bool timeLineIsRunning( void ) const
|
||||
{ return timeLine_.state() == QTimeLine::Running; }
|
||||
|
||||
//! true when decoration is forced active
|
||||
bool isForcedActive( void ) const
|
||||
{ return forceActive_ && clientGroupItems().count() > 1; }
|
||||
|
||||
//! true when separator is to be drawn
|
||||
bool drawSeparator( void ) const
|
||||
{
|
||||
|
@ -124,18 +130,18 @@ namespace Oxygen
|
|||
virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton * = 0) const;
|
||||
|
||||
//! get title bounding rect
|
||||
virtual QRect titleBoundingRect( QPainter* painter, const QString& caption ) const
|
||||
{ return titleBoundingRect( painter, titleRect(), caption ); }
|
||||
virtual QRect titleBoundingRect( const QFont& font, const QString& caption ) const
|
||||
{ return titleBoundingRect( font, titleRect(), caption ); }
|
||||
|
||||
//! get title bounding rect
|
||||
virtual QRect titleBoundingRect( QPainter*, const QRect&, const QString& ) const;
|
||||
virtual QRect titleBoundingRect( const QFont&, QRect, const QString& ) const;
|
||||
|
||||
//! palette background
|
||||
QPalette backgroundPalette( const QWidget*, QPalette ) const;
|
||||
|
||||
//! background
|
||||
QColor backgroundColor( const QWidget* widget, QPalette palette ) const
|
||||
{ return backgroundColor( widget, palette, isActive() ); }
|
||||
{ return backgroundColor( widget, palette, isActive() || isForcedActive() ); }
|
||||
|
||||
//! background
|
||||
QColor backgroundColor( const QWidget*, QPalette, bool ) const;
|
||||
|
@ -165,16 +171,48 @@ namespace Oxygen
|
|||
|
||||
//@}
|
||||
|
||||
public slots:
|
||||
//! event filter
|
||||
virtual bool eventFilter( QObject*, QEvent* );
|
||||
|
||||
//! reset configuration
|
||||
void resetConfiguration( void );
|
||||
//! resize event
|
||||
virtual void resizeEvent(QResizeEvent *e);
|
||||
|
||||
protected:
|
||||
|
||||
//! true when decoration is forced active
|
||||
void setForceActive( bool value )
|
||||
{ forceActive_ = value; }
|
||||
|
||||
|
||||
//!@name event filters
|
||||
//@{
|
||||
|
||||
//! paint
|
||||
virtual void paintEvent( QPaintEvent* );
|
||||
|
||||
//! mouse press event
|
||||
virtual bool mousePressEvent( QMouseEvent* );
|
||||
|
||||
//! mouse release event
|
||||
virtual bool mouseReleaseEvent( QMouseEvent* );
|
||||
|
||||
//! mouse move event
|
||||
virtual bool mouseMoveEvent( QMouseEvent* );
|
||||
|
||||
//! drag enter event
|
||||
virtual bool dragEnterEvent( QDragEnterEvent* );
|
||||
|
||||
//! drag move event
|
||||
virtual bool dragMoveEvent( QDragMoveEvent* );
|
||||
|
||||
//! drag leave event
|
||||
virtual bool dragLeaveEvent( QDragLeaveEvent* );
|
||||
|
||||
//! drop event
|
||||
virtual bool dropEvent( QDropEvent* );
|
||||
|
||||
//@}
|
||||
|
||||
//!@name rendering methods (called in paintEvent)
|
||||
//@{
|
||||
|
||||
|
@ -199,6 +237,12 @@ namespace Oxygen
|
|||
/*! second color, if valid, is for contrast pixel */
|
||||
virtual void renderTitleText( QPainter*, const QRect&, const QString&, const QColor&, const QColor& = QColor() ) const;
|
||||
|
||||
//! GroupItem
|
||||
virtual void renderItem( QPainter*, int, const QPalette& );
|
||||
|
||||
//! tabbing target rect
|
||||
virtual void renderTargetRect( QPainter*, const QPalette& );
|
||||
|
||||
//! render float frame
|
||||
virtual void renderFloatFrame( QPainter*, const QRect&, const QPalette& ) const;
|
||||
|
||||
|
@ -207,6 +251,16 @@ namespace Oxygen
|
|||
|
||||
//@}
|
||||
|
||||
//! close tab matching give button
|
||||
virtual bool closeItem( const OxygenButton* );
|
||||
|
||||
//! index of item matching point
|
||||
int itemClicked( const QPoint& position, bool between = false ) const
|
||||
{ return itemData_.itemAt( position , between ); }
|
||||
|
||||
//! return pixmap corresponding to a given tab, for dragging
|
||||
QPixmap itemDragPixmap( int, const QRect& );
|
||||
|
||||
//! title timeline
|
||||
bool titleTimeLineIsRunning( void ) const
|
||||
{ return titleTimeLine_.state() == QTimeLine::Running; }
|
||||
|
@ -247,7 +301,12 @@ namespace Oxygen
|
|||
QColor titlebarTextColor(const QPalette&, bool active);
|
||||
|
||||
//! text color
|
||||
QColor titlebarContrastColor(const QPalette&);
|
||||
QColor titlebarContrastColor(const QPalette& palette ) const
|
||||
{ return titlebarContrastColor( palette.color( widget()->window()->backgroundRole() ) ); }
|
||||
|
||||
//! text color
|
||||
QColor titlebarContrastColor(const QColor& color ) const
|
||||
{ return helper().calcLightColor( color ); }
|
||||
|
||||
//!@name size grip
|
||||
//@{
|
||||
|
@ -274,6 +333,17 @@ namespace Oxygen
|
|||
void updateOldCaption( void )
|
||||
{ setOldCaption( caption() ); }
|
||||
|
||||
//! set target item to -1
|
||||
void clearTargetItem( void );
|
||||
|
||||
//! clear force active flag
|
||||
void clearForceActive( void )
|
||||
{ if( isActive() ) setForceActive( false ); }
|
||||
|
||||
//! title bounding rects
|
||||
/*! calculate and return title bounding rects in case of tabbed window */
|
||||
void updateItemBoundingRects( bool alsoUpdate = true );
|
||||
|
||||
private:
|
||||
|
||||
//! factory
|
||||
|
@ -297,6 +367,21 @@ namespace Oxygen
|
|||
//! true when initialized
|
||||
bool initialized_;
|
||||
|
||||
//! true when decoration is forced active
|
||||
bool forceActive_;
|
||||
|
||||
//! mouse button
|
||||
Qt::MouseButton mouseButton_;
|
||||
|
||||
//! tab bounding rects
|
||||
ClientGroupItemDataList itemData_;
|
||||
|
||||
//! index of tab being dragged if any, -1 otherwise
|
||||
int sourceItem_;
|
||||
|
||||
//! drag start point
|
||||
QPoint dragPoint_;
|
||||
|
||||
};
|
||||
|
||||
//!@name utility functions
|
||||
|
|
|
@ -0,0 +1,320 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// oxygenclientgroupitemdata.cpp
|
||||
// -------------------
|
||||
//
|
||||
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||
// Copyright (c) 2003, 2004 David Johnson <david@usermode.org>
|
||||
// Copyright (c) 2006, 2007 Riccardo Iaconelli <ruphy@fsfe.org>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "oxygenclientgroupitemdata.h"
|
||||
#include "oxygenclientgroupitemdata.moc"
|
||||
#include "oxygenclient.h"
|
||||
#include "oxygen.h"
|
||||
|
||||
namespace Oxygen
|
||||
{
|
||||
|
||||
//____________________________________________________________________________
|
||||
ClientGroupItemDataList::ClientGroupItemDataList( OxygenClient* parent ):
|
||||
QObject( parent ),
|
||||
QList<ClientGroupItemData>(),
|
||||
client_( *parent ),
|
||||
timeLine_( 150, this ),
|
||||
animationType_( AnimationNone ),
|
||||
draggedItem_( NoItem ),
|
||||
targetItem_( NoItem )
|
||||
{
|
||||
timeLine_.setFrameRange( 0, maxAnimationIndex );
|
||||
timeLine_.setCurveShape( QTimeLine::EaseInOutCurve );
|
||||
connect( &timeLine_, SIGNAL( frameChanged( int ) ), this, SLOT( updateBoundingRects() ) );
|
||||
connect( &timeLine_, SIGNAL( finished() ), this, SLOT( updateBoundingRects() ) );
|
||||
}
|
||||
|
||||
//________________________________________________________________
|
||||
int ClientGroupItemDataList::itemAt( const QPoint& point, bool between ) const
|
||||
{
|
||||
|
||||
for( int i=0; i < count(); i++ )
|
||||
{
|
||||
QRect rect = at(i).activeRect_;
|
||||
if( between ) rect.translate( -rect.width() / 2, 0 );
|
||||
if( rect.adjusted(0,0,0,2).contains( point ) )
|
||||
{ return i; }
|
||||
}
|
||||
|
||||
return NoItem;
|
||||
|
||||
}
|
||||
|
||||
//____________________________________________________________________________
|
||||
void ClientGroupItemDataList::animate( AnimationTypes type, int target )
|
||||
{
|
||||
|
||||
// store animation type
|
||||
animationType_ = type;
|
||||
|
||||
if( type == AnimationNone )
|
||||
{
|
||||
|
||||
if( timeLineIsRunning() ) timeLine().stop();
|
||||
targetItem_ = NoItem;
|
||||
draggedItem_ = NoItem;
|
||||
targetRect_ = QRect();
|
||||
|
||||
} else if( type & (AnimationEnter|AnimationMove ) ) {
|
||||
|
||||
// store dragged item
|
||||
bool animate( true );
|
||||
|
||||
if( (type&AnimationSameTarget) && draggedItem_ == NoItem )
|
||||
{
|
||||
|
||||
animate = false;
|
||||
draggedItem_ = target;
|
||||
|
||||
} else if( (type&AnimationMove) && targetItem_ == target ) return;
|
||||
|
||||
// check timeLine
|
||||
if( timeLineIsRunning() ) timeLine().stop();
|
||||
|
||||
targetItem_ = target;
|
||||
targetRect_ = QRect();
|
||||
QRect titleRect( client_.titleRect() );
|
||||
int left( titleRect.left() );
|
||||
int width = (type&AnimationSameTarget) ?
|
||||
titleRect.width()/count():
|
||||
titleRect.width()/(count()+1);
|
||||
|
||||
if( (type&AnimationSameTarget) && draggedItem_ < target )
|
||||
{
|
||||
target++;
|
||||
if( target >= count() ) target = NoItem;
|
||||
}
|
||||
|
||||
// loop over items and update bounding rects
|
||||
for( int index = 0; index < count(); index++ )
|
||||
{
|
||||
|
||||
ClientGroupItemData& item( ClientGroupItemDataList::operator[](index) );
|
||||
if( index == target )
|
||||
{
|
||||
targetRect_ = item.refBoundingRect_;
|
||||
targetRect_.setLeft( left );
|
||||
targetRect_.setWidth( width );
|
||||
left+=width;
|
||||
}
|
||||
|
||||
item.startBoundingRect_ = item.boundingRect_;
|
||||
item.endBoundingRect_ = item.refBoundingRect_;
|
||||
item.endBoundingRect_.setLeft( left );
|
||||
|
||||
if( !( (type&AnimationSameTarget) && index == draggedItem_ ) )
|
||||
{
|
||||
|
||||
item.endBoundingRect_.setWidth( width );
|
||||
left+=width;
|
||||
|
||||
} else {
|
||||
|
||||
item.endBoundingRect_.setWidth( 0 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( targetRect_.isNull() )
|
||||
{
|
||||
targetRect_ = back().refBoundingRect_;
|
||||
targetRect_.setLeft( left );
|
||||
targetRect_.setWidth( width );
|
||||
}
|
||||
|
||||
if( animate ) timeLine().start();
|
||||
else {
|
||||
|
||||
for( int index = 0; index < count(); index++ )
|
||||
{
|
||||
ClientGroupItemData& item( ClientGroupItemDataList::operator[](index) );
|
||||
item.boundingRect_ = item.endBoundingRect_;
|
||||
}
|
||||
|
||||
updateButtons( true );
|
||||
|
||||
}
|
||||
|
||||
} else if( type & AnimationLeave ) {
|
||||
|
||||
// stop timeLine
|
||||
if( timeLineIsRunning() ) timeLine().stop();
|
||||
|
||||
// reset target
|
||||
targetItem_ = NoItem;
|
||||
targetRect_ = QRect();
|
||||
|
||||
if( type & AnimationSameTarget )
|
||||
{
|
||||
|
||||
// store dragged item
|
||||
draggedItem_ = target;
|
||||
|
||||
// do nothing if only one item
|
||||
if( count() <= 1 ) return;
|
||||
|
||||
QRect titleRect( client_.titleRect() );
|
||||
int left( titleRect.left() );
|
||||
int width = titleRect.width()/(count()-1);
|
||||
|
||||
// loop over items and update bounding rects
|
||||
for( int index = 0; index < count(); index++ )
|
||||
{
|
||||
|
||||
ClientGroupItemData& item( ClientGroupItemDataList::operator[](index) );
|
||||
item.startBoundingRect_ = item.boundingRect_;
|
||||
item.endBoundingRect_ = item.refBoundingRect_;
|
||||
item.endBoundingRect_.setLeft( left );
|
||||
if( index != target )
|
||||
{
|
||||
|
||||
item.endBoundingRect_.setWidth( width );
|
||||
left+=width;
|
||||
|
||||
} else {
|
||||
|
||||
item.endBoundingRect_.setWidth( 0 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// loop over items and update bounding rects
|
||||
for( int index = 0; index < count(); index++ )
|
||||
{
|
||||
ClientGroupItemData& item( ClientGroupItemDataList::operator[](index) );
|
||||
item.startBoundingRect_ = item.boundingRect_;
|
||||
item.endBoundingRect_ = item.refBoundingRect_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
timeLine().start();
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
//____________________________________________________________________________
|
||||
void ClientGroupItemDataList::updateButtonActivity( int visibleItem ) const
|
||||
{
|
||||
|
||||
for( int index = 0; index < count(); index++ )
|
||||
{
|
||||
|
||||
const ClientGroupItemData& item( at(index) );
|
||||
if( item.closeButton_ )
|
||||
{ item.closeButton_.data()->setForceInactive( index != visibleItem ); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//____________________________________________________________________________
|
||||
void ClientGroupItemDataList::updateButtons( bool alsoUpdate ) const
|
||||
{
|
||||
|
||||
// move close buttons
|
||||
// this should move to ClientGroupItemDataList
|
||||
if( alsoUpdate ) client_.widget()->setUpdatesEnabled( false );
|
||||
for( int index = 0; index < count(); index++ )
|
||||
{
|
||||
|
||||
const ClientGroupItemData& item( at(index) );
|
||||
if( !item.closeButton_ ) continue;
|
||||
|
||||
if( !item.boundingRect_.isValid() ) {
|
||||
|
||||
item.closeButton_.data()->hide();
|
||||
|
||||
} else {
|
||||
|
||||
QPoint position(
|
||||
item.boundingRect_.right() - client_.configuration().buttonSize() - client_.layoutMetric(KCommonDecoration::LM_TitleEdgeRight),
|
||||
item.boundingRect_.top() + client_.layoutMetric( KCommonDecoration::LM_TitleEdgeTop ) );
|
||||
|
||||
if( item.closeButton_.data()->isHidden() ) item.closeButton_.data()->show();
|
||||
item.closeButton_.data()->move( position );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( alsoUpdate )
|
||||
{
|
||||
client_.widget()->setUpdatesEnabled( true );
|
||||
client_.widget()->update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//____________________________________________________________________________
|
||||
void ClientGroupItemDataList::updateBoundingRects( bool alsoUpdate )
|
||||
{
|
||||
|
||||
qreal ratio( ClientGroupItemDataList::ratio() );
|
||||
for( iterator iter = begin(); iter != end(); iter++ )
|
||||
{
|
||||
|
||||
// left
|
||||
if( iter->endBoundingRect_.left() == iter->startBoundingRect_.left() )
|
||||
{
|
||||
|
||||
iter->boundingRect_.setLeft( iter->startBoundingRect_.left() );
|
||||
|
||||
} else {
|
||||
|
||||
iter->boundingRect_.setLeft( (1.0-ratio)*iter->startBoundingRect_.left() + ratio*iter->endBoundingRect_.left() );
|
||||
|
||||
}
|
||||
|
||||
// right
|
||||
if( iter->endBoundingRect_.right() == iter->startBoundingRect_.right() )
|
||||
{
|
||||
|
||||
iter->boundingRect_.setRight( iter->startBoundingRect_.right() );
|
||||
|
||||
} else {
|
||||
|
||||
iter->boundingRect_.setRight( (1.0-ratio)*iter->startBoundingRect_.right() + ratio*iter->endBoundingRect_.right() );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// update button position
|
||||
updateButtons( alsoUpdate );
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
#ifndef oxygenclientgroupitemdata_h
|
||||
#define oxygenclientgroupitemdata_h
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// oxygenclientgroupitemdata.h
|
||||
// -------------------
|
||||
//
|
||||
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||
// Copyright (c) 2003, 2004 David Johnson <david@usermode.org>
|
||||
// Copyright (c) 2006, 2007 Riccardo Iaconelli <ruphy@fsfe.org>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "oxygenbutton.h"
|
||||
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QWeakPointer>
|
||||
#include <QtCore/QRect>
|
||||
#include <QtCore/QTimeLine>
|
||||
|
||||
namespace Oxygen
|
||||
{
|
||||
|
||||
class OxygenClient;
|
||||
|
||||
//! animation type
|
||||
enum AnimationType
|
||||
{
|
||||
AnimationNone = 0,
|
||||
AnimationEnter = 1<<0,
|
||||
AnimationMove = 1<<1,
|
||||
AnimationLeave = 1<<2,
|
||||
AnimationSameTarget = 1<<3
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(AnimationTypes, AnimationType)
|
||||
|
||||
//! tab data
|
||||
class ClientGroupItemData
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
explicit ClientGroupItemData( void )
|
||||
{}
|
||||
|
||||
//! destructor
|
||||
virtual ~ClientGroupItemData( void )
|
||||
{}
|
||||
|
||||
//! reset all rects to argument
|
||||
void reset( const QRect& rect )
|
||||
{
|
||||
refBoundingRect_ = rect;
|
||||
startBoundingRect_ = rect;
|
||||
endBoundingRect_ = rect;
|
||||
boundingRect_ = rect;
|
||||
}
|
||||
|
||||
//! tab active rect
|
||||
QRect activeRect_;
|
||||
|
||||
//! reference bounding rect
|
||||
/*! it is usually identical to activeRect unless there is only one tab in window */
|
||||
QRect refBoundingRect_;
|
||||
|
||||
//! tab drawing rect
|
||||
QRect startBoundingRect_;
|
||||
|
||||
//! tab drawing rect
|
||||
QRect endBoundingRect_;
|
||||
|
||||
//! tab drawing rect
|
||||
QRect boundingRect_;
|
||||
|
||||
//! tab button
|
||||
typedef QWeakPointer<OxygenButton> ButtonPointer;
|
||||
ButtonPointer closeButton_;
|
||||
|
||||
};
|
||||
|
||||
class ClientGroupItemDataList: public QObject, public QList<ClientGroupItemData>
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
//! invalid item index
|
||||
enum { NoItem = -1 };
|
||||
|
||||
//! constructor
|
||||
ClientGroupItemDataList( OxygenClient* parent );
|
||||
|
||||
//! dirty state
|
||||
void setDirty( const bool& value )
|
||||
{ dirty_ = value; }
|
||||
|
||||
//! dirty state
|
||||
bool isDirty( void ) const
|
||||
{ return dirty_; }
|
||||
|
||||
//! true if being animated
|
||||
bool animated( void ) const
|
||||
{ return animationType_ != AnimationNone; }
|
||||
|
||||
//! animation type
|
||||
AnimationTypes animationType( void ) const
|
||||
{ return animationType_; }
|
||||
|
||||
//! return item index matching QPoint, or -1 if none
|
||||
int itemAt( const QPoint&, bool ) const;
|
||||
|
||||
//! returns true if index is target
|
||||
bool isTarget( int index ) const
|
||||
{ return index == targetItem_; }
|
||||
|
||||
//! start animation
|
||||
/* might need to add the side of the target here */
|
||||
void animate( AnimationTypes, int = NoItem );
|
||||
|
||||
//! update button activity
|
||||
void updateButtonActivity( int visibleItem ) const;
|
||||
|
||||
//! update buttons
|
||||
void updateButtons( bool alsoUpdate ) const;
|
||||
|
||||
//! get timeLine
|
||||
const QTimeLine& timeLine( void ) const
|
||||
{ return timeLine_; }
|
||||
|
||||
//! get timeLine
|
||||
QTimeLine& timeLine( void )
|
||||
{ return timeLine_; }
|
||||
|
||||
//! true if timeLine is running
|
||||
bool timeLineIsRunning( void ) const
|
||||
{ return timeLine().state() == QTimeLine::Running; }
|
||||
|
||||
//! target rect
|
||||
const QRect& targetRect( void ) const
|
||||
{ return targetRect_; }
|
||||
|
||||
protected slots:
|
||||
|
||||
//! update bounding rects
|
||||
void updateBoundingRects( bool alsoUpdate = true );
|
||||
|
||||
protected:
|
||||
|
||||
//! timeLine ratio
|
||||
qreal ratio( void )
|
||||
{ return qreal( timeLine().currentFrame() ) / qreal( timeLine().endFrame() ); }
|
||||
|
||||
private:
|
||||
|
||||
//! client
|
||||
OxygenClient& client_;
|
||||
|
||||
//! dirty flag
|
||||
/* used to trigger update at next paintEvent */
|
||||
bool dirty_;
|
||||
|
||||
//! animation timeline
|
||||
QTimeLine timeLine_;
|
||||
|
||||
//! last animation
|
||||
AnimationTypes animationType_;
|
||||
|
||||
//! dragged item
|
||||
int draggedItem_;
|
||||
|
||||
//! target item
|
||||
int targetItem_;
|
||||
|
||||
//! target rect
|
||||
QRect targetRect_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -43,6 +43,7 @@ namespace Oxygen
|
|||
useOxygenShadows_( true ),
|
||||
useAnimations_( true ),
|
||||
animationsDuration_( 150 ),
|
||||
tabsEnabled_( true ),
|
||||
useNarrowButtonSpacing_( false )
|
||||
{}
|
||||
|
||||
|
@ -108,10 +109,16 @@ namespace Oxygen
|
|||
OxygenConfig::ANIMATIONS_DURATION,
|
||||
defaultConfiguration.animationsDuration() ) );
|
||||
|
||||
// tabbing
|
||||
setTabsEnabled( group.readEntry(
|
||||
OxygenConfig::TABS_ENABLED,
|
||||
defaultConfiguration.tabsEnabled() ) );
|
||||
|
||||
// buttonSpacing
|
||||
setUseNarrowButtonSpacing( group.readEntry(
|
||||
OxygenConfig::NARROW_BUTTON_SPACING,
|
||||
defaultConfiguration.useNarrowButtonSpacing() ) );
|
||||
|
||||
}
|
||||
|
||||
//__________________________________________________
|
||||
|
@ -130,7 +137,9 @@ namespace Oxygen
|
|||
group.writeEntry( OxygenConfig::USE_OXYGEN_SHADOWS, useOxygenShadows() );
|
||||
group.writeEntry( OxygenConfig::USE_ANIMATIONS, useAnimations() );
|
||||
group.writeEntry( OxygenConfig::ANIMATIONS_DURATION, animationsDuration() );
|
||||
group.writeEntry( OxygenConfig::TABS_ENABLED, tabsEnabled() );
|
||||
group.writeEntry( OxygenConfig::NARROW_BUTTON_SPACING, useNarrowButtonSpacing() );
|
||||
|
||||
}
|
||||
|
||||
//__________________________________________________
|
||||
|
@ -298,6 +307,7 @@ namespace Oxygen
|
|||
useOxygenShadows() == other.useOxygenShadows() &&
|
||||
useAnimations() == other.useAnimations() &&
|
||||
animationsDuration() == other.animationsDuration() &&
|
||||
tabsEnabled() == other.tabsEnabled() &&
|
||||
useNarrowButtonSpacing() == other.useNarrowButtonSpacing();
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace OxygenConfig
|
|||
static const QString HIDE_TITLEBAR = "HideTitleBar";
|
||||
static const QString USE_ANIMATIONS = "UseAnimations";
|
||||
static const QString ANIMATIONS_DURATION = "AnimationsDuration";
|
||||
static const QString TABS_ENABLED = "TabsEnabled";
|
||||
static const QString NARROW_BUTTON_SPACING = "UseNarrowButtonSpacing";
|
||||
|
||||
}
|
||||
|
@ -265,6 +266,14 @@ namespace Oxygen
|
|||
virtual void setAnimationsDuration( int value )
|
||||
{ animationsDuration_ = value; }
|
||||
|
||||
//! tabbing
|
||||
virtual bool tabsEnabled( void ) const
|
||||
{ return tabsEnabled_; }
|
||||
|
||||
//! tabbing
|
||||
virtual void setTabsEnabled( bool value )
|
||||
{ tabsEnabled_ = value; }
|
||||
|
||||
private:
|
||||
|
||||
//! title alignment
|
||||
|
@ -300,6 +309,9 @@ namespace Oxygen
|
|||
//! animations
|
||||
int animationsDuration_;
|
||||
|
||||
//! tabbing
|
||||
bool tabsEnabled_;
|
||||
|
||||
//! narrow button spacing
|
||||
bool useNarrowButtonSpacing_;
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
#include <cassert>
|
||||
#include <KColorUtils>
|
||||
#include <KDebug>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
namespace Oxygen
|
||||
|
@ -44,7 +43,6 @@ namespace Oxygen
|
|||
activeShadowConfiguration_( OxygenShadowConfiguration( QPalette::Active ) ),
|
||||
inactiveShadowConfiguration_( OxygenShadowConfiguration( QPalette::Inactive ) )
|
||||
{
|
||||
kDebug(1212) << endl;
|
||||
shadowCache_.setMaxCost( 1<<6 );
|
||||
animatedShadowCache_.setMaxCost( maxIndex_<<6 );
|
||||
}
|
||||
|
@ -393,7 +391,7 @@ namespace Oxygen
|
|||
index(0)
|
||||
{
|
||||
|
||||
active = client->isActive();
|
||||
active = client->isActive() || client->isForcedActive();
|
||||
useOxygenShadows = client->configuration().useOxygenShadows();
|
||||
isShade = client->isShade();
|
||||
hasTitleOutline = client->configuration().drawTitleOutline();
|
||||
|
|
|
@ -33,8 +33,6 @@
|
|||
#include <QtGui/QPolygon>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <KDebug>
|
||||
|
||||
#include <QtGui/QX11Info>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
|
@ -92,12 +90,10 @@ namespace Oxygen
|
|||
WId window_id = client().windowId();
|
||||
if( client().isPreview() ) {
|
||||
|
||||
kDebug(1212) << "Using kcommondecoration::widget()" << endl;
|
||||
setParent( client().widget() );
|
||||
|
||||
} else if( window_id ) {
|
||||
|
||||
kDebug(1212) << "Using Window ID" << endl;
|
||||
WId current = window_id;
|
||||
while( true )
|
||||
{
|
||||
|
@ -113,7 +109,6 @@ namespace Oxygen
|
|||
XReparentWindow( QX11Info::display(), winId(), current, 0, 0 );
|
||||
} else {
|
||||
|
||||
kDebug(1212) << "Unable to find valid parent. Hiding" << endl;
|
||||
hide();
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
add_subdirectory( config )
|
||||
|
||||
set(kwin_tabstrip_SRCS
|
||||
tabstripbutton.cpp
|
||||
tabstripdecoration.cpp
|
||||
tabstripfactory.cpp
|
||||
)
|
||||
|
||||
kde4_add_plugin(kwin3_tabstrip ${kwin_tabstrip_SRCS})
|
||||
|
||||
target_link_libraries(kwin3_tabstrip kdecorations)
|
||||
|
||||
install(TARGETS kwin3_tabstrip DESTINATION ${PLUGIN_INSTALL_DIR})
|
||||
|
||||
install( FILES tabstrip.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin )
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
set(kwin_tabstrip_config_SRCS tabstripconfig.cpp )
|
||||
|
||||
kde4_add_ui_files(kwin_tabstrip_config_SRCS tabstripconfig.ui )
|
||||
|
||||
kde4_add_plugin(kwin_tabstrip_config ${kwin_tabstrip_config_SRCS})
|
||||
|
||||
target_link_libraries(kwin_tabstrip_config ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY})
|
||||
|
||||
install(TARGETS kwin_tabstrip_config DESTINATION ${PLUGIN_INSTALL_DIR} )
|
|
@ -0,0 +1,91 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "tabstripconfig.h"
|
||||
|
||||
#include "tabstripconfig.moc"
|
||||
|
||||
#include <KConfig>
|
||||
#include <KGlobal>
|
||||
#include <KLocale>
|
||||
|
||||
#include <QString>
|
||||
#include <QRadioButton>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
KDE_EXPORT QObject* allocate_config( KConfig* conf, QWidget* parent )
|
||||
{
|
||||
return new TabstripConfig::TabstripConfig( conf, parent );
|
||||
}
|
||||
}
|
||||
|
||||
TabstripConfig::TabstripConfig( KConfig *c, QWidget *parent )
|
||||
{
|
||||
KGlobal::locale()->insertCatalog( "kwin_tabstrip_config" );
|
||||
config = new KConfig( "tabstriprc" );
|
||||
KConfigGroup cg( config, "General" );
|
||||
ui = new TabstripConfigDialog( parent );
|
||||
connect( ui->left, SIGNAL( clicked() ), SIGNAL( changed() ) );
|
||||
connect( ui->center, SIGNAL( clicked() ), SIGNAL( changed() ) );
|
||||
connect( ui->right, SIGNAL( clicked() ), SIGNAL( changed() ) );
|
||||
connect( ui->showIcon, SIGNAL( clicked() ), SIGNAL( changed() ) );
|
||||
load( cg );
|
||||
ui->show();
|
||||
}
|
||||
|
||||
TabstripConfig::~TabstripConfig()
|
||||
{
|
||||
delete ui;
|
||||
delete config;
|
||||
}
|
||||
|
||||
void TabstripConfig::load( KConfigGroup &c )
|
||||
{
|
||||
c = KConfigGroup( config, "General" );
|
||||
QString align = c.readEntry( "TitleAlignment", "Center" );
|
||||
ui->left->setChecked( align == "Left" );
|
||||
ui->center->setChecked( align == "Center" );
|
||||
ui->right->setChecked( align == "Right" );
|
||||
ui->showIcon->setChecked( c.readEntry( "ShowIcon", true ) );
|
||||
}
|
||||
|
||||
void TabstripConfig::save( KConfigGroup &c )
|
||||
{
|
||||
c = KConfigGroup( config, "General" );
|
||||
if( ui->left->isChecked() )
|
||||
c.writeEntry( "TitleAlignment", "Left" );
|
||||
else if( ui->center->isChecked() )
|
||||
c.writeEntry( "TitleAlignment", "Center" );
|
||||
else
|
||||
c.writeEntry( "TitleAlignment", "Right" );
|
||||
c.writeEntry( "ShowIcon", ui->showIcon->isChecked() );
|
||||
config->sync();
|
||||
}
|
||||
|
||||
void TabstripConfig::defaults()
|
||||
{
|
||||
ui->left->setChecked( false );
|
||||
ui->center->setChecked( true );
|
||||
ui->right->setChecked( false );
|
||||
ui->showIcon->setChecked( true );
|
||||
emit changed();
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef TABSTRIPCONFIG_H
|
||||
#define TABSTRIPCONFIG_H
|
||||
|
||||
#include "ui_tabstripconfig.h"
|
||||
|
||||
#include <KConfig>
|
||||
#include <QObject>
|
||||
|
||||
class TabstripConfigDialog : public QWidget, public Ui::TabstripConfigUi
|
||||
{
|
||||
public:
|
||||
TabstripConfigDialog( QWidget *parent ) : QWidget( parent )
|
||||
{
|
||||
setupUi( this );
|
||||
}
|
||||
};
|
||||
|
||||
class TabstripConfig : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TabstripConfig( KConfig *c, QWidget *parent );
|
||||
~TabstripConfig();
|
||||
signals:
|
||||
void changed();
|
||||
public slots:
|
||||
void load( KConfigGroup &c );
|
||||
void save( KConfigGroup &c );
|
||||
void defaults();
|
||||
private:
|
||||
KConfig *config;
|
||||
TabstripConfigDialog *ui;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabstripConfigUi</class>
|
||||
<widget class="QWidget" name="TabstripConfigUi">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>276</width>
|
||||
<height>98</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tabstrip</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Title &Alignment</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="left">
|
||||
<property name="text">
|
||||
<string>&Left</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="center">
|
||||
<property name="text">
|
||||
<string>&Center</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="right">
|
||||
<property name="text">
|
||||
<string>&Right</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showIcon">
|
||||
<property name="text">
|
||||
<string>Display window icons</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,4 @@
|
|||
[Desktop Entry]
|
||||
Name=Tabstrip
|
||||
Name[x-test]=xxTabstripxx
|
||||
X-KDE-Library=kwin3_tabstrip
|
|
@ -0,0 +1,317 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include <kcommondecoration.h>
|
||||
#include "tabstripbutton.h"
|
||||
#include "tabstripdecoration.h"
|
||||
#include "tabstripfactory.h"
|
||||
|
||||
#include <KLocale>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
#include <QPixmap>
|
||||
#include <QRect>
|
||||
|
||||
TabstripButton::TabstripButton( ButtonType type, TabstripDecoration *parent, QString tip )
|
||||
: KCommonDecorationButton( type, parent ), SIZE( 16 )
|
||||
{
|
||||
setAutoFillBackground( false );
|
||||
setFixedSize( SIZE, SIZE );
|
||||
setCursor( Qt::ArrowCursor );
|
||||
client = parent;
|
||||
btype = type;
|
||||
setToolTip( tip );
|
||||
active_item = true;
|
||||
hovering = false;
|
||||
}
|
||||
|
||||
TabstripButton::~TabstripButton()
|
||||
{
|
||||
}
|
||||
|
||||
void TabstripButton::reset( unsigned long )
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
QSize TabstripButton::sizeHint() const
|
||||
{
|
||||
return QSize( SIZE, SIZE );
|
||||
}
|
||||
|
||||
void TabstripButton::paintEvent( QPaintEvent * )
|
||||
{
|
||||
QPainter p( this );
|
||||
const bool active = client->isActive() && active_item;
|
||||
|
||||
// Icon geometry
|
||||
QRect geom = QRect( 3, 3, width() - 6, height() - 6 );
|
||||
|
||||
// Determine painting colors
|
||||
QColor bgColor = client->options()->color( KDecoration::ColorTitleBar, active );
|
||||
QColor textColor = client->options()->color( KDecoration::ColorFont, active );
|
||||
if( hovering )
|
||||
{ // Invert if the mouse cursor is hovering over the button
|
||||
textColor.setRed( 255 - textColor.red() );
|
||||
textColor.setGreen( 255 - textColor.green() );
|
||||
textColor.setBlue( 255 - textColor.blue() );
|
||||
}
|
||||
|
||||
// Slight optimization as we are drawing solid straight lines
|
||||
p.setRenderHint( QPainter::Antialiasing, false );
|
||||
|
||||
// Background
|
||||
p.fillRect( 0, 0, width(), height(), bgColor );
|
||||
//p.fillRect( 0, 0, width(), height(), QColor( 255, 0, 0 ));
|
||||
|
||||
// Paint buttons with the text color
|
||||
p.setPen( textColor );
|
||||
|
||||
switch( btype )
|
||||
{
|
||||
case HelpButton:
|
||||
{
|
||||
QFont font;
|
||||
font.setBold( true );
|
||||
p.setFont( font );
|
||||
p.drawText( geom.adjusted( 0, 1, 0, 0), Qt::AlignVCenter | Qt::AlignHCenter, "?" );
|
||||
}
|
||||
break;
|
||||
case MaxButton:
|
||||
switch( client->maximizeMode() )
|
||||
{
|
||||
case TabstripDecoration::MaximizeRestore:
|
||||
case TabstripDecoration::MaximizeVertical:
|
||||
case TabstripDecoration::MaximizeHorizontal:
|
||||
// TL
|
||||
p.drawLine( geom.x() + 3, geom.y(),
|
||||
geom.x(), geom.y() );
|
||||
p.drawLine( geom.x(), geom.y() + 3,
|
||||
geom.x(), geom.y() );
|
||||
p.drawLine( geom.x() + 3, geom.y() + 1,
|
||||
geom.x(), geom.y() + 1 );
|
||||
p.drawLine( geom.x() + 1, geom.y() + 3,
|
||||
geom.x(), geom.y() + 1 );
|
||||
// TR
|
||||
p.drawLine( geom.x() + geom.width() - 3, geom.y(),
|
||||
geom.x() + geom.width(), geom.y() );
|
||||
p.drawLine( geom.x() + geom.width(), geom.y() + 3,
|
||||
geom.x() + geom.width(), geom.y() );
|
||||
p.drawLine( geom.x() + geom.width() - 3, geom.y() + 1,
|
||||
geom.x() + geom.width(), geom.y() + 1 );
|
||||
p.drawLine( geom.x() + geom.width() - 1, geom.y() + 3,
|
||||
geom.x() + geom.width() - 1, geom.y() );
|
||||
// BL
|
||||
p.drawLine( geom.x() + 3, geom.y() + geom.height(),
|
||||
geom.x(), geom.y() + geom.height() );
|
||||
p.drawLine( geom.x(), geom.y() + geom.height() - 3,
|
||||
geom.x(), geom.y() + geom.height() );
|
||||
p.drawLine( geom.x() + 3, geom.y() + geom.height() - 1,
|
||||
geom.x(), geom.y() + geom.height() - 1 );
|
||||
p.drawLine( geom.x() + 1, geom.y() + geom.height() - 3,
|
||||
geom.x() + 1, geom.y() + geom.height() );
|
||||
// BR
|
||||
p.drawLine( geom.x() + geom.width() - 3, geom.y() + geom.height(),
|
||||
geom.x() + geom.width(), geom.y() + geom.height() );
|
||||
p.drawLine( geom.x() + geom.width(), geom.y() + geom.height() - 3,
|
||||
geom.x() + geom.width(), geom.y() + geom.height() );
|
||||
p.drawLine( geom.x() + geom.width() - 3, geom.y() + geom.height() - 1,
|
||||
geom.x() + geom.width(), geom.y() + geom.height() - 1 );
|
||||
p.drawLine( geom.x() + geom.width() - 1, geom.y() + geom.height() - 3,
|
||||
geom.x() + geom.width() - 1, geom.y() + geom.height() );
|
||||
break;
|
||||
case TabstripDecoration::MaximizeFull:
|
||||
// TL
|
||||
p.drawLine( geom.x() + 2, geom.y(),
|
||||
geom.x() + 2, geom.y() + 2 );
|
||||
p.drawLine( geom.x(), geom.y() + 2,
|
||||
geom.x() + 2, geom.y() + 2 );
|
||||
p.drawLine( geom.x() + 3, geom.y(),
|
||||
geom.x() + 3, geom.y() + 3 );
|
||||
p.drawLine( geom.x(), geom.y() + 3,
|
||||
geom.x() + 3, geom.y() + 3 );
|
||||
// TR
|
||||
p.drawLine( geom.x() + geom.width() - 2, geom.y(),
|
||||
geom.x() + geom.width() - 2, geom.y() + 2 );
|
||||
p.drawLine( geom.x() + geom.width(), geom.y() + 2,
|
||||
geom.x() + geom.width() - 2, geom.y() + 2 );
|
||||
p.drawLine( geom.x() + geom.width() - 3, geom.y(),
|
||||
geom.x() + geom.width() - 3, geom.y() + 3 );
|
||||
p.drawLine( geom.x() + geom.width(), geom.y() + 3,
|
||||
geom.x() + geom.width() - 3, geom.y() + 3 );
|
||||
// BL
|
||||
p.drawLine( geom.x() + 2, geom.y() + geom.height(),
|
||||
geom.x() + 2, geom.y() + geom.height() - 2 );
|
||||
p.drawLine( geom.x(), geom.y() + geom.height() - 2,
|
||||
geom.x() + 2, geom.y() + geom.height() - 2 );
|
||||
p.drawLine( geom.x() + 3, geom.y() + geom.height(),
|
||||
geom.x() + 3, geom.y() + geom.height() - 3 );
|
||||
p.drawLine( geom.x(), geom.y() + geom.height() - 3,
|
||||
geom.x() + 3, geom.y() + geom.height() - 3 );
|
||||
// BR
|
||||
p.drawLine( geom.x() + geom.width() - 2, geom.y() + geom.height(),
|
||||
geom.x() + geom.width() - 2, geom.y() + geom.height() - 2 );
|
||||
p.drawLine( geom.x() + geom.width(), geom.y() + geom.height() - 2,
|
||||
geom.x() + geom.width() - 2, geom.y() + geom.height() - 2 );
|
||||
p.drawLine( geom.x() + geom.width() - 3, geom.y() + geom.height(),
|
||||
geom.x() + geom.width() - 3, geom.y() + geom.height() - 3 );
|
||||
p.drawLine( geom.x() + geom.width(), geom.y() + geom.height() - 3,
|
||||
geom.x() + geom.width() - 3, geom.y() + geom.height() - 3 );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MinButton:
|
||||
// B
|
||||
p.drawLine( geom.x(), geom.y() + geom.height(),
|
||||
geom.x() + geom.width(), geom.y() + geom.height() );
|
||||
p.drawLine( geom.x(), geom.y() + geom.height() - 1,
|
||||
geom.x() + geom.width(), geom.y() + geom.height() - 1 );
|
||||
// L
|
||||
p.drawLine( geom.x(), geom.y() + geom.height() - 3,
|
||||
geom.x(), geom.y() + geom.height() );
|
||||
p.drawLine( geom.x() + 1, geom.y() + geom.height() - 3,
|
||||
geom.x() + 1, geom.y() + geom.height() );
|
||||
// R
|
||||
p.drawLine( geom.x() + geom.width(), geom.y() + geom.height() - 3,
|
||||
geom.x() + geom.width(), geom.y() + geom.height() );
|
||||
p.drawLine( geom.x() + geom.width() - 1, geom.y() + geom.height() - 3,
|
||||
geom.x() + geom.width() - 1, geom.y() + geom.height() );
|
||||
break;
|
||||
case CloseButton:
|
||||
case ItemCloseButton:
|
||||
// TL-BR
|
||||
p.drawLine( geom.x() + 1, geom.y() + 1,
|
||||
geom.x() + geom.width() - 1, geom.y() + geom.height() - 1 );
|
||||
p.drawLine( geom.x() + 2, geom.y() + 1,
|
||||
geom.x() + geom.width() - 1, geom.y() + geom.height() - 2 );
|
||||
p.drawLine( geom.x() + 1, geom.y() + 2,
|
||||
geom.x() + geom.width() - 2, geom.y() + geom.height() - 1 );
|
||||
// TR-BL
|
||||
p.drawLine( geom.x() + 1, geom.y() + geom.height() - 1,
|
||||
geom.x() + geom.width() - 1, geom.y() + 1 );
|
||||
p.drawLine( geom.x() + 2, geom.y() + geom.height() - 1,
|
||||
geom.x() + geom.width() - 1, geom.y() + 2 );
|
||||
p.drawLine( geom.x() + 1, geom.y() + geom.height() - 2,
|
||||
geom.x() + geom.width() - 2, geom.y() + 1 );
|
||||
break;
|
||||
case MenuButton:
|
||||
if( client->clientGroupItems().count() > 1 || !TabstripFactory::showIcon() )
|
||||
{
|
||||
p.drawRect( geom.x(), geom.y() + geom.height() / 2 - 5,
|
||||
1, 1 );
|
||||
p.drawRect( geom.x(), geom.y() + geom.height() / 2 - 1,
|
||||
1, 1 );
|
||||
p.drawRect( geom.x(), geom.y() + geom.height() / 2 + 3,
|
||||
1, 1 );
|
||||
p.drawRect( geom.x() + 4, geom.y() + geom.height() / 2 - 5,
|
||||
geom.width() - 5, 1 );
|
||||
p.drawRect( geom.x() + 4, geom.y() + geom.height() / 2 - 1,
|
||||
geom.width() - 5, 1 );
|
||||
p.drawRect( geom.x() + 4, geom.y() + geom.height() / 2 + 3,
|
||||
geom.width() - 5, 1 );
|
||||
}
|
||||
else
|
||||
p.drawPixmap( 0, 0, client->icon().pixmap( SIZE ));
|
||||
break;
|
||||
case OnAllDesktopsButton:
|
||||
{
|
||||
if( isChecked() )
|
||||
p.fillRect( geom.x() + geom.width() / 2 - 1, geom.y() + geom.height() / 2 - 1,
|
||||
3, 3, textColor );
|
||||
else
|
||||
{
|
||||
p.fillRect( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 - 4,
|
||||
3, 3, textColor );
|
||||
p.fillRect( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 + 2,
|
||||
3, 3, textColor );
|
||||
p.fillRect( geom.x() + geom.width() / 2 + 2, geom.y() + geom.height() / 2 - 4,
|
||||
3, 3, textColor );
|
||||
p.fillRect( geom.x() + geom.width() / 2 + 2, geom.y() + geom.height() / 2 + 2,
|
||||
3, 3, textColor );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AboveButton:
|
||||
{
|
||||
int o = -2;
|
||||
if( isChecked() )
|
||||
{
|
||||
o = -4;
|
||||
p.drawRect( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 + 3,
|
||||
8, 1 );
|
||||
}
|
||||
p.drawPoint( geom.x() + geom.width() / 2, geom.y() + geom.height() / 2 + o );
|
||||
p.drawLine( geom.x() + geom.width() / 2 - 1, geom.y() + geom.height() / 2 + o + 1,
|
||||
geom.x() + geom.width() / 2 + 1, geom.y() + geom.height() / 2 + o + 1 );
|
||||
p.drawLine( geom.x() + geom.width() / 2 - 2, geom.y() + geom.height() / 2 + o + 2,
|
||||
geom.x() + geom.width() / 2 + 2, geom.y() + geom.height() / 2 + o + 2 );
|
||||
p.drawLine( geom.x() + geom.width() / 2 - 3, geom.y() + geom.height() / 2 + o + 3,
|
||||
geom.x() + geom.width() / 2 + 3, geom.y() + geom.height() / 2 + o + 3 );
|
||||
p.drawLine( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 + o + 4,
|
||||
geom.x() + geom.width() / 2 + 4, geom.y() + geom.height() / 2 + o + 4 );
|
||||
}
|
||||
break;
|
||||
case BelowButton:
|
||||
{
|
||||
int o = 1;
|
||||
if( isChecked() )
|
||||
{
|
||||
o = 3;
|
||||
p.drawRect( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 - 5,
|
||||
8, 1 );
|
||||
}
|
||||
p.drawPoint( geom.x() + geom.width() / 2, geom.y() + geom.height() / 2 + o );
|
||||
p.drawLine( geom.x() + geom.width() / 2 - 1, geom.y() + geom.height() / 2 + o - 1,
|
||||
geom.x() + geom.width() / 2 + 1, geom.y() + geom.height() / 2 + o - 1 );
|
||||
p.drawLine( geom.x() + geom.width() / 2 - 2, geom.y() + geom.height() / 2 + o - 2,
|
||||
geom.x() + geom.width() / 2 + 2, geom.y() + geom.height() / 2 + o - 2 );
|
||||
p.drawLine( geom.x() + geom.width() / 2 - 3, geom.y() + geom.height() / 2 + o - 3,
|
||||
geom.x() + geom.width() / 2 + 3, geom.y() + geom.height() / 2 + o - 3 );
|
||||
p.drawLine( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 + o - 4,
|
||||
geom.x() + geom.width() / 2 + 4, geom.y() + geom.height() / 2 + o - 4 );
|
||||
}
|
||||
break;
|
||||
case ShadeButton:
|
||||
p.drawLine( geom.x(), geom.y(),
|
||||
geom.x() + geom.width(), geom.y() );
|
||||
p.drawLine( geom.x(), geom.y() + 1,
|
||||
geom.x() + geom.width(), geom.y() + 1 );
|
||||
break;
|
||||
case NumButtons:
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void TabstripButton::enterEvent( QEvent *e )
|
||||
{
|
||||
hovering = true;
|
||||
repaint();
|
||||
KCommonDecorationButton::enterEvent( e );
|
||||
}
|
||||
|
||||
void TabstripButton::leaveEvent( QEvent *e )
|
||||
{
|
||||
hovering = false;
|
||||
repaint();
|
||||
KCommonDecorationButton::leaveEvent( e );
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef TABSTRIPBUTTON_H
|
||||
#define TABSTRIPBUTTON_H
|
||||
|
||||
#include <kcommondecoration.h>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
|
||||
class TabstripDecoration;
|
||||
|
||||
class TabstripButton : public KCommonDecorationButton
|
||||
{
|
||||
public:
|
||||
TabstripButton( ButtonType type, TabstripDecoration *parent, QString tip );
|
||||
~TabstripButton();
|
||||
void reset( unsigned long changed );
|
||||
QSize sizeHint() const;
|
||||
void setActive( bool active );
|
||||
private:
|
||||
void paintEvent( QPaintEvent *e );
|
||||
void leaveEvent( QEvent *e );
|
||||
void enterEvent( QEvent *e );
|
||||
TabstripDecoration *client;
|
||||
ButtonType btype;
|
||||
const int SIZE;
|
||||
bool active_item;
|
||||
bool hovering;
|
||||
};
|
||||
|
||||
inline void TabstripButton::setActive( bool active )
|
||||
{
|
||||
active_item = active;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,457 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "tabstripdecoration.h"
|
||||
#include "tabstripbutton.h"
|
||||
#include "tabstripfactory.h"
|
||||
|
||||
#include <KLocale>
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
TabstripDecoration::TabstripDecoration( KDecorationBridge *bridge, KDecorationFactory *factory )
|
||||
: KCommonDecorationUnstable( bridge, factory )
|
||||
{
|
||||
click_in_progress = false;
|
||||
drag_in_progress = false;
|
||||
button = Qt::NoButton;
|
||||
}
|
||||
|
||||
TabstripDecoration::~TabstripDecoration()
|
||||
{
|
||||
for( int i = 0; i < closeButtons.size(); ++i )
|
||||
{
|
||||
TabstripButton *btn = closeButtons.front();
|
||||
closeButtons.removeFirst();
|
||||
delete btn;
|
||||
}
|
||||
}
|
||||
|
||||
KCommonDecorationButton *TabstripDecoration::createButton( ButtonType type )
|
||||
{
|
||||
switch( type )
|
||||
{
|
||||
case HelpButton:
|
||||
return ( new TabstripButton( type, this, i18n("Help") ) );
|
||||
break;
|
||||
case MaxButton:
|
||||
return ( new TabstripButton( type, this, i18n("Maximize") ) );
|
||||
break;
|
||||
case MinButton:
|
||||
return ( new TabstripButton( type, this, i18n("Minimize") ) );
|
||||
break;
|
||||
case CloseButton:
|
||||
return ( new TabstripButton( type, this, i18n("Close") ) );
|
||||
break;
|
||||
case MenuButton:
|
||||
return ( new TabstripButton( type, this, i18n("Menu") ) );
|
||||
break;
|
||||
case OnAllDesktopsButton:
|
||||
return ( new TabstripButton( type, this, i18n("AllDesktops") ) );
|
||||
break;
|
||||
case AboveButton:
|
||||
return ( new TabstripButton( type, this, i18n("Above") ) );
|
||||
break;
|
||||
case BelowButton:
|
||||
return ( new TabstripButton( type, this, i18n("Below") ) );
|
||||
break;
|
||||
case ShadeButton:
|
||||
return ( new TabstripButton( type, this, i18n("Shade") ) );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TabstripDecoration::paintTab( QPainter &painter, const QRect &geom, ClientGroupItem &item, bool active )
|
||||
{
|
||||
// Determine painting colors
|
||||
QColor bgColor = options()->color( ColorTitleBar, active );
|
||||
QColor textColor = options()->color( ColorFont, active );
|
||||
|
||||
// Draw border around the tab
|
||||
painter.setPen( Qt::black );
|
||||
painter.drawRect( geom.adjusted( 0, 0, -1, -1 ));
|
||||
painter.setPen( Qt::white );
|
||||
painter.drawRect( geom.adjusted( 1, 1, -2, -2 ));
|
||||
|
||||
// Background
|
||||
painter.fillRect( geom.adjusted( 2, 2, -2, -2 ), bgColor );
|
||||
|
||||
// Window title and icon
|
||||
painter.setPen( textColor );
|
||||
if( TabstripFactory::showIcon() )
|
||||
{
|
||||
QRect rect( geom.x() + 25, geom.y(), geom.width() - 48, geom.height() );
|
||||
QRect text;
|
||||
QFont font;
|
||||
QFontMetrics metrics( font );
|
||||
QString string = metrics.elidedText( item.title(), Qt::ElideRight, rect.width() );
|
||||
painter.drawText( rect, TabstripFactory::titleAlign() | Qt::AlignVCenter, string, &text );
|
||||
painter.drawPixmap( text.x() - 22, rect.y() + 3, item.icon().pixmap( 16 ));
|
||||
}
|
||||
else
|
||||
{
|
||||
QRect rect( geom.x() + 5, geom.y(), geom.width() - 28, geom.height() );
|
||||
QFont font;
|
||||
QFontMetrics metrics( font );
|
||||
QString string = metrics.elidedText( item.title(), Qt::ElideRight, rect.width() );
|
||||
painter.drawText( rect, TabstripFactory::titleAlign() | Qt::AlignVCenter, string );
|
||||
}
|
||||
}
|
||||
|
||||
void TabstripDecoration::paintEvent( QPaintEvent * )
|
||||
{
|
||||
QPainter painter( widget() );
|
||||
|
||||
// Determine painting colors
|
||||
QColor bgColor = options()->color( ColorTitleBar, isClientGroupActive() );
|
||||
QColor textColor = options()->color( ColorFont, isClientGroupActive() );
|
||||
|
||||
// Determine section geometry
|
||||
QRect frame( QPoint( 0, 0 ), widget()->frameGeometry().size() );
|
||||
QRect titlebar( frame.topLeft(), QSize( frame.width(),
|
||||
layoutMetric( LM_TitleEdgeTop ) + layoutMetric( LM_TitleHeight ) +
|
||||
layoutMetric( LM_TitleEdgeBottom ) - 1 // Titlebar and main frame overlap by 1px
|
||||
));
|
||||
|
||||
// Slight optimization as we are drawing solid straight lines
|
||||
painter.setRenderHint( QPainter::Antialiasing, false );
|
||||
|
||||
// Draw black/white border around the main window
|
||||
painter.setPen( Qt::black );
|
||||
painter.drawRect( 0, titlebar.height() - 1, frame.width() - 1, frame.height() - titlebar.height() );
|
||||
painter.setPen( Qt::white );
|
||||
painter.drawRect( 1, titlebar.height(), frame.width() - 3, frame.height() - titlebar.height() - 2 );
|
||||
|
||||
QList< ClientGroupItem > tabList = clientGroupItems();
|
||||
const int tabCount = tabList.count();
|
||||
|
||||
// Delete unneeded tab close buttons
|
||||
while( tabCount < closeButtons.size() || ( tabCount == 1 && closeButtons.size() > 0 ))
|
||||
{
|
||||
TabstripButton *btn = closeButtons.front();
|
||||
closeButtons.removeFirst();
|
||||
delete btn;
|
||||
}
|
||||
|
||||
if( tabCount > 1 )
|
||||
{
|
||||
QRect allTabGeom = titleRect().adjusted( -1, -layoutMetric( LM_TitleEdgeTop ), 1, 0 );
|
||||
QRect tabGeom = allTabGeom;
|
||||
tabGeom.setWidth( tabGeom.width() / tabCount + 1 ); // Split titlebar evenly
|
||||
for( int i = 0; i < tabCount; ++i )
|
||||
{
|
||||
// Last tab may have a different width due to rounding
|
||||
if( i == tabCount - 1 )
|
||||
tabGeom.setWidth( allTabGeom.width() - tabGeom.width() * i + i - 1 );
|
||||
|
||||
// Actually paint the tab
|
||||
paintTab( painter, tabGeom, tabList[i], isActive() && visibleClientGroupItem() == i );
|
||||
|
||||
// Create new close button if required
|
||||
if( i >= closeButtons.size() )
|
||||
closeButtons.append( new TabstripButton( ItemCloseButton, this, i18n( "Close Item" ) ) );
|
||||
closeButtons[ i ]->setActive( isActive() && visibleClientGroupItem() == i );
|
||||
closeButtons[ i ]->move( tabGeom.right() - 18, tabGeom.bottom() - 18 );
|
||||
closeButtons[ i ]->installEventFilter( this );
|
||||
closeButtons[ i ]->show();
|
||||
|
||||
// Prepare for next iteration
|
||||
tabGeom.translate( tabGeom.width() - 1, 0 );
|
||||
}
|
||||
|
||||
// Draw border around the buttons
|
||||
painter.setPen( Qt::black );
|
||||
painter.drawRect( 0, 0, allTabGeom.left(), allTabGeom.height() - 1 );
|
||||
painter.drawRect( allTabGeom.right() - 1, 0, frame.width() - allTabGeom.right(), allTabGeom.height() - 1 );
|
||||
painter.setPen( Qt::white );
|
||||
painter.drawRect( 1, 1, allTabGeom.left() - 2, allTabGeom.height() - 3 );
|
||||
painter.drawRect( allTabGeom.right(), 1, frame.width() - allTabGeom.right() - 2, allTabGeom.height() - 3 );
|
||||
|
||||
// Background behind the buttons
|
||||
painter.fillRect( 2, 2, allTabGeom.left() - 3, allTabGeom.height() - 4, bgColor );
|
||||
painter.fillRect( allTabGeom.right() + 1, 2, frame.width() - allTabGeom.right() - 3, allTabGeom.height() - 4, bgColor );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw border around the titlebar
|
||||
painter.setPen( Qt::black );
|
||||
painter.drawRect( titlebar.adjusted( 0, 0, -1, -1 ));
|
||||
painter.setPen( Qt::white );
|
||||
painter.drawRect( titlebar.adjusted( 1, 1, -2, -2 ));
|
||||
|
||||
// Background
|
||||
painter.fillRect( titlebar.adjusted( 2, 2, -2, -2 ), bgColor );
|
||||
|
||||
// Window title
|
||||
painter.setPen( textColor );
|
||||
QRect rect( titleRect().x() + 2, titleRect().y(),
|
||||
titleRect().width() - 6, titleRect().height() - 3 );
|
||||
QFont font;
|
||||
QFontMetrics metrics( font );
|
||||
QString string = metrics.elidedText( caption(), Qt::ElideRight, rect.width() );
|
||||
painter.drawText( rect, TabstripFactory::titleAlign() | Qt::AlignVCenter, string );
|
||||
}
|
||||
}
|
||||
|
||||
QString TabstripDecoration::visibleName() const
|
||||
{
|
||||
return i18n("Tabstrip");
|
||||
}
|
||||
|
||||
void TabstripDecoration::init()
|
||||
{
|
||||
KCommonDecoration::init();
|
||||
widget()->setAutoFillBackground( false );
|
||||
widget()->setAttribute( Qt::WA_OpaquePaintEvent );
|
||||
widget()->setAcceptDrops( true );
|
||||
}
|
||||
|
||||
|
||||
bool TabstripDecoration::eventFilter( QObject* o, QEvent* e )
|
||||
{
|
||||
bool state = false;
|
||||
if( e->type() == QEvent::MouseButtonPress )
|
||||
state = mouseButtonPressEvent( static_cast< QMouseEvent* >( e ) );
|
||||
|
||||
else if( e->type() == QEvent::MouseButtonRelease && widget() == o )
|
||||
state = mouseButtonReleaseEvent( static_cast< QMouseEvent* >( e ) );
|
||||
|
||||
else if( e->type() == QEvent::MouseMove )
|
||||
state = mouseMoveEvent( static_cast< QMouseEvent* >( e ) );
|
||||
|
||||
else if( e->type() == QEvent::DragEnter && widget() == o )
|
||||
state = dragEnterEvent( static_cast< QDragEnterEvent* >( e ) );
|
||||
|
||||
else if( e->type() == QEvent::DragMove && widget() == o )
|
||||
state = dragMoveEvent( static_cast< QDragMoveEvent* >( e ) );
|
||||
|
||||
else if( e->type() == QEvent::DragLeave && widget() == o )
|
||||
state = dragLeaveEvent( static_cast< QDragLeaveEvent* >( e ) );
|
||||
|
||||
else if( e->type() == QEvent::Drop && widget() == o )
|
||||
state = dropEvent( static_cast< QDropEvent* >( e ) );
|
||||
|
||||
else if( TabstripButton *btn = dynamic_cast< TabstripButton* >( o ) )
|
||||
if( e->type() == QEvent::MouseButtonRelease )
|
||||
{
|
||||
if( static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton )
|
||||
{ closeClientGroupItem( closeButtons.indexOf( btn ) ); }
|
||||
return true;
|
||||
}
|
||||
if( TabstripButton *btn = dynamic_cast< TabstripButton* >( o ) )
|
||||
if( e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseMove )
|
||||
{
|
||||
QMouseEvent *past = static_cast< QMouseEvent* >( e );
|
||||
QPoint point = btn->mapToParent( past->pos() );
|
||||
QMouseEvent *ev = new QMouseEvent( past->type(), point, past->button(), past->buttons(), past->modifiers() );
|
||||
e = dynamic_cast< QEvent* >( ev );
|
||||
o = widget();
|
||||
}
|
||||
return state || KCommonDecorationUnstable::eventFilter( o, e );
|
||||
}
|
||||
|
||||
bool TabstripDecoration::mouseButtonPressEvent( QMouseEvent* e )
|
||||
{
|
||||
click = widget()->mapToParent( e->pos() );
|
||||
int item = itemClicked( click );
|
||||
if( item >= 0 &&
|
||||
( e->button() == Qt::MidButton || e->button() == Qt::LeftButton || e->button() == Qt::RightButton ))
|
||||
{
|
||||
click_in_progress = true;
|
||||
button = e->button();
|
||||
return button != Qt::LeftButton;
|
||||
}
|
||||
click_in_progress = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TabstripDecoration::mouseButtonReleaseEvent( QMouseEvent* e )
|
||||
{
|
||||
release = e->pos();
|
||||
int item = itemClicked( release );
|
||||
if( click_in_progress && item >= 0 )
|
||||
{
|
||||
click_in_progress = false;
|
||||
if( e->button() == Qt::LeftButton || e->button() == Qt::MidButton )
|
||||
setVisibleClientGroupItem( item );
|
||||
else if( e->button() == Qt::RightButton )
|
||||
displayClientMenu( item, widget()->mapToGlobal( release ) );
|
||||
return true;
|
||||
}
|
||||
click_in_progress = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TabstripDecoration::mouseMoveEvent( QMouseEvent* e )
|
||||
{
|
||||
QPoint c = e->pos();
|
||||
int item = itemClicked( c );
|
||||
if( item >= 0 && click_in_progress && button == Qt::MidButton && ( c - click ).manhattanLength() >= 4 )
|
||||
{
|
||||
click_in_progress = false;
|
||||
drag_in_progress = true;
|
||||
QDrag *drag = new QDrag( widget() );
|
||||
QMimeData *group_data = new QMimeData();
|
||||
group_data->setData( clientGroupItemDragMimeType(), QString().setNum( itemId( item )).toAscii() );
|
||||
drag->setMimeData( group_data );
|
||||
|
||||
// Create draggable tab pixmap
|
||||
QList< ClientGroupItem > tabList = clientGroupItems();
|
||||
const int tabCount = tabList.count();
|
||||
QRect frame( QPoint( 0, 0 ), widget()->frameGeometry().size() );
|
||||
QRect titlebar( frame.topLeft(), QSize( frame.width(),
|
||||
layoutMetric( LM_TitleEdgeTop ) + layoutMetric( LM_TitleHeight ) +
|
||||
layoutMetric( LM_TitleEdgeBottom ) - 1 // Titlebar and main frame overlap by 1px
|
||||
));
|
||||
QRect geom = titleRect().adjusted( -1, -layoutMetric( LM_TitleEdgeTop ), 1, 0 );
|
||||
geom.setWidth( geom.width() / tabCount + 1 ); // Split titlebar evenly
|
||||
geom.translate( geom.width() * item - item, 0 );
|
||||
QPixmap pix( geom.size() );
|
||||
QPainter painter( &pix );
|
||||
paintTab( painter, QRect( QPoint( 0, 0 ), geom.size() ), tabList[item],
|
||||
isActive() && visibleClientGroupItem() == item );
|
||||
drag->setPixmap( pix );
|
||||
// If the cursor is on top of the pixmap then it makes the movement jerky on some systems
|
||||
//drag->setHotSpot( QPoint( c.x() - geom.x(), c.y() - geom.y() ));
|
||||
drag->setHotSpot( QPoint( c.x() - geom.x(), -1 ));
|
||||
|
||||
drag->exec( Qt::MoveAction );
|
||||
drag_in_progress = false;
|
||||
if( drag->target() == 0 && tabList.count() > 1 )
|
||||
{ // Remove window from group and move to where the cursor is located
|
||||
QPoint pos = QCursor::pos();
|
||||
frame.moveTo( pos.x() - c.x(), pos.y() - c.y() );
|
||||
removeFromClientGroup( itemClicked( click ), frame );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TabstripDecoration::dragEnterEvent( QDragEnterEvent* e )
|
||||
{
|
||||
if( e->source() != 0 && e->source()->objectName() == "decoration widget" )
|
||||
{
|
||||
drag_in_progress = true;
|
||||
e->acceptProposedAction();
|
||||
QPoint point = widget()->mapToParent( e->pos() );
|
||||
targetTab = itemClicked( point );
|
||||
widget()->update();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TabstripDecoration::dropEvent( QDropEvent* e )
|
||||
{
|
||||
QPoint point = widget()->mapToParent( e->pos() );
|
||||
drag_in_progress = false;
|
||||
int tabClick = itemClicked( point );
|
||||
if( tabClick >= 0 )
|
||||
{
|
||||
const QMimeData *group_data = e->mimeData();
|
||||
if( group_data->hasFormat( clientGroupItemDragMimeType() ) )
|
||||
{
|
||||
if( widget() == e->source() )
|
||||
{
|
||||
int from = itemClicked( click );
|
||||
moveItemInClientGroup( from, itemClicked( point, true ));
|
||||
}
|
||||
else
|
||||
{
|
||||
int source = QString( group_data->data( clientGroupItemDragMimeType() ) ).toInt();
|
||||
moveItemToClientGroup( source, itemClicked( point, true ));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TabstripDecoration::dragMoveEvent( QDragMoveEvent* )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TabstripDecoration::dragLeaveEvent( QDragLeaveEvent* )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int TabstripDecoration::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *button) const
|
||||
{
|
||||
switch ( lm )
|
||||
{
|
||||
case LM_BorderBottom:
|
||||
return 2;
|
||||
case LM_BorderLeft:
|
||||
case LM_BorderRight:
|
||||
return 2;
|
||||
case LM_TitleHeight:
|
||||
return 17;
|
||||
case LM_TitleBorderLeft:
|
||||
return 3;
|
||||
case LM_TitleBorderRight:
|
||||
return 1;
|
||||
case LM_TitleEdgeTop:
|
||||
case LM_TitleEdgeBottom:
|
||||
case LM_TitleEdgeLeft:
|
||||
case LM_TitleEdgeRight:
|
||||
return 3;
|
||||
case LM_ButtonWidth:
|
||||
case LM_ButtonHeight:
|
||||
return 16;
|
||||
case LM_ButtonSpacing:
|
||||
return 6;
|
||||
case LM_ExplicitButtonSpacer:
|
||||
return -2;
|
||||
default:
|
||||
return KCommonDecoration::layoutMetric( lm, respectWindowState, button );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int TabstripDecoration::itemClicked( const QPoint &point, bool between )
|
||||
{
|
||||
QRect frame = widget()->frameGeometry();
|
||||
QList< ClientGroupItem > list = clientGroupItems();
|
||||
int tabs = list.count();
|
||||
int t_x = titleRect().x();
|
||||
int t_y = frame.y();
|
||||
int t_w = titleRect().width();
|
||||
int t_h = layoutMetric( LM_TitleEdgeTop ) + layoutMetric( LM_TitleHeight ) + layoutMetric( LM_TitleEdgeBottom );
|
||||
int tabWidth = t_w/tabs;
|
||||
if( between ) // We are inserting a new tab between two existing ones
|
||||
t_x -= tabWidth / 2;
|
||||
int rem = t_w%tabs;
|
||||
int tab_x = t_x;
|
||||
for( int i = 0; i < tabs; ++i )
|
||||
{
|
||||
QRect tabRect( tab_x, t_y, i<rem?tabWidth+1:tabWidth, t_h );
|
||||
if( tabRect.contains( point ) )
|
||||
return i;
|
||||
tab_x += tabRect.width();
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef TABSTRIPDECORATION_H
|
||||
#define TABSTRIPDECORATION_H
|
||||
|
||||
#include <kdecoration.h>
|
||||
#include <kcommondecoration.h>
|
||||
#include <QPaintEvent>
|
||||
#include <kdebug.h>
|
||||
|
||||
class TabstripButton;
|
||||
|
||||
class TabstripDecoration : public KCommonDecorationUnstable
|
||||
{
|
||||
public:
|
||||
TabstripDecoration( KDecorationBridge *bridge, KDecorationFactory *factory );
|
||||
~TabstripDecoration();
|
||||
KCommonDecorationButton *createButton( ButtonType type );
|
||||
void init();
|
||||
QString visibleName() const;
|
||||
virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton *button = 0) const;
|
||||
virtual bool eventFilter( QObject* o, QEvent* e );
|
||||
private:
|
||||
void paintTab( QPainter &painter, const QRect &geom, ClientGroupItem &item, bool active );
|
||||
void paintEvent( QPaintEvent *e );
|
||||
bool mouseSingleClickEvent( QMouseEvent* e );
|
||||
bool mouseMoveEvent( QMouseEvent* e );
|
||||
bool mouseButtonPressEvent( QMouseEvent* e );
|
||||
bool mouseButtonReleaseEvent( QMouseEvent* e );
|
||||
bool dragMoveEvent( QDragMoveEvent* e );
|
||||
bool dragLeaveEvent( QDragLeaveEvent* e );
|
||||
bool dragEnterEvent( QDragEnterEvent* e );
|
||||
bool dropEvent( QDropEvent* e );
|
||||
int itemClicked( const QPoint &point, bool between = false );
|
||||
QList< TabstripButton* > closeButtons;
|
||||
QPoint click, release;
|
||||
int targetTab;
|
||||
bool click_in_progress, drag_in_progress;
|
||||
Qt::MouseButton button;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,111 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "tabstripfactory.h"
|
||||
#include "tabstripdecoration.h"
|
||||
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
#include <KDebug>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
KDE_EXPORT KDecorationFactory *create_factory()
|
||||
{
|
||||
return new TabstripFactory::TabstripFactory();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::AlignmentFlag TabstripFactory::titlealign = Qt::AlignCenter;
|
||||
bool TabstripFactory::show_icon = true;
|
||||
|
||||
TabstripFactory::TabstripFactory()
|
||||
{
|
||||
initialized = false;
|
||||
readConfig();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
TabstripFactory::~TabstripFactory()
|
||||
{
|
||||
}
|
||||
|
||||
KDecoration *TabstripFactory::createDecoration( KDecorationBridge *bridge )
|
||||
{
|
||||
return ( new TabstripDecoration( bridge, this ) )->decoration();
|
||||
}
|
||||
|
||||
bool TabstripFactory::supports( Ability ability ) const
|
||||
{
|
||||
switch( ability )
|
||||
{
|
||||
case AbilityButtonMenu:
|
||||
case AbilityAnnounceColors:
|
||||
case AbilityButtonOnAllDesktops:
|
||||
case AbilityButtonSpacer:
|
||||
case AbilityButtonHelp:
|
||||
case AbilityButtonMinimize:
|
||||
case AbilityButtonMaximize:
|
||||
case AbilityButtonClose:
|
||||
case AbilityButtonAboveOthers:
|
||||
case AbilityButtonBelowOthers:
|
||||
case AbilityButtonShade:
|
||||
case AbilityClientGrouping:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
bool TabstripFactory::readConfig()
|
||||
{
|
||||
KConfig config( "tabstriprc" );
|
||||
KConfigGroup cg = config.group( "General" );
|
||||
Qt::AlignmentFlag oldalign = titlealign;
|
||||
QString align = cg.readEntry( "TitleAlignment", "Center" );
|
||||
if( align == "Left" )
|
||||
titlealign = Qt::AlignLeft;
|
||||
else if( align == "Center" )
|
||||
titlealign = Qt::AlignHCenter;
|
||||
else if( align == "Right" )
|
||||
titlealign = Qt::AlignRight;
|
||||
show_icon = cg.readEntry( "ShowIcon", true );
|
||||
return ( titlealign != oldalign );
|
||||
}
|
||||
|
||||
bool TabstripFactory::reset( unsigned long changed )
|
||||
{
|
||||
initialized = false;
|
||||
bool c_change = readConfig();
|
||||
initialized = true;
|
||||
if( c_change || ( changed & ( SettingDecoration | SettingButtons | SettingBorder ) ) )
|
||||
return true;
|
||||
else
|
||||
{
|
||||
resetDecorations( changed );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QList< KDecorationDefines::BorderSize > TabstripFactory::borderSizes() const
|
||||
{
|
||||
return QList< BorderSize >() << BorderNormal;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef TABSTRIPFACTORY_H
|
||||
#define TABSTRIPFACTORY_H
|
||||
|
||||
#include <kdecorationfactory.h>
|
||||
#include <kdecoration.h>
|
||||
#include <kdecorationbridge.h>
|
||||
|
||||
class TabstripFactory : public KDecorationFactoryUnstable
|
||||
{
|
||||
public:
|
||||
TabstripFactory();
|
||||
~TabstripFactory();
|
||||
KDecoration *createDecoration( KDecorationBridge *bridge );
|
||||
bool supports( Ability ability ) const;
|
||||
bool reset( unsigned long changed );
|
||||
QList< KDecorationDefines::BorderSize > borderSizes() const;
|
||||
static Qt::AlignmentFlag titleAlign();
|
||||
static bool showIcon();
|
||||
private:
|
||||
bool readConfig();
|
||||
bool initialized;
|
||||
static Qt::AlignmentFlag titlealign;
|
||||
static bool show_icon;
|
||||
};
|
||||
|
||||
inline Qt::AlignmentFlag TabstripFactory::titleAlign()
|
||||
{
|
||||
return titlealign;
|
||||
}
|
||||
|
||||
inline bool TabstripFactory::showIcon()
|
||||
{
|
||||
return show_icon;
|
||||
}
|
||||
|
||||
#endif
|
25
effects.cpp
25
effects.cpp
|
@ -261,6 +261,24 @@ void EffectsHandlerImpl::windowUnminimized( EffectWindow* c )
|
|||
ep.second->windowUnminimized( c );
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::clientGroupItemSwitched( EffectWindow* from, EffectWindow* to )
|
||||
{
|
||||
foreach( const EffectPair &ep, loaded_effects )
|
||||
ep.second->clientGroupItemSwitched( from, to );
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::clientGroupItemAdded( EffectWindow* from, EffectWindow* to )
|
||||
{
|
||||
foreach( const EffectPair &ep, loaded_effects )
|
||||
ep.second->clientGroupItemAdded( from, to );
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::clientGroupItemRemoved( EffectWindow* c, EffectWindow* group )
|
||||
{
|
||||
foreach( const EffectPair &ep, loaded_effects )
|
||||
ep.second->clientGroupItemRemoved( c, group );
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::desktopChanged( int old )
|
||||
{
|
||||
foreach( const EffectPair &ep, loaded_effects )
|
||||
|
@ -1495,6 +1513,13 @@ void EffectWindowImpl::closeWindow() const
|
|||
}
|
||||
}
|
||||
|
||||
bool EffectWindowImpl::visibleInClientGroup() const
|
||||
{
|
||||
if( Client* c = dynamic_cast< Client* >( toplevel ))
|
||||
return c == c->clientGroup()->visible();
|
||||
return false;
|
||||
}
|
||||
|
||||
EffectWindow* effectWindow( Toplevel* w )
|
||||
{
|
||||
EffectWindowImpl* ret = w->effectWindow();
|
||||
|
|
|
@ -147,6 +147,9 @@ class EffectsHandlerImpl : public EffectsHandler
|
|||
void windowActivated( EffectWindow* c );
|
||||
void windowMinimized( EffectWindow* c );
|
||||
void windowUnminimized( EffectWindow* c );
|
||||
void clientGroupItemSwitched( EffectWindow* from, EffectWindow* to );
|
||||
void clientGroupItemAdded( EffectWindow* from, EffectWindow* to );
|
||||
void clientGroupItemRemoved( EffectWindow* c, EffectWindow* group );
|
||||
void desktopChanged( int old );
|
||||
void windowDamaged( EffectWindow* w, const QRect& r );
|
||||
void windowGeometryShapeChanged( EffectWindow* w, const QRect& old );
|
||||
|
@ -264,6 +267,8 @@ class EffectWindowImpl : public EffectWindow
|
|||
virtual void unminimize() const;
|
||||
virtual void closeWindow() const;
|
||||
|
||||
virtual bool visibleInClientGroup() const;
|
||||
|
||||
const Toplevel* window() const;
|
||||
Toplevel* window();
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#######################################
|
||||
# Effect
|
||||
|
||||
# Source files
|
||||
set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
|
||||
slidetabs/slidetabs.cpp
|
||||
)
|
||||
|
||||
# .desktop files
|
||||
install( FILES
|
||||
slidetabs/slidetabs.desktop
|
||||
DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
|
||||
|
||||
#######################################
|
||||
# Config
|
||||
|
||||
# Source files
|
||||
set( kwin4_effect_builtins_config_sources ${kwin4_effect_builtins_config_sources}
|
||||
slidetabs/slidetabs_config.cpp
|
||||
slidetabs/slidetabs_config.ui
|
||||
)
|
||||
|
||||
# .desktop files
|
||||
install( FILES
|
||||
slidetabs/slidetabs_config.desktop
|
||||
DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
|
|
@ -0,0 +1,194 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "slidetabs.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <QPoint>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
KWIN_EFFECT( slidetabs, SlideTabsEffect )
|
||||
|
||||
SlideTabsEffect::SlideTabsEffect()
|
||||
{
|
||||
reconfigure( ReconfigureAll );
|
||||
}
|
||||
|
||||
void SlideTabsEffect::reconfigure( ReconfigureFlags )
|
||||
{
|
||||
KConfigGroup conf = EffectsHandler::effectConfig("SlideTabs");
|
||||
switching = conf.readEntry("SlideSwitching", true );
|
||||
grouping = conf.readEntry("SlideGrouping", true );
|
||||
totalTime = conf.readEntry("SlideDuration", 500 );
|
||||
}
|
||||
|
||||
void SlideTabsEffect::prePaintWindow( EffectWindow *w, WindowPrePaintData &data, int time )
|
||||
{
|
||||
if( motionManager.isManaging( w ) )
|
||||
{
|
||||
data.setTransformed();
|
||||
w->enablePainting( EffectWindow::PAINT_DISABLED );
|
||||
timeLine.addTime( time );
|
||||
}
|
||||
effects->prePaintWindow( w, data, time );
|
||||
}
|
||||
|
||||
void SlideTabsEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
||||
{
|
||||
if( motionManager.isManaging( w ) && w == inMove )
|
||||
motionManager.apply( w, data );
|
||||
effects->paintWindow( w, mask, region, data );
|
||||
}
|
||||
|
||||
void SlideTabsEffect::postPaintWindow( EffectWindow* w )
|
||||
{
|
||||
if( motionManager.isManaging( w ) )
|
||||
{
|
||||
if( w == inMove )
|
||||
{
|
||||
QRect moving = calculateNextMove();
|
||||
motionManager.moveWindow( w, moving );
|
||||
if( direction && timeLine.progress() >= 0.5 )
|
||||
{
|
||||
moving = target;
|
||||
target = source;
|
||||
source = moving;
|
||||
direction = false;
|
||||
effects->setElevatedWindow( notMoving, false );
|
||||
effects->setElevatedWindow( w, true );
|
||||
}
|
||||
else if( timeLine.progress() >= 1.0 )
|
||||
{
|
||||
effects->setElevatedWindow( notMoving, false );
|
||||
effects->setElevatedWindow( inMove, false );
|
||||
motionManager.unmanage( notMoving );
|
||||
motionManager.unmanage( inMove );
|
||||
notMoving = NULL;
|
||||
inMove = NULL;
|
||||
wasD = false;
|
||||
effects->addRepaintFull();
|
||||
}
|
||||
}
|
||||
else if( w == notMoving && !direction && target != w->geometry() && !wasD )
|
||||
{
|
||||
target = w->geometry();
|
||||
}
|
||||
w->addRepaintFull();
|
||||
}
|
||||
effects->postPaintWindow( w );
|
||||
}
|
||||
|
||||
void SlideTabsEffect::prePaintScreen( ScreenPrePaintData &data, int time )
|
||||
{
|
||||
if( motionManager.managingWindows() )
|
||||
{
|
||||
motionManager.calculate( time );
|
||||
data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
|
||||
}
|
||||
effects->prePaintScreen( data, time );
|
||||
}
|
||||
|
||||
void SlideTabsEffect::postPaintScreen()
|
||||
{
|
||||
if( motionManager.managingWindows() )
|
||||
effects->addRepaintFull();
|
||||
effects->postPaintScreen();
|
||||
}
|
||||
|
||||
void SlideTabsEffect::clientGroupItemSwitched( EffectWindow* from, EffectWindow* to )
|
||||
{
|
||||
if( !switching )
|
||||
return;
|
||||
inMove = to;
|
||||
notMoving = from;
|
||||
source = notMoving->geometry();
|
||||
QRect window = notMoving->geometry();
|
||||
int leftSpace = window.x(), rightSpace = displayWidth() - ( window.x() + window.width() ),
|
||||
upSpace = window.y(), downSpace = displayHeight() - ( window.y() + window.height() );
|
||||
|
||||
if( leftSpace >= rightSpace && leftSpace >= upSpace && leftSpace >= downSpace )
|
||||
target = QRect( source.x() - ( 1.2 * source.width() ), source.y(), source.width(), source.height() );
|
||||
else if( rightSpace >= leftSpace && rightSpace >= upSpace && rightSpace >= downSpace )
|
||||
target = QRect( source.x() + ( 1.2 * source.width() ), source.y(), source.width(), source.height() );
|
||||
else if( upSpace >= leftSpace && upSpace >= rightSpace && upSpace >= downSpace )
|
||||
target = QRect( source.x(), source.y() - ( 1.2 * source.height() ), source.width(), source.height() );
|
||||
else
|
||||
target = QRect( source.x(), source.y() + ( 1.2 * source.height() ), source.width(), source.height() );
|
||||
|
||||
timeLine.setCurveShape( TimeLine::LinearCurve );
|
||||
timeLine.setDuration( animationTime( totalTime ) );
|
||||
timeLine.setProgress( 0.0f );
|
||||
motionManager.manage( inMove );
|
||||
motionManager.manage( notMoving );
|
||||
distance = sqrt( ( ( source.x()-target.x() ) * ( source.x()-target.x() ) ) + ( ( source.y()-target.y() ) * ( source.y()-target.y() ) ) );
|
||||
effects->setElevatedWindow( notMoving, true );
|
||||
direction = wasD = true;
|
||||
|
||||
QRect moving = calculateNextMove();
|
||||
motionManager.moveWindow( inMove, moving );
|
||||
}
|
||||
|
||||
void SlideTabsEffect::clientGroupItemAdded( EffectWindow* from, EffectWindow* to )
|
||||
{
|
||||
if( !grouping || from->desktop() != to->desktop() || from->isMinimized() || to->isMinimized() )
|
||||
return;
|
||||
timeLine.setCurveShape( TimeLine::LinearCurve );
|
||||
timeLine.setDuration( animationTime( totalTime ) );
|
||||
timeLine.setProgress( 0.0f );
|
||||
inMove = from;
|
||||
notMoving = to;
|
||||
source = inMove->geometry();
|
||||
target = notMoving->geometry();
|
||||
distance = sqrt( ( ( source.x()-target.x() ) * ( source.x()-target.x() ) ) + ( ( source.y()-target.y() ) * ( source.y()-target.y() ) ) );
|
||||
motionManager.manage( inMove );
|
||||
motionManager.manage( notMoving );
|
||||
QRect moving = calculateNextMove();
|
||||
motionManager.moveWindow( inMove, moving );
|
||||
effects->setElevatedWindow( notMoving, true );
|
||||
direction = wasD = false;
|
||||
}
|
||||
|
||||
QPoint SlideTabsEffect::calculatePointTarget( const QPoint &a, const QPoint &b )
|
||||
{
|
||||
double dy, dx, x, y, k;
|
||||
k = direction? (2.0*timeLine.progress()):(wasD?((timeLine.progress()-0.5)*2):timeLine.progress());
|
||||
dx = fabs( a.x() - b.x() );
|
||||
dy = fabs( a.y() - b.y() );
|
||||
y = k*dy;
|
||||
x = k*dx;
|
||||
if( a.x() > b.x() )
|
||||
x = -x;
|
||||
if( a.y() > b.y() )
|
||||
y = -y;
|
||||
return QPoint( a.x() + x, a.y() + y );
|
||||
}
|
||||
|
||||
QRect SlideTabsEffect::calculateNextMove()
|
||||
{
|
||||
QPoint topLeft, bottomRight;
|
||||
int mw = source.width(), mh = source.height(), tw = target.width(), th = target.height();
|
||||
topLeft = calculatePointTarget( QPoint( source.x(), source.y() ), QPoint( target.x(), target.y() ) );
|
||||
bottomRight = calculatePointTarget( QPoint( source.x() + mw, source.y() + mh ), QPoint( target.x() + tw, target.y() + th ) );
|
||||
return QRect( topLeft.x(), topLeft.y(), bottomRight.x() - topLeft.x(), bottomRight.y() - topLeft.y() );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
[Desktop Entry]
|
||||
Name=Slide Tabs
|
||||
Name[x-test]=xxSlide Tabsxx
|
||||
|
||||
Icon=preferences-system-windows-effect-slidetabs
|
||||
|
||||
Type=Service
|
||||
Comment=Slide windows when switching or groupping tabs.
|
||||
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=KWin/Effect
|
||||
X-KDE-PluginInfo-Author=Jorge Mata
|
||||
X-KDE-PluginInfo-Email=matamax123@gmail.com
|
||||
X-KDE-PluginInfo-Name=kwin4_effect_slidetabs
|
||||
X-KDE-PluginInfo-Version=0.1.0
|
||||
X-KDE-PluginInfo-Category=Focus
|
||||
X-KDE-PluginInfo-Depends=
|
||||
X-KDE-PluginInfo-License=GPL
|
||||
X-KDE-PluginInfo-EnabledByDefault=false
|
||||
X-KDE-Library=kwin4_effect_builtins
|
||||
X-KDE-Ordering=50
|
|
@ -0,0 +1,56 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef KWIN_SLIDETABS_H
|
||||
#define KWIN_SLIDETABS_H
|
||||
|
||||
#include <kwineffects.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class SlideTabsEffect : public Effect
|
||||
{
|
||||
public:
|
||||
SlideTabsEffect();
|
||||
virtual void reconfigure( ReconfigureFlags );
|
||||
virtual void prePaintWindow( EffectWindow *w, WindowPrePaintData &data, int time );
|
||||
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
|
||||
virtual void postPaintWindow( EffectWindow* w );
|
||||
virtual void prePaintScreen( ScreenPrePaintData &data, int time );
|
||||
virtual void postPaintScreen();
|
||||
virtual void clientGroupItemSwitched( EffectWindow* from, EffectWindow* to );
|
||||
virtual void clientGroupItemAdded( EffectWindow* from, EffectWindow* to );
|
||||
|
||||
private:
|
||||
QRect calculateNextMove();
|
||||
QPoint calculatePointTarget( const QPoint &a, const QPoint &b );
|
||||
WindowMotionManager motionManager;
|
||||
EffectWindow* inMove;
|
||||
EffectWindow* notMoving;
|
||||
TimeLine timeLine;
|
||||
QRect target, source;
|
||||
bool direction, wasD, grouping, switching;
|
||||
int totalTime, distance;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,95 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "slidetabs_config.h"
|
||||
|
||||
#include <kwineffects.h>
|
||||
|
||||
#include <klocale.h>
|
||||
#include <kconfiggroup.h>
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
KWIN_EFFECT_CONFIG_FACTORY
|
||||
|
||||
SlideTabsEffectConfigForm::SlideTabsEffectConfigForm( QWidget* parent ) : QWidget( parent )
|
||||
{
|
||||
setupUi( this );
|
||||
}
|
||||
|
||||
SlideTabsEffectConfig::SlideTabsEffectConfig(QWidget* parent, const QVariantList& args)
|
||||
: KCModule( EffectFactory::componentData(), parent, args )
|
||||
{
|
||||
m_ui = new SlideTabsEffectConfigForm( this );
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout( this );
|
||||
|
||||
layout->addWidget( m_ui );
|
||||
|
||||
connect( m_ui->grouping, SIGNAL( toggled( bool )), this, SLOT( changed() ) );
|
||||
connect( m_ui->switching, SIGNAL( toggled( bool )), this, SLOT( changed() ) );
|
||||
connect( m_ui->duration, SIGNAL( valueChanged( int ) ), this, SLOT( changed() ) );
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
void SlideTabsEffectConfig::save()
|
||||
{
|
||||
KConfigGroup conf = EffectsHandler::effectConfig( "SlideTabs" );
|
||||
|
||||
conf.writeEntry( "SlideGrouping", m_ui->grouping->isChecked() );
|
||||
conf.writeEntry( "SlideSwitching", m_ui->switching->isChecked() );
|
||||
conf.writeEntry( "SlideDuration", m_ui->duration->value() );
|
||||
|
||||
conf.sync();
|
||||
|
||||
KCModule::save();
|
||||
emit changed( false );
|
||||
EffectsHandler::sendReloadMessage( "slidetabs" );
|
||||
}
|
||||
|
||||
void SlideTabsEffectConfig::load()
|
||||
{
|
||||
KCModule::load();
|
||||
KConfigGroup conf = EffectsHandler::effectConfig( "SlideTabs" );
|
||||
|
||||
bool switching = conf.readEntry( "SlideSwitching", true );
|
||||
bool grouping = conf.readEntry( "SlideGrouping", true );
|
||||
int duration = conf.readEntry("SlideDuration", 500 );
|
||||
m_ui->switching->setChecked( switching );
|
||||
m_ui->grouping->setChecked( grouping );
|
||||
m_ui->duration->setValue( duration );
|
||||
emit changed( false );
|
||||
}
|
||||
|
||||
void SlideTabsEffectConfig::defaults()
|
||||
{
|
||||
m_ui->grouping->setChecked( true );
|
||||
m_ui->switching->setChecked( true );
|
||||
m_ui->duration->setValue( 500 );
|
||||
emit changed( true );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "slidetabs_config.moc"
|
|
@ -0,0 +1,11 @@
|
|||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=KCModule
|
||||
|
||||
X-KDE-Library=kcm_kwin4_effect_builtins
|
||||
X-KDE-ParentComponents=kwin4_effect_slidetabs
|
||||
X-KDE-PluginKeyword=slidetabs
|
||||
|
||||
Name=Slide Tabs
|
||||
Name[x-test]=xxSlide Tabsxx
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef KWIN_SLIDETABS_CONFIG_H
|
||||
#define KWIN_SLIDETABS_CONFIG_H
|
||||
|
||||
#include <kcmodule.h>
|
||||
|
||||
#include "ui_slidetabs_config.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class SlideTabsEffectConfigForm : public QWidget, public Ui::SlideTabsEffectConfigForm
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SlideTabsEffectConfigForm( QWidget* parent );
|
||||
};
|
||||
|
||||
class SlideTabsEffectConfig : public KCModule
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SlideTabsEffectConfig( QWidget* parent = 0, const QVariantList& args = QVariantList() );
|
||||
public slots:
|
||||
virtual void save();
|
||||
virtual void load();
|
||||
virtual void defaults();
|
||||
private:
|
||||
SlideTabsEffectConfigForm* m_ui;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KWin::SlideTabsEffectConfigForm</class>
|
||||
<widget class="QWidget" name="KWin::SlideTabsEffectConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>238</width>
|
||||
<height>90</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="grouping">
|
||||
<property name="text">
|
||||
<string>Slide when grouping</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="switching">
|
||||
<property name="text">
|
||||
<string>slide when switching tabs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Duration</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="duration">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,26 @@
|
|||
#######################################
|
||||
# Effect
|
||||
|
||||
# Source files
|
||||
set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
|
||||
swiveltabs/swiveltabs.cpp
|
||||
)
|
||||
|
||||
# .desktop files
|
||||
install( FILES
|
||||
swiveltabs/swiveltabs.desktop
|
||||
DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
|
||||
|
||||
#######################################
|
||||
# Config
|
||||
|
||||
# Source files
|
||||
set( kwin4_effect_builtins_config_sources ${kwin4_effect_builtins_config_sources}
|
||||
swiveltabs/swiveltabs_config.cpp
|
||||
swiveltabs/swiveltabs_config.ui
|
||||
)
|
||||
|
||||
# .desktop files
|
||||
install( FILES
|
||||
swiveltabs/swiveltabs_config.desktop
|
||||
DESTINATION ${SERVICES_INSTALL_DIR}/kwin )
|
|
@ -0,0 +1,157 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "swiveltabs.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
KWIN_EFFECT( swiveltabs, SwivelTabsEffect )
|
||||
KWIN_EFFECT_SUPPORTED( swiveltabs, SwivelTabsEffect::supported() )
|
||||
|
||||
SwivelTabsEffect::SwivelTabsEffect()
|
||||
{
|
||||
isActive = false;
|
||||
PI = 2.0 * acos( 0.0 );
|
||||
reconfigure( ReconfigureAll );
|
||||
}
|
||||
|
||||
bool SwivelTabsEffect::supported()
|
||||
{
|
||||
return effects->compositingType() == OpenGLCompositing;
|
||||
}
|
||||
|
||||
void SwivelTabsEffect::reconfigure( ReconfigureFlags )
|
||||
{
|
||||
KConfigGroup conf = EffectsHandler::effectConfig("SwivelTabs");
|
||||
vertical = conf.readEntry("SwivelVertical", true );
|
||||
horizontal = conf.readEntry("SwivelHorizontal", true );
|
||||
totalTime = conf.readEntry("SwivelDuration", 500 );
|
||||
}
|
||||
|
||||
void SwivelTabsEffect::prePaintScreen( ScreenPrePaintData& data, int time )
|
||||
{
|
||||
if( isActive )
|
||||
data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
|
||||
effects->prePaintScreen( data, time );
|
||||
}
|
||||
|
||||
void SwivelTabsEffect::prePaintWindow( EffectWindow *w, WindowPrePaintData &data, int time )
|
||||
{
|
||||
if( isActive && ( w == windows.show || w == windows.hide ) )
|
||||
{
|
||||
data.quads = data.quads.makeGrid( 40 );
|
||||
data.setTransformed();
|
||||
w->enablePainting( EffectWindow::PAINT_DISABLED );
|
||||
windows.time.addTime( time );
|
||||
}
|
||||
effects->prePaintWindow( w, data, time );
|
||||
}
|
||||
|
||||
void SwivelTabsEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
||||
{
|
||||
if( isActive && ( w == windows.show || w == windows.hide ) )
|
||||
{
|
||||
for( int i = 0; i < data.quads.count(); ++i )
|
||||
transformQuad( data.quads[i] );
|
||||
}
|
||||
effects->paintWindow( w, mask, region, data );
|
||||
}
|
||||
|
||||
void SwivelTabsEffect::postPaintWindow( EffectWindow* w )
|
||||
{
|
||||
if( isActive && ( w == windows.show || w == windows.hide ) )
|
||||
w->addRepaintFull();
|
||||
effects->postPaintWindow( w );
|
||||
}
|
||||
|
||||
void SwivelTabsEffect::transformQuad( WindowQuad &quad )
|
||||
{
|
||||
double F = windows.time.progress();
|
||||
int width = quad[1].x()-quad[0].x();
|
||||
int height = quad[3].y() - quad[0].y();
|
||||
int cx = quad[0].x() + ( width/2 );
|
||||
int cy = quad[0].y() + ( height/2 );
|
||||
if( lastF < 0.5 && F > 0.5 )
|
||||
{
|
||||
effects->setElevatedWindow( windows.hide, false );
|
||||
effects->setElevatedWindow( windows.show, true );
|
||||
}
|
||||
lastF = F;
|
||||
if( F >= 1.0 )
|
||||
{
|
||||
isActive = false;
|
||||
effects->setElevatedWindow( windows.hide, false );
|
||||
effects->setElevatedWindow( windows.show, false );
|
||||
}
|
||||
if( F < 0.5 )
|
||||
{
|
||||
if( horizontal )
|
||||
{
|
||||
quad[0].setX( quad[0].x() + ( width * F ) );
|
||||
quad[3].setX( quad[3].x() + ( width * F ) );
|
||||
quad[1].setX( quad[1].x() - ( width * F ) );
|
||||
quad[2].setX( quad[2].x() - ( width * F ) );
|
||||
}
|
||||
if( vertical )
|
||||
{
|
||||
quad[0].setY( quad[0].y() + ( height * F ) );
|
||||
quad[3].setY( quad[3].y() - ( height * F ) );
|
||||
quad[1].setY( quad[1].y() + ( height * F ) );
|
||||
quad[2].setY( quad[2].y() - ( height * F ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
F -= 0.5;
|
||||
if( horizontal )
|
||||
{
|
||||
quad[0].setX( cx - ( width * F ) );
|
||||
quad[3].setX( cx - ( width * F ) );
|
||||
quad[1].setX( cx + ( width * F ) );
|
||||
quad[2].setX( cx + ( width * F ) );
|
||||
}
|
||||
if( vertical )
|
||||
{
|
||||
quad[0].setY( cy - ( height * F ) );
|
||||
quad[3].setY( cy + ( height * F ) );
|
||||
quad[1].setY( cy - ( height * F ) );
|
||||
quad[2].setY( cy + ( height * F ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwivelTabsEffect::clientGroupItemSwitched( EffectWindow* from, EffectWindow* to )
|
||||
{
|
||||
if( isActive || from->isMinimized() )
|
||||
return;
|
||||
windows.show = to;
|
||||
windows.hide = from;
|
||||
windows.time.setCurveShape( TimeLine::LinearCurve );
|
||||
windows.time.setDuration( animationTime( totalTime ) );
|
||||
windows.time.setProgress( 0.0f );
|
||||
lastF = 0.0;
|
||||
isActive = true;
|
||||
effects->setElevatedWindow( to, false );
|
||||
effects->setElevatedWindow( from, true );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
[Desktop Entry]
|
||||
Name=Swivel Tabs
|
||||
Name[x-test]=xxSwivel Tabsxx
|
||||
Icon=preferences-system-windows-effect-swiveltabs
|
||||
Comment=Make the windows turn when switching tabs
|
||||
Comment[x-test]=xxMake the windows turn when switching tabsxx
|
||||
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=KWin/Effect
|
||||
X-KDE-PluginInfo-Author=Jorge Mata
|
||||
X-KDE-PluginInfo-Email=matamax123@gmail.com
|
||||
X-KDE-PluginInfo-Name=kwin4_effect_swiveltabs
|
||||
X-KDE-PluginInfo-Version=0.1.0
|
||||
X-KDE-PluginInfo-Category=Focus
|
||||
X-KDE-PluginInfo-Depends=
|
||||
X-KDE-PluginInfo-License=GPL
|
||||
X-KDE-PluginInfo-EnabledByDefault=false
|
||||
X-KDE-Library=kwin4_effect_builtins
|
|
@ -0,0 +1,62 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef KWIN_SWIVELTABS_H
|
||||
#define KWIN_SWIVELTABS_H
|
||||
|
||||
#include <kwineffects.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class SwivelTabsEffect : public Effect
|
||||
{
|
||||
public:
|
||||
SwivelTabsEffect();
|
||||
virtual void reconfigure( ReconfigureFlags );
|
||||
virtual void prePaintScreen( ScreenPrePaintData& data, int time );
|
||||
virtual void prePaintWindow( EffectWindow *w, WindowPrePaintData &data, int time );
|
||||
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
|
||||
virtual void postPaintWindow( EffectWindow* w );
|
||||
virtual void clientGroupItemSwitched( EffectWindow* from, EffectWindow* to );
|
||||
static bool supported();
|
||||
private:
|
||||
struct swivel
|
||||
{
|
||||
EffectWindow* hide;
|
||||
EffectWindow* show;
|
||||
TimeLine time;
|
||||
// The points of the transformed window
|
||||
QPoint topLeft, topRight, bottomLeft, bottomRight;
|
||||
// The size of the transformed window
|
||||
double left, top, right, bottom;
|
||||
};
|
||||
swivel windows;
|
||||
bool isActive, horizontal, vertical;
|
||||
int totalTime, kal;
|
||||
double PI, lastF;
|
||||
void nextStep( EffectWindow *w );
|
||||
void transformQuad( WindowQuad &quad );
|
||||
double calculateCoords( double original, double space, double newSpace );
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,91 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "swiveltabs_config.h"
|
||||
|
||||
#include <kwineffects.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
KWIN_EFFECT_CONFIG_FACTORY
|
||||
|
||||
SwivelTabsEffectConfigForm::SwivelTabsEffectConfigForm( QWidget* parent ) : QWidget( parent )
|
||||
{
|
||||
setupUi( this );
|
||||
}
|
||||
|
||||
SwivelTabsEffectConfig::SwivelTabsEffectConfig(QWidget* parent, const QVariantList& args)
|
||||
: KCModule( EffectFactory::componentData(), parent, args )
|
||||
{
|
||||
m_ui = new SwivelTabsEffectConfigForm( this );
|
||||
QVBoxLayout* layout = new QVBoxLayout( this );
|
||||
layout->addWidget( m_ui );
|
||||
connect( m_ui->vertical, SIGNAL( toggled( bool )), this, SLOT( changed() ) );
|
||||
connect( m_ui->horizontal, SIGNAL( toggled( bool )), this, SLOT( changed() ) );
|
||||
connect( m_ui->duration, SIGNAL( valueChanged( int ) ), this, SLOT( changed() ) );
|
||||
load();
|
||||
}
|
||||
|
||||
SwivelTabsEffectConfig::~SwivelTabsEffectConfig()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void SwivelTabsEffectConfig::save()
|
||||
{
|
||||
KConfigGroup conf = EffectsHandler::effectConfig( "SwivelTabs" );
|
||||
|
||||
conf.writeEntry( "SwivelVertical", m_ui->vertical->isChecked() );
|
||||
conf.writeEntry( "SwivelHorizontal", m_ui->horizontal->isChecked() );
|
||||
conf.writeEntry( "SwivelDuration", m_ui->duration->value() );
|
||||
|
||||
conf.sync();
|
||||
|
||||
KCModule::save();
|
||||
emit changed( false );
|
||||
EffectsHandler::sendReloadMessage( "swiveltabs" );
|
||||
}
|
||||
|
||||
void SwivelTabsEffectConfig::load()
|
||||
{
|
||||
KCModule::load();
|
||||
KConfigGroup conf = EffectsHandler::effectConfig( "SwivelTabs" );
|
||||
|
||||
bool vertical = conf.readEntry( "SwivelVertical", true );
|
||||
bool horizontal = conf.readEntry( "SwivelHorizontal", true );
|
||||
int duration = conf.readEntry("SwivelDuration", 500 );
|
||||
m_ui->vertical->setChecked( vertical );
|
||||
m_ui->horizontal->setChecked( horizontal );
|
||||
m_ui->duration->setValue( duration );
|
||||
emit changed( false );
|
||||
}
|
||||
|
||||
void SwivelTabsEffectConfig::defaults()
|
||||
{
|
||||
m_ui->vertical->setChecked( true );
|
||||
m_ui->horizontal->setChecked( true );
|
||||
m_ui->duration->setValue( 500 );
|
||||
emit changed( true );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=KCModule
|
||||
|
||||
X-KDE-Library=kcm_kwin4_effect_builtins
|
||||
X-KDE-ParentComponents=kwin4_effect_swiveltabs
|
||||
X-KDE-PluginKeyword=swiveltabs
|
||||
|
||||
Name=Swivel Tabs
|
||||
Name[x-test]=xxSwivel Tabsxx
|
|
@ -0,0 +1,53 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef KWIN_SWIVELTABS_CONFIG_H
|
||||
#define KWIN_SWIVELTABS_CONFIG_H
|
||||
|
||||
#include <kcmodule.h>
|
||||
#include "ui_swiveltabs_config.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class SwivelTabsEffectConfigForm : public QWidget, public Ui::SwivelTabsEffectConfigForm
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SwivelTabsEffectConfigForm( QWidget* parent );
|
||||
};
|
||||
|
||||
class SwivelTabsEffectConfig : public KCModule
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SwivelTabsEffectConfig(QWidget* parent = 0, const QVariantList& args = QVariantList());
|
||||
~SwivelTabsEffectConfig();
|
||||
public slots:
|
||||
virtual void save();
|
||||
virtual void load();
|
||||
virtual void defaults();
|
||||
private:
|
||||
SwivelTabsEffectConfigForm *m_ui;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KWin::SwivelTabsEffectConfigForm</class>
|
||||
<widget class="QWidget" name="KWin::SwivelTabsEffectConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>234</width>
|
||||
<height>102</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="vertical">
|
||||
<property name="text">
|
||||
<string>Vertical</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="horizontal">
|
||||
<property name="text">
|
||||
<string>Horizontal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Duration</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="duration">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>250</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>1</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -1614,6 +1614,8 @@ bool PresentWindowsEffect::isSelectableWindow( EffectWindow *w )
|
|||
return false;
|
||||
if( !w->acceptsFocus() )
|
||||
return false;
|
||||
if( !w->visibleInClientGroup() )
|
||||
return false;
|
||||
switch( m_mode )
|
||||
{
|
||||
case ModeAllDesktops:
|
||||
|
|
|
@ -61,6 +61,18 @@ void SlideBackEffect::windowActivated( EffectWindow* w )
|
|||
return;
|
||||
}
|
||||
|
||||
if( clientItemShown == w )
|
||||
{
|
||||
clientItemShown = NULL;
|
||||
updateStackingOrder();
|
||||
return;
|
||||
}
|
||||
if( clientItemHidden == w )
|
||||
{
|
||||
clientItemHidden = NULL;
|
||||
updateStackingOrder();
|
||||
return;
|
||||
}
|
||||
// Determine all windows on top of the activated one
|
||||
bool currentFound = false;
|
||||
foreach( EffectWindow *tmp, oldStackingOrder )
|
||||
|
@ -351,6 +363,12 @@ void SlideBackEffect::windowUnminimized( EffectWindow* w)
|
|||
}
|
||||
}
|
||||
|
||||
void SlideBackEffect::clientGroupItemSwitched( EffectWindow* from, EffectWindow* to )
|
||||
{
|
||||
clientItemShown = to;
|
||||
clientItemHidden = from;
|
||||
}
|
||||
|
||||
void SlideBackEffect::tabBoxClosed()
|
||||
{
|
||||
disabled = true;
|
||||
|
@ -368,7 +386,8 @@ bool SlideBackEffect::isWindowOnTop( EffectWindow* w )
|
|||
|
||||
bool SlideBackEffect::isWindowUsable( EffectWindow* w )
|
||||
{
|
||||
return w && ( w->isNormalWindow() || w->isDialog() ) && !w->keepAbove() && !w->isDeleted() && !w->isMinimized();
|
||||
return w && ( w->isNormalWindow() || w->isDialog() ) && !w->keepAbove() && !w->isDeleted() && !w->isMinimized()
|
||||
&& w->visibleInClientGroup();
|
||||
}
|
||||
|
||||
bool SlideBackEffect::intersects( EffectWindow* windowUnder, const QRect &windowOverGeometry )
|
||||
|
|
|
@ -45,6 +45,7 @@ class SlideBackEffect
|
|||
virtual void windowDeleted( EffectWindow* w );
|
||||
virtual void windowAdded( EffectWindow* w );
|
||||
virtual void windowUnminimized( EffectWindow* w );
|
||||
virtual void clientGroupItemSwitched( EffectWindow* from, EffectWindow* to );
|
||||
|
||||
virtual void tabBoxClosed();
|
||||
|
||||
|
@ -56,6 +57,8 @@ class SlideBackEffect
|
|||
EffectWindowList coveringWindows;
|
||||
EffectWindowList elevatedList;
|
||||
EffectWindow* unminimizedWindow;
|
||||
EffectWindow* clientItemShown;
|
||||
EffectWindow* clientItemHidden;
|
||||
QHash<EffectWindow *, QRect> destinationList;
|
||||
bool disabled;
|
||||
QList <QRegion> clippedRegions;
|
||||
|
|
|
@ -1367,6 +1367,8 @@ bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int
|
|||
QPoint mousepos( x_root - x, y_root - y );
|
||||
mode = mousePosition( mousepos );
|
||||
}
|
||||
else if( workspace()->decorationSupportsClientGrouping() )
|
||||
return false;
|
||||
updateCursor();
|
||||
}
|
||||
return true;
|
||||
|
|
26
geometry.cpp
26
geometry.cpp
|
@ -402,6 +402,7 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos, bool unrestricted
|
|||
{
|
||||
if ((*l)->isOnDesktop(c->desktop()) &&
|
||||
!(*l)->isMinimized()
|
||||
&& (!(*l)->clientGroup() || (*l) != (*l)->clientGroup()->visible())
|
||||
&& (*l) != c )
|
||||
{
|
||||
lx = (*l)->x();
|
||||
|
@ -1345,8 +1346,8 @@ QSize Client::sizeForClientSize( const QSize& wsize, Sizemode mode, bool noframe
|
|||
|
||||
// basesize, minsize, maxsize, paspect and resizeinc have all values defined,
|
||||
// even if they're not set in flags - see getWmNormalHints()
|
||||
QSize min_size = minSize();
|
||||
QSize max_size = maxSize();
|
||||
QSize min_size = clientGroup() ? clientGroup()->minSize() : minSize();
|
||||
QSize max_size = clientGroup() ? clientGroup()->maxSize() : maxSize();
|
||||
if( decoration != NULL )
|
||||
{
|
||||
QSize decominsize = decoration->minimumSize();
|
||||
|
@ -1902,8 +1903,8 @@ bool Client::isResizable() const
|
|||
if( rules()->checkSize( QSize()).isValid()) // forced size
|
||||
return false;
|
||||
|
||||
QSize min = minSize();
|
||||
QSize max = maxSize();
|
||||
QSize min = clientGroup() ? clientGroup()->minSize() : minSize();
|
||||
QSize max = clientGroup() ? clientGroup()->maxSize() : maxSize();
|
||||
return min.width() < max.width() || min.height() < max.height();
|
||||
}
|
||||
|
||||
|
@ -2025,6 +2026,10 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
|
|||
addWorkspaceRepaint( deco_rect );
|
||||
geom_before_block = geom;
|
||||
deco_rect_before_block = deco_rect;
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
void Client::plainResize( int w, int h, ForceGeometry_t force )
|
||||
|
@ -2097,6 +2102,10 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
|
|||
addWorkspaceRepaint( deco_rect );
|
||||
geom_before_block = geom;
|
||||
deco_rect_before_block = deco_rect;
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -2138,6 +2147,10 @@ void Client::move( int x, int y, ForceGeometry_t force )
|
|||
addWorkspaceRepaint( deco_rect ); // trigger repaint of window's new location
|
||||
geom_before_block = geom;
|
||||
deco_rect_before_block = deco_rect;
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
void Client::blockGeometryUpdates( bool block )
|
||||
|
@ -2181,6 +2194,10 @@ void Client::setMaximize( bool vertically, bool horizontally )
|
|||
false );
|
||||
if( effects )
|
||||
static_cast<EffectsHandlerImpl*>(effects)->windowUserMovedResized( effectWindow(), true, true );
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
|
||||
|
@ -3005,7 +3022,6 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
|
|||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
// adjust new size to snap to other windows/borders
|
||||
moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode );
|
||||
|
||||
|
|
|
@ -467,6 +467,58 @@ bool KDecorationPreviewBridge::compositingActive() const
|
|||
return KWindowSystem::compositingActive();
|
||||
}
|
||||
|
||||
// Window tabbing
|
||||
|
||||
bool KDecorationPreviewBridge::isClientGroupActive()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
QList< ClientGroupItem > KDecorationPreviewBridge::clientGroupItems() const
|
||||
{
|
||||
return QList< ClientGroupItem >() << ClientGroupItem(
|
||||
active ? "Active Window" : "Inactive Window", icon() );
|
||||
}
|
||||
|
||||
int KDecorationPreviewBridge::itemId( int )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int KDecorationPreviewBridge::visibleClientGroupItem()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void KDecorationPreviewBridge::setVisibleClientGroupItem( int )
|
||||
{
|
||||
}
|
||||
|
||||
void KDecorationPreviewBridge::moveItemInClientGroup( int, int )
|
||||
{
|
||||
}
|
||||
|
||||
void KDecorationPreviewBridge::moveItemToClientGroup( int, int )
|
||||
{
|
||||
}
|
||||
|
||||
void KDecorationPreviewBridge::removeFromClientGroup( int, const QRect& )
|
||||
{
|
||||
}
|
||||
|
||||
void KDecorationPreviewBridge::closeClientGroupItem( int )
|
||||
{
|
||||
}
|
||||
|
||||
void KDecorationPreviewBridge::closeAllInClientGroup()
|
||||
{
|
||||
}
|
||||
|
||||
void KDecorationPreviewBridge::displayClientMenu( int, const QPoint& )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KDecorationPreviewOptions::KDecorationPreviewOptions()
|
||||
{
|
||||
customBorderSize = BordersCount; // invalid
|
||||
|
|
|
@ -115,6 +115,20 @@ class KDecorationPreviewBridge
|
|||
virtual void grabXServer( bool grab );
|
||||
|
||||
virtual bool compositingActive() const;
|
||||
|
||||
// Window tabbing
|
||||
virtual bool isClientGroupActive();
|
||||
virtual QList< ClientGroupItem > clientGroupItems() const;
|
||||
virtual int itemId( int index );
|
||||
virtual int visibleClientGroupItem();
|
||||
virtual void setVisibleClientGroupItem( int index );
|
||||
virtual void moveItemInClientGroup( int index, int before );
|
||||
virtual void moveItemToClientGroup( int itemId, int before );
|
||||
virtual void removeFromClientGroup( int index, const QRect& newGeom );
|
||||
virtual void closeClientGroupItem( int index );
|
||||
virtual void closeAllInClientGroup();
|
||||
virtual void displayClientMenu( int index, const QPoint& pos );
|
||||
|
||||
private:
|
||||
KDecorationPreview* preview;
|
||||
bool active;
|
||||
|
|
|
@ -54,6 +54,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
a->setText( i18n("Navigation") );
|
||||
DEF( I18N_NOOP("Walk Through Windows"), Qt::ALT+Qt::Key_Tab, slotWalkThroughWindows() );
|
||||
DEF( I18N_NOOP("Walk Through Windows (Reverse)"), Qt::ALT+Qt::SHIFT+Qt::Key_Backtab, slotWalkBackThroughWindows() );
|
||||
DEF( I18N_NOOP("Walk Through Grouped Windows"), 0, slotSwitchToTabRight() );
|
||||
DEF( I18N_NOOP("Walk Through Grouped Windows (Reverse)"), 0, slotSwitchToTabLeft() );
|
||||
DEF( I18N_NOOP("Remove Window From Group"), 0, slotRemoveFromGroup() );
|
||||
DEF( I18N_NOOP("Walk Through Windows Alternative"), 0, slotWalkThroughWindowsAlternative() );
|
||||
DEF( I18N_NOOP("Walk Through Windows Alternative (Reverse)"), 0, slotWalkBackThroughWindowsAlternative() );
|
||||
DEF( I18N_NOOP("Walk Through Desktops"), 0, slotWalkThroughDesktops() );
|
||||
|
|
|
@ -820,6 +820,10 @@ void Client::setKeepAbove( bool b )
|
|||
decoration->emitKeepAboveChanged( keepAbove());
|
||||
workspace()->updateClientLayer( this );
|
||||
updateWindowRules();
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
void Client::setKeepBelow( bool b )
|
||||
|
@ -839,6 +843,10 @@ void Client::setKeepBelow( bool b )
|
|||
decoration->emitKeepBelowChanged( keepBelow());
|
||||
workspace()->updateClientLayer( this );
|
||||
updateWindowRules();
|
||||
|
||||
// Update states of all other windows in this group
|
||||
if( clientGroup() )
|
||||
clientGroup()->updateStates( this );
|
||||
}
|
||||
|
||||
Layer Client::layer() const
|
||||
|
|
|
@ -1279,5 +1279,67 @@ bool KCommonDecorationUnstable::compositingActive() const
|
|||
return static_cast<const KDecorationUnstable*>( decoration() )->compositingActive();
|
||||
}
|
||||
|
||||
// Window tabbing
|
||||
|
||||
bool KCommonDecorationUnstable::isClientGroupActive()
|
||||
{
|
||||
return static_cast<const KDecorationUnstable*>( decoration() )->isClientGroupActive();
|
||||
}
|
||||
|
||||
QList< ClientGroupItem > KCommonDecorationUnstable::clientGroupItems() const
|
||||
{
|
||||
return static_cast<const KDecorationUnstable*>( decoration() )->clientGroupItems();
|
||||
}
|
||||
|
||||
int KCommonDecorationUnstable::itemId( int index )
|
||||
{
|
||||
return static_cast<const KDecorationUnstable*>( decoration() )->itemId( index );
|
||||
}
|
||||
|
||||
int KCommonDecorationUnstable::visibleClientGroupItem()
|
||||
{
|
||||
return static_cast<const KDecorationUnstable*>( decoration() )->visibleClientGroupItem();
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::setVisibleClientGroupItem( int index )
|
||||
{
|
||||
static_cast<const KDecorationUnstable*>( decoration() )->setVisibleClientGroupItem( index );
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::moveItemInClientGroup( int index, int before )
|
||||
{
|
||||
static_cast<const KDecorationUnstable*>( decoration() )->moveItemInClientGroup( index, before );
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::moveItemToClientGroup( int itemId, int before )
|
||||
{
|
||||
static_cast<const KDecorationUnstable*>( decoration() )->moveItemToClientGroup( itemId, before );
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::removeFromClientGroup( int index, const QRect& newGeom )
|
||||
{
|
||||
static_cast<const KDecorationUnstable*>( decoration() )->removeFromClientGroup( index, newGeom );
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::closeClientGroupItem( int index )
|
||||
{
|
||||
static_cast<const KDecorationUnstable*>( decoration() )->closeClientGroupItem( index );
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::closeAllInClientGroup()
|
||||
{
|
||||
static_cast<const KDecorationUnstable*>( decoration() )->closeAllInClientGroup();
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::displayClientMenu( int index, const QPoint& pos )
|
||||
{
|
||||
static_cast<const KDecorationUnstable*>( decoration() )->displayClientMenu( index, pos );
|
||||
}
|
||||
|
||||
bool KCommonDecorationUnstable::eventFilter( QObject* o, QEvent* e )
|
||||
{
|
||||
return KCommonDecoration::eventFilter( o, e );
|
||||
}
|
||||
|
||||
// kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle;
|
||||
|
||||
|
|
|
@ -44,7 +44,9 @@ enum ButtonType {
|
|||
AboveButton,
|
||||
BelowButton,
|
||||
ShadeButton,
|
||||
NumButtons
|
||||
NumButtons,
|
||||
ItemCloseButton=100, // Close only one tab
|
||||
ItemMenuButton // shows the window menu for one tab
|
||||
};
|
||||
|
||||
class KCommonDecorationButton;
|
||||
|
@ -378,6 +380,21 @@ class KWIN_EXPORT KCommonDecorationUnstable
|
|||
KCommonDecorationUnstable(KDecorationBridge* bridge, KDecorationFactory* factory);
|
||||
virtual ~KCommonDecorationUnstable();
|
||||
bool compositingActive() const;
|
||||
|
||||
// Window tabbing
|
||||
bool isClientGroupActive();
|
||||
QList< ClientGroupItem > clientGroupItems() const;
|
||||
int itemId( int index );
|
||||
int visibleClientGroupItem();
|
||||
void setVisibleClientGroupItem( int index );
|
||||
void moveItemInClientGroup( int index, int before );
|
||||
void moveItemToClientGroup( int itemId, int before = -1 );
|
||||
void removeFromClientGroup( int index, const QRect& newGeom = QRect() );
|
||||
void closeClientGroupItem( int index );
|
||||
void closeAllInClientGroup();
|
||||
void displayClientMenu( int index, const QPoint& pos );
|
||||
|
||||
virtual bool eventFilter( QObject* o, QEvent* e );
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -403,6 +403,69 @@ void KDecorationUnstable::padding(int &left, int &right, int &top, int &bottom)
|
|||
left = right = top = bottom = 0;
|
||||
}
|
||||
|
||||
// Window tabbing
|
||||
|
||||
bool KDecorationUnstable::isClientGroupActive()
|
||||
{
|
||||
return static_cast< KDecorationBridgeUnstable* >( bridge_ )->isClientGroupActive();
|
||||
}
|
||||
|
||||
QList< ClientGroupItem > KDecorationUnstable::clientGroupItems() const
|
||||
{
|
||||
return static_cast< KDecorationBridgeUnstable* >( bridge_ )->clientGroupItems();
|
||||
}
|
||||
|
||||
int KDecorationUnstable::itemId( int index )
|
||||
{
|
||||
return static_cast< KDecorationBridgeUnstable* >( bridge_ )->itemId( index );
|
||||
}
|
||||
|
||||
int KDecorationUnstable::visibleClientGroupItem()
|
||||
{
|
||||
return static_cast< KDecorationBridgeUnstable* >( bridge_ )->visibleClientGroupItem();
|
||||
}
|
||||
|
||||
void KDecorationUnstable::setVisibleClientGroupItem( int index )
|
||||
{
|
||||
static_cast< KDecorationBridgeUnstable* >( bridge_ )->setVisibleClientGroupItem( index );
|
||||
}
|
||||
|
||||
void KDecorationUnstable::moveItemInClientGroup( int index, int before )
|
||||
{
|
||||
static_cast< KDecorationBridgeUnstable* >( bridge_ )->moveItemInClientGroup( index, before );
|
||||
}
|
||||
|
||||
void KDecorationUnstable::moveItemToClientGroup( int itemId, int before )
|
||||
{
|
||||
static_cast< KDecorationBridgeUnstable* >( bridge_ )->moveItemToClientGroup( itemId, before );
|
||||
}
|
||||
|
||||
void KDecorationUnstable::removeFromClientGroup( int index, const QRect& newGeom )
|
||||
{
|
||||
static_cast< KDecorationBridgeUnstable* >( bridge_ )->removeFromClientGroup( index, newGeom );
|
||||
}
|
||||
|
||||
void KDecorationUnstable::closeClientGroupItem( int index )
|
||||
{
|
||||
static_cast< KDecorationBridgeUnstable* >( bridge_ )->closeClientGroupItem( index );
|
||||
}
|
||||
|
||||
void KDecorationUnstable::closeAllInClientGroup()
|
||||
{
|
||||
static_cast< KDecorationBridgeUnstable* >( bridge_ )->closeAllInClientGroup();
|
||||
}
|
||||
|
||||
void KDecorationUnstable::displayClientMenu( int index, const QPoint& pos )
|
||||
{
|
||||
static_cast< KDecorationBridgeUnstable* >( bridge_ )->displayClientMenu( index, pos );
|
||||
}
|
||||
|
||||
|
||||
QString KDecorationDefines::clientGroupItemDragMimeType()
|
||||
{
|
||||
return "text/ClientGroupItem";
|
||||
}
|
||||
|
||||
KDecorationOptions::KDecorationOptions()
|
||||
: d( new KDecorationOptionsPrivate )
|
||||
{
|
||||
|
|
|
@ -105,7 +105,11 @@ public:
|
|||
NoBorderOp,
|
||||
NoOp,
|
||||
SetupWindowShortcutOp,
|
||||
ApplicationRulesOp
|
||||
ApplicationRulesOp,
|
||||
RemoveClientFromGroupOp, // Remove from group
|
||||
CloseClientGroupOp, // Close the group
|
||||
MoveClientInGroupLeftOp, // Move left in the group
|
||||
MoveClientInGroupRightOp // Move right in the group
|
||||
};
|
||||
/**
|
||||
* Basic color types that should be recognized by all decoration styles.
|
||||
|
@ -192,11 +196,42 @@ public:
|
|||
/// The mask is still used to define the input region and the blurred
|
||||
/// region, when the blur plugin is enabled.
|
||||
/// @since 4.3
|
||||
// Tabbing
|
||||
AbilityClientGrouping = 4000, ///< The decoration supports tabbing
|
||||
// TODO colors for individual button types
|
||||
ABILITY_DUMMY = 10000000
|
||||
};
|
||||
|
||||
enum Requirement { REQUIREMENT_DUMMY = 1000000 };
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns mimeType used to drag and drop clientGroupItems
|
||||
*/
|
||||
|
||||
static QString clientGroupItemDragMimeType();
|
||||
|
||||
};
|
||||
|
||||
class KWIN_EXPORT ClientGroupItem
|
||||
{
|
||||
public:
|
||||
ClientGroupItem( QString t, QIcon i )
|
||||
{
|
||||
title_ = t;
|
||||
icon_ = i;
|
||||
}
|
||||
inline QIcon icon() const
|
||||
{
|
||||
return icon_;
|
||||
}
|
||||
inline QString title() const
|
||||
{
|
||||
return title_;
|
||||
}
|
||||
private:
|
||||
QString title_;
|
||||
QIcon icon_;
|
||||
};
|
||||
|
||||
class KDecorationProvides
|
||||
|
@ -672,6 +707,7 @@ class KWIN_EXPORT KDecoration
|
|||
* isShade() to get the current state.
|
||||
*/
|
||||
virtual void shadeChange() = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal is emitted whenever the window's keep-above state changes.
|
||||
|
@ -681,6 +717,7 @@ class KWIN_EXPORT KDecoration
|
|||
* This signal is emitted whenever the window's keep-below state changes.
|
||||
*/
|
||||
void keepBelowChanged( bool );
|
||||
|
||||
public:
|
||||
/**
|
||||
* This function may be reimplemented to provide custom bound drawing
|
||||
|
@ -848,6 +885,7 @@ class KWIN_EXPORT KDecoration
|
|||
* @internal
|
||||
*/
|
||||
void emitKeepBelowChanged( bool below );
|
||||
|
||||
private:
|
||||
KDecorationBridge* bridge_;
|
||||
QWidget* w_;
|
||||
|
@ -856,6 +894,7 @@ class KWIN_EXPORT KDecoration
|
|||
friend class KDecorationUnstable; // for bridge_
|
||||
static KDecorationOptions* options_;
|
||||
KDecorationPrivate* d;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -884,6 +923,62 @@ class KWIN_EXPORT KDecorationUnstable
|
|||
* Returns @a true if compositing--and therefore ARGB--is enabled.
|
||||
*/
|
||||
bool compositingActive() const;
|
||||
|
||||
// Window tabbing
|
||||
|
||||
/**
|
||||
* Returns whether or not this client group contains the active client.
|
||||
*/
|
||||
bool isClientGroupActive();
|
||||
/**
|
||||
* Return a list of all the clients in the group that contains the client that this
|
||||
* decoration is attached to.
|
||||
*/
|
||||
QList< ClientGroupItem > clientGroupItems() const;
|
||||
/**
|
||||
* Returns a unique identifier for the client at index \p index of the client group list.
|
||||
* \see moveItemToClientGroup()
|
||||
*/
|
||||
int itemId( int index );
|
||||
/**
|
||||
* Returns the list index of the currently visible client in this group.
|
||||
*/
|
||||
int visibleClientGroupItem();
|
||||
/**
|
||||
* Switch the currently visible client to the one at list index \p index.
|
||||
*/
|
||||
void setVisibleClientGroupItem( int index );
|
||||
/**
|
||||
* Move the client at index \p index to the position before the client at index \p before.
|
||||
*/
|
||||
void moveItemInClientGroup( int index, int before );
|
||||
/**
|
||||
* Move the client that's unique identifier is \p itemId to the position before the client
|
||||
* at index \p before if set, otherwise the end of the list. This call is to move clients
|
||||
* between two different groups, if moving in the same group then use
|
||||
* moveItemInClientGroup() instead.
|
||||
* \see itemId()
|
||||
*/
|
||||
void moveItemToClientGroup( int itemId, int before = -1 );
|
||||
/**
|
||||
* Remove the client at index \p index from the group. If \p newGeom is set then the client
|
||||
* will move and resize to the specified geometry, otherwise it will stay where the group
|
||||
* is located.
|
||||
*/
|
||||
void removeFromClientGroup( int index, const QRect& newGeom = QRect() );
|
||||
/**
|
||||
* Close the client at index \p index.
|
||||
*/
|
||||
void closeClientGroupItem( int index );
|
||||
/**
|
||||
* Close all windows in this group.
|
||||
*/
|
||||
void closeAllInClientGroup();
|
||||
/**
|
||||
* Display the right-click client menu belonging to the client at index \p index at the
|
||||
* global coordinates specified by \p pos.
|
||||
*/
|
||||
void displayClientMenu( int index, const QPoint& pos );
|
||||
};
|
||||
|
||||
inline
|
||||
|
|
|
@ -94,6 +94,19 @@ class KWIN_EXPORT KDecorationBridgeUnstable
|
|||
{
|
||||
public:
|
||||
virtual bool compositingActive() const = 0;
|
||||
|
||||
// Window tabbing
|
||||
virtual bool isClientGroupActive() = 0;
|
||||
virtual QList< ClientGroupItem > clientGroupItems() const = 0;
|
||||
virtual int itemId( int index ) = 0;
|
||||
virtual int visibleClientGroupItem() = 0;
|
||||
virtual void setVisibleClientGroupItem( int index ) = 0;
|
||||
virtual void moveItemInClientGroup( int index, int before ) = 0;
|
||||
virtual void moveItemToClientGroup( int itemId, int before ) = 0;
|
||||
virtual void removeFromClientGroup( int index, const QRect& newGeom ) = 0;
|
||||
virtual void closeClientGroupItem( int index ) = 0;
|
||||
virtual void closeAllInClientGroup() = 0;
|
||||
virtual void displayClientMenu( int index, const QPoint& pos ) = 0;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -155,6 +155,18 @@ void Effect::windowUnminimized( EffectWindow* )
|
|||
{
|
||||
}
|
||||
|
||||
void Effect::clientGroupItemSwitched( EffectWindow* from, EffectWindow* to )
|
||||
{
|
||||
}
|
||||
|
||||
void Effect::clientGroupItemAdded( EffectWindow* from, EffectWindow* to )
|
||||
{
|
||||
}
|
||||
|
||||
void Effect::clientGroupItemRemoved( EffectWindow* c, EffectWindow* group )
|
||||
{
|
||||
}
|
||||
|
||||
void Effect::windowInputMouseEvent( Window, QEvent* )
|
||||
{
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ X-KDE-Library=kwin4_effect_cooleffect
|
|||
|
||||
#define KWIN_EFFECT_API_MAKE_VERSION( major, minor ) (( major ) << 8 | ( minor ))
|
||||
#define KWIN_EFFECT_API_VERSION_MAJOR 0
|
||||
#define KWIN_EFFECT_API_VERSION_MINOR 106
|
||||
#define KWIN_EFFECT_API_VERSION_MINOR 107
|
||||
#define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \
|
||||
KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR )
|
||||
|
||||
|
@ -393,6 +393,9 @@ class KWIN_EXPORT Effect
|
|||
virtual void windowActivated( EffectWindow* c );
|
||||
virtual void windowMinimized( EffectWindow* c );
|
||||
virtual void windowUnminimized( EffectWindow* c );
|
||||
virtual void clientGroupItemSwitched( EffectWindow* from, EffectWindow* to );
|
||||
virtual void clientGroupItemAdded( EffectWindow* from, EffectWindow* to ); // from merged with to
|
||||
virtual void clientGroupItemRemoved( EffectWindow* c, EffectWindow* group ); // c removed from group
|
||||
virtual void windowInputMouseEvent( Window w, QEvent* e );
|
||||
virtual void desktopChanged( int old );
|
||||
virtual void windowDamaged( EffectWindow* w, const QRect& r );
|
||||
|
@ -956,6 +959,8 @@ class KWIN_EXPORT EffectWindow
|
|||
virtual void minimize() const = 0;
|
||||
virtual void unminimize() const = 0;
|
||||
virtual void closeWindow() const = 0;
|
||||
|
||||
virtual bool visibleInClientGroup() const = 0;
|
||||
};
|
||||
|
||||
class KWIN_EXPORT EffectWindowGroup
|
||||
|
|
20
manage.cpp
20
manage.cpp
|
@ -296,6 +296,26 @@ bool Client::manage( Window w, bool isMapped )
|
|||
if( placementDone )
|
||||
move( geom.x(), geom.y() ); // Before gravitating
|
||||
|
||||
// Create client group if the window will have a decoration
|
||||
if( !noBorder() )
|
||||
{
|
||||
client_group = NULL;
|
||||
// Automatically add to previous groups on session restore
|
||||
if( session && session->clientGroupClient && session->clientGroupClient != this )
|
||||
session->clientGroupClient->clientGroup()->add( this, -1, true );
|
||||
else if( isMapped )
|
||||
// If the window is already mapped (Restarted KWin) add any windows that already have the
|
||||
// same geometry to the same client group. (May incorrectly handle maximized windows)
|
||||
foreach( ClientGroup* group, workspace()->clientGroups )
|
||||
if( geom == QRect( group->visible()->pos(), group->visible()->clientSize() ))
|
||||
{
|
||||
group->add( this, -1, true );
|
||||
break;
|
||||
}
|
||||
if( !client_group )
|
||||
client_group = new ClientGroup( this );
|
||||
}
|
||||
|
||||
updateDecoration( false ); // Also gravitates
|
||||
// TODO: Is CentralGravity right here, when resizing is done after gravitating?
|
||||
plainResize( rules()->checkSize( sizeForClientSize( geom.size() ), !isMapped ));
|
||||
|
|
13
sm.cpp
13
sm.cpp
|
@ -127,6 +127,10 @@ void Workspace::storeSession( KConfig* config, SMSavePhase phase )
|
|||
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 ));
|
||||
int group = 0;
|
||||
if( c->clientGroup() )
|
||||
group = c->clientGroup()->clients().count() > 1 ? (int) c->clientGroup() : 0;
|
||||
cg.writeEntry( QString("clientGroup")+n, group );
|
||||
}
|
||||
}
|
||||
if( phase == SMSavePhase0 )
|
||||
|
@ -193,6 +197,8 @@ void Workspace::loadSessionInfo()
|
|||
info->shortcut = cg.readEntry( QString("shortcut")+n, QString() );
|
||||
info->active = ( active_client == i );
|
||||
info->stackingOrder = cg.readEntry( QString("stackingOrder")+n, -1 );
|
||||
info->clientGroup = cg.readEntry( QString("clientGroup")+n, 0 );
|
||||
info->clientGroupClient = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,6 +272,13 @@ SessionInfo* Workspace::takeSessionInfo( Client* c )
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set clientGroupClient for other clients in the same group
|
||||
if( realInfo && realInfo->clientGroup )
|
||||
foreach( SessionInfo* info, session )
|
||||
if( !info->clientGroupClient && info->clientGroup == realInfo->clientGroup )
|
||||
info->clientGroupClient = c;
|
||||
|
||||
return realInfo;
|
||||
}
|
||||
|
||||
|
|
5
sm.h
5
sm.h
|
@ -34,6 +34,8 @@ class QSocketNotifier;
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
class Client;
|
||||
|
||||
struct SessionInfo
|
||||
{
|
||||
QByteArray sessionId;
|
||||
|
@ -62,6 +64,9 @@ struct SessionInfo
|
|||
bool active; // means 'was active in the saved session'
|
||||
int stackingOrder;
|
||||
float opacity;
|
||||
int clientGroup; // Unique identifier for the client group that this window is in
|
||||
|
||||
Client* clientGroupClient; // The first client created that has an identical identifier
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -859,6 +859,15 @@ void Workspace::slotWalkBackThroughWindowsKeyChanged( const QKeySequence& seq )
|
|||
cutWalkThroughWindowsReverse = KShortcut( seq );
|
||||
}
|
||||
|
||||
void Workspace::slotMoveToTabLeftKeyChanged( const QKeySequence& seq )
|
||||
{
|
||||
cutWalkThroughGroupWindows = KShortcut( seq );
|
||||
}
|
||||
void Workspace::slotMoveToTabRightKeyChanged( const QKeySequence& seq )
|
||||
{
|
||||
cutWalkThroughGroupWindowsReverse = KShortcut( seq );
|
||||
}
|
||||
|
||||
void Workspace::slotWalkThroughWindowsAlternativeKeyChanged( const QKeySequence& seq )
|
||||
{
|
||||
cutWalkThroughWindowsAlternative = KShortcut( seq );
|
||||
|
|
222
useractions.cpp
222
useractions.cpp
|
@ -167,6 +167,27 @@ QMenu* Workspace::clientPopup()
|
|||
mShadeOpAction->setCheckable( true );
|
||||
mShadeOpAction->setData( Options::ShadeOp );
|
||||
|
||||
popup->addSeparator();
|
||||
|
||||
// Actions for window tabbing
|
||||
if( decorationSupportsClientGrouping() )
|
||||
{
|
||||
mRemoveTabGroup = popup->addAction( i18n("Remove &from group") );
|
||||
kaction = qobject_cast<KAction*>( keys->action("Remove TabGroup") );
|
||||
if( kaction!=0 )
|
||||
mRemoveTabGroup->setShortcut( kaction->globalShortcut().primary() );
|
||||
mRemoveTabGroup->setData( Options::RemoveClientFromGroupOp );
|
||||
|
||||
mCloseGroup = popup->addAction( i18n("Close entire &group") );
|
||||
mCloseGroup->setIcon( KIcon( "window-close" ) );
|
||||
kaction = qobject_cast<KAction*>( keys->action("Close TabGroup") );
|
||||
if( kaction!=0 )
|
||||
mCloseGroup->setShortcut( kaction->globalShortcut().primary() );
|
||||
mCloseGroup->setData( Options::CloseClientGroupOp );
|
||||
|
||||
popup->addSeparator();
|
||||
}
|
||||
|
||||
action = popup->addMenu( advanced_popup );
|
||||
action->setText( i18n("Ad&vanced") );
|
||||
|
||||
|
@ -196,6 +217,8 @@ void Workspace::discardPopup()
|
|||
delete popup;
|
||||
popup = NULL;
|
||||
desk_popup = NULL;
|
||||
switch_to_tab_popup = NULL;
|
||||
add_tabs_popup = NULL;
|
||||
}
|
||||
|
||||
void Workspace::setPopupClientOpacity( QAction* action )
|
||||
|
@ -240,6 +263,22 @@ void Workspace::clientPopupAboutToShow()
|
|||
mNoBorderOpAction->setChecked( active_popup_client->noBorder() );
|
||||
mMinimizeOpAction->setEnabled( active_popup_client->isMinimizable() );
|
||||
mCloseOpAction->setEnabled( active_popup_client->isCloseable() );
|
||||
|
||||
delete switch_to_tab_popup;
|
||||
switch_to_tab_popup = 0;
|
||||
delete add_tabs_popup;
|
||||
add_tabs_popup = 0;
|
||||
if( decorationSupportsClientGrouping() )
|
||||
{
|
||||
const int tabGroupSize = active_popup_client->clientGroup()->items().count();
|
||||
if( tabGroupSize > 1 )
|
||||
initSwitchToTab();
|
||||
initAddToTabGroup();
|
||||
|
||||
mRemoveTabGroup->setVisible( tabGroupSize > 1 );
|
||||
mCloseGroup->setVisible( tabGroupSize > 1 );
|
||||
}
|
||||
|
||||
if( trans_popup != NULL )
|
||||
{
|
||||
foreach( QAction* action, trans_popup->actions())
|
||||
|
@ -252,6 +291,118 @@ void Workspace::clientPopupAboutToShow()
|
|||
}
|
||||
}
|
||||
|
||||
void Workspace::initSwitchToTab()
|
||||
{
|
||||
if( switch_to_tab_popup )
|
||||
return;
|
||||
switch_to_tab_popup = new QMenu( popup );
|
||||
switch_to_tab_popup->setFont( KGlobalSettings::menuFont() );
|
||||
connect( switch_to_tab_popup, SIGNAL( triggered( QAction* ) ),
|
||||
this, SLOT( slotSwitchToTab( QAction* ) ) );
|
||||
connect( switch_to_tab_popup, SIGNAL( aboutToShow() ),
|
||||
this, SLOT( switchToTabPopupAboutToShow() ) );
|
||||
|
||||
QAction* action = switch_to_tab_popup->menuAction();
|
||||
popup->insertAction( mRemoveTabGroup, action );
|
||||
action->setText( i18n("Switch to group window") );
|
||||
}
|
||||
|
||||
void Workspace::slotSwitchToTab( QAction* action )
|
||||
{
|
||||
int side = action->data().toInt();
|
||||
int c_id = active_popup_client->clientGroup()->indexOfClient( active_popup_client );
|
||||
int size = active_popup_client->clientGroup()->clients().count();
|
||||
if( side == 0 ) // Left
|
||||
{
|
||||
if( c_id > 0 )
|
||||
active_popup_client->clientGroup()->setVisible( c_id - 1 );
|
||||
else
|
||||
active_popup_client->clientGroup()->setVisible( size - 1 );
|
||||
}
|
||||
else if( side == 1 ) // Right
|
||||
{
|
||||
if( c_id < size - 1 )
|
||||
active_popup_client->clientGroup()->setVisible( c_id + 1 );
|
||||
else
|
||||
active_popup_client->clientGroup()->setVisible( 0 );
|
||||
}
|
||||
else // Find the client
|
||||
{
|
||||
side -= 2;
|
||||
for( QList<ClientGroup*>::const_iterator i = clientGroups.begin(); i != clientGroups.end(); ++i )
|
||||
{
|
||||
if( (*i)->contains( active_popup_client ))
|
||||
{
|
||||
(*i)->setVisible( side );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::switchToTabPopupAboutToShow()
|
||||
{
|
||||
if( !switch_to_tab_popup )
|
||||
return;
|
||||
switch_to_tab_popup->clear();
|
||||
QAction* action = switch_to_tab_popup->addAction( i18n( "To the left" ));
|
||||
action->setData( 0 );
|
||||
action = switch_to_tab_popup->addAction( i18n( "To the right" ));
|
||||
action->setData( 1 );
|
||||
switch_to_tab_popup->addSeparator();
|
||||
int index = 2;
|
||||
foreach( Client* c, active_popup_client->clientGroup()->clients() )
|
||||
{
|
||||
if( c != active_popup_client )
|
||||
{
|
||||
action = switch_to_tab_popup->addAction( c->caption() );
|
||||
action->setData( index );
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Workspace::initAddToTabGroup()
|
||||
{
|
||||
if( add_tabs_popup )
|
||||
return;
|
||||
add_tabs_popup = new QMenu( popup );
|
||||
add_tabs_popup->setFont( KGlobalSettings::menuFont() );
|
||||
connect( add_tabs_popup, SIGNAL( triggered( QAction* ) ),
|
||||
this, SLOT( slotAddToTabGroup( QAction* ) ) ); // Merge to a group
|
||||
connect( add_tabs_popup, SIGNAL( aboutToShow() ),
|
||||
this, SLOT( groupTabPopupAboutToShow() ) ); // Show the possible groups to add
|
||||
|
||||
QAction* action = add_tabs_popup->menuAction();
|
||||
popup->insertAction( mRemoveTabGroup, action );
|
||||
action->setText( i18n("Move window to group") );
|
||||
}
|
||||
|
||||
void Workspace::slotAddToTabGroup( QAction* action )
|
||||
{
|
||||
if( !action->data().isValid() )
|
||||
return;
|
||||
moveItemToClientGroup( active_popup_client->clientGroup(),
|
||||
active_popup_client->clientGroup()->indexOfClient( active_popup_client ),
|
||||
clientGroups[action->data().toInt()], -1 );
|
||||
}
|
||||
|
||||
void Workspace::groupTabPopupAboutToShow()
|
||||
{
|
||||
if( !add_tabs_popup )
|
||||
return;
|
||||
add_tabs_popup->clear();
|
||||
int index = 0;
|
||||
for( QList<ClientGroup*>::const_iterator i = clientGroups.begin(); i != clientGroups.end(); i++, index++ )
|
||||
{
|
||||
if( !(*i)->contains( active_popup_client ))
|
||||
{
|
||||
QAction* action = add_tabs_popup->addAction( (*i)->visible()->caption() );
|
||||
action->setData( index );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::initDesktopPopup()
|
||||
{
|
||||
|
@ -382,6 +533,22 @@ void Workspace::readShortcuts()
|
|||
connect( kaction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(slotWalkBackThroughWindowsKeyChanged(QKeySequence)));
|
||||
}
|
||||
|
||||
kaction = qobject_cast<KAction*>( keys->action("Walk Through Group Windows") );
|
||||
if( kaction != 0 )
|
||||
{
|
||||
cutWalkThroughGroupWindows = kaction->globalShortcut();
|
||||
connect( kaction, SIGNAL( globalShortcutChanged( QKeySequence ) ), this,
|
||||
SLOT( slotMoveToTabRightKeyChanged( QKeySequence ) ) );
|
||||
}
|
||||
|
||||
kaction = qobject_cast<KAction*>( keys->action("Walk Through Group Windows (Reverse)") );
|
||||
if( kaction != 0 )
|
||||
{
|
||||
cutWalkThroughGroupWindowsReverse = kaction->globalShortcut();
|
||||
connect( kaction, SIGNAL( globalShortcutChanged( QKeySequence ) ), this,
|
||||
SLOT( slotMoveToTabLeftKeyChanged( QKeySequence ) ) );
|
||||
}
|
||||
|
||||
kaction = qobject_cast<KAction*>( keys->action("Walk Through Windows Alternative") );
|
||||
if ( kaction!=0 )
|
||||
{
|
||||
|
@ -582,6 +749,31 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
|
|||
break;
|
||||
case Options::NoOp:
|
||||
break;
|
||||
case Options::RemoveClientFromGroupOp:
|
||||
c->clientGroup()->remove( c );
|
||||
break;
|
||||
case Options::MoveClientInGroupLeftOp:
|
||||
{
|
||||
int c_id = c->clientGroup()->indexOfClient( c );
|
||||
int size = c->clientGroup()->clients().count();
|
||||
if( c_id > 0 )
|
||||
c->clientGroup()->setVisible( c_id - 1 );
|
||||
else
|
||||
c->clientGroup()->setVisible( size - 1 );
|
||||
break;
|
||||
}
|
||||
case Options::MoveClientInGroupRightOp:
|
||||
{
|
||||
int c_id = c->clientGroup()->indexOfClient( c );
|
||||
int size = c->clientGroup()->clients().count();
|
||||
if( c_id < size - 1 )
|
||||
c->clientGroup()->setVisible( c_id + 1 );
|
||||
else
|
||||
c->clientGroup()->setVisible( 0 );
|
||||
break;
|
||||
}
|
||||
case Options::CloseClientGroupOp:
|
||||
c->clientGroup()->closeAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1154,6 +1346,36 @@ void Workspace::slotWindowToDesktopDown()
|
|||
}
|
||||
}
|
||||
|
||||
void Workspace::slotSwitchToTabRight()
|
||||
{
|
||||
if( !active_client )
|
||||
return;
|
||||
int c_id = active_client->clientGroup()->indexOfClient( active_client );
|
||||
int size = active_client->clientGroup()->clients().count();
|
||||
if( c_id < size - 1 )
|
||||
active_client->clientGroup()->setVisible( c_id + 1 );
|
||||
else
|
||||
active_client->clientGroup()->setVisible( 0 );
|
||||
}
|
||||
|
||||
void Workspace::slotSwitchToTabLeft()
|
||||
{
|
||||
if( !active_client )
|
||||
return;
|
||||
int c_id = active_client->clientGroup()->indexOfClient( active_client );
|
||||
int size = active_client->clientGroup()->clients().count();
|
||||
if( c_id > 0 )
|
||||
active_client->clientGroup()->setVisible( c_id - 1 );
|
||||
else
|
||||
active_client->clientGroup()->setVisible( size - 1 );
|
||||
}
|
||||
|
||||
void Workspace::slotRemoveFromGroup()
|
||||
{
|
||||
if( !active_client )
|
||||
return;
|
||||
active_client->clientGroup()->remove( active_client );
|
||||
}
|
||||
|
||||
/*!
|
||||
Kill Window feature, similar to xkill
|
||||
|
|
|
@ -122,6 +122,8 @@ Workspace::Workspace( bool restore )
|
|||
, advanced_popup( 0 )
|
||||
, trans_popup( 0 )
|
||||
, desk_popup( 0 )
|
||||
, add_tabs_popup( 0 )
|
||||
, switch_to_tab_popup( 0 )
|
||||
, keys( 0 )
|
||||
, client_keys( NULL )
|
||||
, client_keys_dialog( NULL )
|
||||
|
@ -1070,6 +1072,13 @@ void Workspace::slotReconfigure()
|
|||
it != clients.constEnd();
|
||||
++it )
|
||||
(*it)->updateDecoration( true, true );
|
||||
// If the new decoration doesn't supports tabs then ungroup clients
|
||||
if( !decorationSupportsClientGrouping() )
|
||||
{
|
||||
QList<ClientGroup*> tmpGroups = clientGroups; // Prevent crashing
|
||||
for( QList<ClientGroup*>::const_iterator i = tmpGroups.begin(); i != tmpGroups.end(); i++ )
|
||||
(*i)->removeAll();
|
||||
}
|
||||
mgr->destroyPreviousPlugin();
|
||||
}
|
||||
else
|
||||
|
@ -2855,6 +2864,19 @@ void Workspace::checkCursorPos()
|
|||
x11ToQtKeyboardModifiers( last_buttons ), x11ToQtKeyboardModifiers( lastb ));
|
||||
}
|
||||
|
||||
int Workspace::indexOfClientGroup( ClientGroup* group )
|
||||
{
|
||||
return clientGroups.indexOf( group );
|
||||
}
|
||||
|
||||
void Workspace::moveItemToClientGroup( ClientGroup* oldGroup, int oldIndex,
|
||||
ClientGroup* group, int index )
|
||||
{
|
||||
Client* c = oldGroup->clients().at( oldIndex );
|
||||
oldGroup->remove( c );
|
||||
group->add( c, index, true );
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "workspace.moc"
|
||||
|
|
44
workspace.h
44
workspace.h
|
@ -60,6 +60,7 @@ class TabBox;
|
|||
}
|
||||
|
||||
class Client;
|
||||
class ClientGroup;
|
||||
class DesktopChangeOSD;
|
||||
class RootInfo;
|
||||
class PluginMgr;
|
||||
|
@ -314,6 +315,15 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
void unrefTabBox();
|
||||
void closeTabBox();
|
||||
|
||||
// Tabbing
|
||||
void addClientGroup( ClientGroup* group );
|
||||
void removeClientGroup( ClientGroup* group );
|
||||
/// Returns the index of c in clientGroupList.
|
||||
int indexOfClientGroup( ClientGroup* group );
|
||||
/// Change the client c_id to the group with index g_id
|
||||
void moveItemToClientGroup( ClientGroup* oldGroup, int oldIndex, ClientGroup* group, int index = -1 );
|
||||
QList<ClientGroup*> clientGroups; // List of existing clients groups with no special order
|
||||
|
||||
/**
|
||||
* Returns the list of clients sorted in stacking order, with topmost client
|
||||
* at the last position
|
||||
|
@ -371,6 +381,7 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
|
||||
bool hasDecorationShadows() const;
|
||||
bool decorationHasAlpha() const;
|
||||
bool decorationSupportsClientGrouping() const; // Returns true if the decoration supports tabs.
|
||||
|
||||
// D-Bus interface
|
||||
void cascadeDesktop();
|
||||
|
@ -588,6 +599,8 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
void slotWalkBackThroughDesktopListKeyChanged( const QKeySequence& seq );
|
||||
void slotWalkThroughWindowsKeyChanged( const QKeySequence& seq );
|
||||
void slotWalkBackThroughWindowsKeyChanged( const QKeySequence& seq );
|
||||
void slotMoveToTabLeftKeyChanged( const QKeySequence& seq );
|
||||
void slotMoveToTabRightKeyChanged( const QKeySequence& seq );
|
||||
void slotWalkThroughWindowsAlternativeKeyChanged( const QKeySequence& seq );
|
||||
void slotWalkBackThroughWindowsAlternativeKeyChanged( const QKeySequence& seq );
|
||||
|
||||
|
@ -636,7 +649,15 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
void suspendCompositing();
|
||||
void suspendCompositing( bool suspend );
|
||||
|
||||
void slotSwitchToTabLeft(); // Slot to move left the active Client.
|
||||
void slotSwitchToTabRight(); // Slot to move right the active Client.
|
||||
void slotRemoveFromGroup(); // Slot to remove the active client from its group.
|
||||
|
||||
private slots:
|
||||
void groupTabPopupAboutToShow(); // Popup to add to another group
|
||||
void switchToTabPopupAboutToShow(); // Popup to move in the group
|
||||
void slotAddToTabGroup( QAction* ); // Add client to a group
|
||||
void slotSwitchToTab( QAction* ); // Change the tab
|
||||
void desktopPopupAboutToShow();
|
||||
void clientPopupAboutToShow();
|
||||
void slotSendToDesktop( QAction* );
|
||||
|
@ -820,6 +841,7 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
KShortcut cutWalkThroughDesktops, cutWalkThroughDesktopsReverse;
|
||||
KShortcut cutWalkThroughDesktopList, cutWalkThroughDesktopListReverse;
|
||||
KShortcut cutWalkThroughWindows, cutWalkThroughWindowsReverse;
|
||||
KShortcut cutWalkThroughGroupWindows, cutWalkThroughGroupWindowsReverse;
|
||||
KShortcut cutWalkThroughWindowsAlternative, cutWalkThroughWindowsAlternativeReverse;
|
||||
bool mouse_emulation;
|
||||
unsigned int mouse_emulation_state;
|
||||
|
@ -833,6 +855,8 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
QMenu* advanced_popup;
|
||||
QMenu* trans_popup;
|
||||
QMenu* desk_popup;
|
||||
QMenu* add_tabs_popup; // Menu to add the group to other group
|
||||
QMenu* switch_to_tab_popup; // Menu to change tab
|
||||
|
||||
void modalActionsSwitch( bool enabled );
|
||||
|
||||
|
@ -848,12 +872,17 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
QAction* mNoBorderOpAction;
|
||||
QAction* mMinimizeOpAction;
|
||||
QAction* mCloseOpAction;
|
||||
QAction* mRemoveTabGroup; // Remove client from group
|
||||
QAction* mCloseGroup; // Close all clients in the group
|
||||
ShortcutDialog* client_keys_dialog;
|
||||
Client* client_keys_client;
|
||||
KActionCollection* disable_shortcuts_keys;
|
||||
bool global_shortcuts_disabled;
|
||||
bool global_shortcuts_disabled_for_client;
|
||||
|
||||
void initAddToTabGroup(); // Load options for menu add_tabs_popup
|
||||
void initSwitchToTab(); // Load options for menu switch_to_tab_popup
|
||||
|
||||
PluginMgr* mgr;
|
||||
|
||||
RootInfo* rootInfo;
|
||||
|
@ -1222,6 +1251,21 @@ inline bool Workspace::decorationHasAlpha() const
|
|||
return mgr->factory()->supports( AbilityUsesAlphaChannel );
|
||||
}
|
||||
|
||||
inline bool Workspace::decorationSupportsClientGrouping() const
|
||||
{
|
||||
return mgr->factory()->supports( AbilityClientGrouping );
|
||||
}
|
||||
|
||||
inline void Workspace::addClientGroup( ClientGroup* group )
|
||||
{
|
||||
clientGroups.append( group );
|
||||
}
|
||||
|
||||
inline void Workspace::removeClientGroup( ClientGroup* group )
|
||||
{
|
||||
clientGroups.removeAll( group );
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue