f2e8fdf067
Thanks to Glen Kaukola for the patch. FEATURE: 227540 svn path=/trunk/KDE/kdebase/workspace/; revision=1105530
1725 lines
56 KiB
C++
1725 lines
56 KiB
C++
/********************************************************************
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
|
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
|
|
|
|
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/>.
|
|
*********************************************************************/
|
|
|
|
/*
|
|
|
|
This file contains things relevant to direct user actions, such as
|
|
responses to global keyboard shortcuts, or selecting actions
|
|
from the window operations menu.
|
|
|
|
*/
|
|
|
|
#include "client.h"
|
|
#include "workspace.h"
|
|
#include "effects.h"
|
|
|
|
#include <fixx11h.h>
|
|
#include <QPushButton>
|
|
#include <QSlider>
|
|
|
|
#include <kglobalsettings.h>
|
|
#include <kiconloader.h>
|
|
#include <klocale.h>
|
|
#include <kconfig.h>
|
|
#include <kglobalaccel.h>
|
|
#include <kapplication.h>
|
|
#include <QRegExp>
|
|
#include <QMenu>
|
|
#include <QVBoxLayout>
|
|
#include <kauthorized.h>
|
|
#include <kactioncollection.h>
|
|
#include <kaction.h>
|
|
|
|
#include "killwindow.h"
|
|
#include "tabbox.h"
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
//****************************************
|
|
// Workspace
|
|
//****************************************
|
|
|
|
QMenu* Workspace::clientPopup()
|
|
{
|
|
if ( !popup )
|
|
{
|
|
popup = new QMenu;
|
|
popup->setFont(KGlobalSettings::menuFont());
|
|
connect( popup, SIGNAL( aboutToShow() ), this, SLOT( clientPopupAboutToShow() ) );
|
|
connect( popup, SIGNAL( triggered(QAction*) ), this, SLOT( clientPopupActivated(QAction*) ) );
|
|
|
|
advanced_popup = new QMenu( popup );
|
|
advanced_popup->setFont(KGlobalSettings::menuFont());
|
|
|
|
mKeepAboveOpAction = advanced_popup->addAction( i18n("Keep &Above Others") );
|
|
mKeepAboveOpAction->setIcon( KIcon( "go-up" ) );
|
|
KAction *kaction = qobject_cast<KAction*>( keys->action("Window Above Other Windows") );
|
|
if ( kaction!=0 )
|
|
mKeepAboveOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
mKeepAboveOpAction->setCheckable( true );
|
|
mKeepAboveOpAction->setData( Options::KeepAboveOp );
|
|
|
|
mKeepBelowOpAction = advanced_popup->addAction( i18n("Keep &Below Others") );
|
|
mKeepBelowOpAction->setIcon( KIcon( "go-down" ) );
|
|
kaction = qobject_cast<KAction*>( keys->action("Window Below Other Windows") );
|
|
if ( kaction!=0 )
|
|
mKeepBelowOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
mKeepBelowOpAction->setCheckable( true );
|
|
mKeepBelowOpAction->setData( Options::KeepBelowOp );
|
|
|
|
mFullScreenOpAction = advanced_popup->addAction( i18n("&Fullscreen") );
|
|
mFullScreenOpAction->setIcon( KIcon( "view-fullscreen" ) );
|
|
kaction = qobject_cast<KAction*>( keys->action("Window Fullscreen") );
|
|
if ( kaction!=0 )
|
|
mFullScreenOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
mFullScreenOpAction->setCheckable( true );
|
|
mFullScreenOpAction->setData( Options::FullScreenOp );
|
|
|
|
mNoBorderOpAction = advanced_popup->addAction( i18n("&No Border") );
|
|
kaction = qobject_cast<KAction*>( keys->action("Window No Border") );
|
|
if ( kaction!=0 )
|
|
mNoBorderOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
mNoBorderOpAction->setCheckable( true );
|
|
mNoBorderOpAction->setData( Options::NoBorderOp );
|
|
|
|
QAction *action = advanced_popup->addAction( i18n("Window &Shortcut...") );
|
|
action->setIcon( KIcon("configure-shortcuts") );
|
|
kaction = qobject_cast<KAction*>( keys->action("Setup Window Shortcut") );
|
|
if ( kaction!=0 )
|
|
action->setShortcut( kaction->globalShortcut().primary() );
|
|
action->setData( Options::SetupWindowShortcutOp );
|
|
|
|
action = advanced_popup->addAction( i18n("&Special Window Settings...") );
|
|
action->setIcon( KIcon( "preferences-system-windows-actions" ) );
|
|
action->setData( Options::WindowRulesOp );
|
|
|
|
action = advanced_popup->addAction( i18n("&Special Application Settings...") );
|
|
action->setIcon( KIcon( "preferences-system-windows-actions" ) );
|
|
action->setData( Options::ApplicationRulesOp );
|
|
|
|
trans_popup = 0;
|
|
if (compositing()){
|
|
trans_popup = new QMenu( popup );
|
|
trans_popup->setFont(KGlobalSettings::menuFont());
|
|
connect( trans_popup, SIGNAL( triggered(QAction*) ), this, SLOT( setPopupClientOpacity(QAction*)));
|
|
trans_popup_group = new QActionGroup(trans_popup);
|
|
const int levels[] = { 100, 90, 75, 50, 25, 10 };
|
|
for( unsigned int i = 0;
|
|
i < sizeof( levels ) / sizeof( levels[ 0 ] );
|
|
++i )
|
|
{
|
|
action = trans_popup->addAction( QString::number( levels[ i ] ) + "%" );
|
|
action->setActionGroup( trans_popup_group );
|
|
action->setCheckable( true );
|
|
action->setData( levels[ i ] );
|
|
}
|
|
action = popup->addMenu( trans_popup );
|
|
action->setText( i18n("&Opacity") );
|
|
}
|
|
|
|
mMoveOpAction = popup->addAction( i18n("&Move") );
|
|
mMoveOpAction->setIcon( KIcon( "transform-move" ) );
|
|
kaction = qobject_cast<KAction*>( keys->action("Window Move") );
|
|
if ( kaction!=0 )
|
|
mMoveOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
mMoveOpAction->setData( Options::MoveOp );
|
|
|
|
mResizeOpAction = popup->addAction( i18n("Re&size") );
|
|
kaction = qobject_cast<KAction*>( keys->action("Window Resize") );
|
|
if ( kaction!=0 )
|
|
mResizeOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
mResizeOpAction->setData( Options::ResizeOp );
|
|
|
|
mMinimizeOpAction = popup->addAction( i18n("Mi&nimize") );
|
|
kaction = qobject_cast<KAction*>( keys->action("Window Minimize") );
|
|
if ( kaction!=0 )
|
|
mMinimizeOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
mMinimizeOpAction->setData( Options::MinimizeOp );
|
|
|
|
mMaximizeOpAction = popup->addAction( i18n("Ma&ximize") );
|
|
kaction = qobject_cast<KAction*>( keys->action("Window Maximize") );
|
|
if ( kaction!=0 )
|
|
mMaximizeOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
mMaximizeOpAction->setCheckable( true );
|
|
mMaximizeOpAction->setData( Options::MaximizeOp );
|
|
|
|
mShadeOpAction = popup->addAction( i18n("Sh&ade") );
|
|
kaction = qobject_cast<KAction*>( keys->action("Window Shade") );
|
|
if ( kaction!=0 )
|
|
mShadeOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
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") );
|
|
|
|
popup->addSeparator();
|
|
|
|
if (!KGlobal::config()->isImmutable() &&
|
|
!KAuthorized::authorizeControlModules(Workspace::configModules(true)).isEmpty())
|
|
{
|
|
action = popup->addAction( i18n("Configur&e Window Behavior...") );
|
|
action->setIcon( KIcon( "configure" ) );
|
|
connect( action, SIGNAL( triggered() ), this, SLOT( configureWM() ) );
|
|
popup->addSeparator();
|
|
}
|
|
|
|
mCloseOpAction = popup->addAction( i18n("&Close") );
|
|
mCloseOpAction->setIcon( KIcon( "window-close" ) );
|
|
kaction = qobject_cast<KAction*>( keys->action("Window Close") );
|
|
if ( kaction!=0 )
|
|
mCloseOpAction->setShortcut( kaction->globalShortcut().primary() );
|
|
mCloseOpAction->setData( Options::CloseOp );
|
|
}
|
|
return popup;
|
|
}
|
|
|
|
void Workspace::discardPopup()
|
|
{
|
|
delete popup;
|
|
popup = NULL;
|
|
desk_popup = NULL;
|
|
switch_to_tab_popup = NULL;
|
|
add_tabs_popup = NULL;
|
|
}
|
|
|
|
void Workspace::setPopupClientOpacity( QAction* action )
|
|
{
|
|
if( active_popup_client == NULL )
|
|
return;
|
|
int level = action->data().toInt();
|
|
active_popup_client->setOpacity( level / 100.0 );
|
|
}
|
|
|
|
/*!
|
|
The client popup menu will become visible soon.
|
|
|
|
Adjust the items according to the respective popup client.
|
|
*/
|
|
void Workspace::clientPopupAboutToShow()
|
|
{
|
|
if ( !active_popup_client || !popup )
|
|
return;
|
|
|
|
if ( numberOfDesktops() == 1 )
|
|
{
|
|
delete desk_popup;
|
|
desk_popup = 0;
|
|
}
|
|
else
|
|
{
|
|
initDesktopPopup();
|
|
}
|
|
|
|
mResizeOpAction->setEnabled( active_popup_client->isResizable() );
|
|
mMoveOpAction->setEnabled( active_popup_client->isMovableAcrossScreens() );
|
|
mMaximizeOpAction->setEnabled( active_popup_client->isMaximizable() );
|
|
mMaximizeOpAction->setChecked( active_popup_client->maximizeMode() == Client::MaximizeFull );
|
|
mShadeOpAction->setEnabled( active_popup_client->isShadeable() );
|
|
mShadeOpAction->setChecked( active_popup_client->shadeMode() != ShadeNone );
|
|
mKeepAboveOpAction->setChecked( active_popup_client->keepAbove() );
|
|
mKeepBelowOpAction->setChecked( active_popup_client->keepBelow() );
|
|
mFullScreenOpAction->setEnabled( active_popup_client->userCanSetFullScreen() );
|
|
mFullScreenOpAction->setChecked( active_popup_client->isFullScreen() );
|
|
mNoBorderOpAction->setEnabled( active_popup_client->userCanSetNoBorder() );
|
|
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() ?
|
|
active_popup_client->clientGroup()->items().count() : 1;
|
|
if( tabGroupSize > 1 )
|
|
initSwitchToTab();
|
|
initAddToTabGroup();
|
|
|
|
mRemoveTabGroup->setVisible( tabGroupSize > 1 );
|
|
mCloseGroup->setVisible( tabGroupSize > 1 );
|
|
}
|
|
|
|
if( trans_popup != NULL )
|
|
{
|
|
foreach( QAction* action, trans_popup->actions())
|
|
{
|
|
if( action->data().toInt() == qRound( active_popup_client->opacity() * 100 ))
|
|
action->setChecked( true );
|
|
else
|
|
action->setChecked( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
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 window tab") );
|
|
}
|
|
|
|
void Workspace::slotSwitchToTab( QAction* action )
|
|
{
|
|
int side = action->data().toInt();
|
|
int c_id = active_popup_client->clientGroup()->indexOfVisibleClient();
|
|
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.constBegin(); i != clientGroups.constEnd(); ++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->clientGroup()->visible() )
|
|
{
|
|
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.constBegin(); i != clientGroups.constEnd(); i++, index++ )
|
|
{
|
|
if( !(*i)->contains( active_popup_client ))
|
|
{
|
|
QAction* action = add_tabs_popup->addAction( (*i)->visible()->caption() );
|
|
action->setData( index );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Workspace::initDesktopPopup()
|
|
{
|
|
if (desk_popup)
|
|
return;
|
|
|
|
desk_popup = new QMenu( popup );
|
|
desk_popup->setFont(KGlobalSettings::menuFont());
|
|
connect( desk_popup, SIGNAL( triggered(QAction*) ),
|
|
this, SLOT( slotSendToDesktop(QAction*) ) );
|
|
connect( desk_popup, SIGNAL( aboutToShow() ),
|
|
this, SLOT( desktopPopupAboutToShow() ) );
|
|
|
|
QAction *action = desk_popup->menuAction();
|
|
// set it as the first item
|
|
popup->insertAction( trans_popup ? trans_popup->menuAction() : mMoveOpAction, action);
|
|
action->setText( i18n("To &Desktop") );
|
|
}
|
|
|
|
/*!
|
|
Adjusts the desktop popup to the current values and the location of
|
|
the popup client.
|
|
*/
|
|
void Workspace::desktopPopupAboutToShow()
|
|
{
|
|
if ( !desk_popup )
|
|
return;
|
|
|
|
desk_popup->clear();
|
|
QAction *action = desk_popup->addAction( i18n("&All Desktops") );
|
|
action->setData( 0 );
|
|
action->setCheckable( true );
|
|
|
|
if ( active_popup_client && active_popup_client->isOnAllDesktops() )
|
|
action->setChecked( true );
|
|
desk_popup->addSeparator();
|
|
|
|
const int BASE = 10;
|
|
for ( int i = 1; i <= numberOfDesktops(); i++ ) {
|
|
QString basic_name("%1 %2");
|
|
if (i<BASE) {
|
|
basic_name.prepend('&');
|
|
}
|
|
action = desk_popup->addAction( basic_name.arg(i).arg( desktopName(i).replace( '&', "&&" ) ) );
|
|
action->setData( i );
|
|
action->setCheckable( true );
|
|
|
|
if ( active_popup_client &&
|
|
!active_popup_client->isOnAllDesktops() && active_popup_client->desktop() == i )
|
|
action->setChecked( true );
|
|
}
|
|
}
|
|
|
|
void Workspace::closeActivePopup()
|
|
{
|
|
if( active_popup )
|
|
{
|
|
active_popup->close();
|
|
active_popup = NULL;
|
|
active_popup_client = NULL;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Create the global accel object \c keys.
|
|
*/
|
|
void Workspace::initShortcuts()
|
|
{
|
|
keys = new KActionCollection( this );
|
|
KActionCollection* actionCollection = keys;
|
|
QAction* a = 0L;
|
|
|
|
// a separate KActionCollection is needed for the shortcut for disabling global shortcuts,
|
|
// otherwise it would also disable itself
|
|
disable_shortcuts_keys = new KActionCollection( this );
|
|
// TODO: PORT ME (KGlobalAccel related)
|
|
// FIXME KAccel port... needed?
|
|
//disable_shortcuts_keys->disableBlocking( true );
|
|
#define IN_KWIN
|
|
#include "kwinbindings.cpp"
|
|
readShortcuts();
|
|
}
|
|
|
|
void Workspace::readShortcuts()
|
|
{
|
|
// TODO: PORT ME (KGlobalAccel related)
|
|
//KGlobalAccel::self()->readSettings();
|
|
|
|
KAction *kaction = qobject_cast<KAction*>( keys->action("Walk Through Desktops") );
|
|
if ( kaction!=0 )
|
|
{
|
|
cutWalkThroughDesktops = kaction->globalShortcut();
|
|
connect( kaction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(slotWalkThroughDesktopsKeyChanged(QKeySequence)));
|
|
}
|
|
|
|
kaction = qobject_cast<KAction*>( keys->action("Walk Through Desktops (Reverse)") );
|
|
if ( kaction!=0 )
|
|
{
|
|
cutWalkThroughDesktopsReverse = kaction->globalShortcut();
|
|
connect( kaction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(slotWalkBackThroughDesktopsKeyChanged(QKeySequence)));
|
|
}
|
|
|
|
kaction = qobject_cast<KAction*>( keys->action("Walk Through Desktop List") );
|
|
if ( kaction!=0 )
|
|
{
|
|
cutWalkThroughDesktopList = kaction->globalShortcut();
|
|
connect( kaction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(slotWalkThroughDesktopListKeyChanged(QKeySequence)));
|
|
}
|
|
|
|
kaction = qobject_cast<KAction*>( keys->action("Walk Through Desktop List (Reverse)") );
|
|
if ( kaction!=0 )
|
|
{
|
|
cutWalkThroughDesktopListReverse = kaction->globalShortcut();
|
|
connect( kaction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(slotWalkBackThroughDesktopListKeyChanged(QKeySequence)));
|
|
}
|
|
|
|
kaction = qobject_cast<KAction*>( keys->action("Walk Through Windows") );
|
|
if ( kaction!=0 )
|
|
{
|
|
cutWalkThroughWindows = kaction->globalShortcut();
|
|
connect( kaction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(slotWalkThroughWindowsKeyChanged(QKeySequence)));
|
|
}
|
|
|
|
kaction = qobject_cast<KAction*>( keys->action("Walk Through Windows (Reverse)") );
|
|
if ( kaction!=0 )
|
|
{
|
|
cutWalkThroughWindowsReverse = kaction->globalShortcut();
|
|
connect( kaction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(slotWalkBackThroughWindowsKeyChanged(QKeySequence)));
|
|
}
|
|
|
|
kaction = qobject_cast<KAction*>( keys->action("Walk Through Window Tabs") );
|
|
if( kaction != 0 )
|
|
{
|
|
cutWalkThroughGroupWindows = kaction->globalShortcut();
|
|
connect( kaction, SIGNAL( globalShortcutChanged( QKeySequence ) ), this,
|
|
SLOT( slotMoveToTabRightKeyChanged( QKeySequence ) ) );
|
|
}
|
|
|
|
kaction = qobject_cast<KAction*>( keys->action("Walk Through Window Tabs (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 )
|
|
{
|
|
cutWalkThroughWindowsAlternative = kaction->globalShortcut();
|
|
connect( kaction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(slotWalkThroughWindowsAlternativeKeyChanged(QKeySequence)));
|
|
}
|
|
|
|
kaction = qobject_cast<KAction*>( keys->action("Walk Through Windows Alternative (Reverse)") );
|
|
if ( kaction!=0 )
|
|
{
|
|
cutWalkThroughWindowsAlternativeReverse = kaction->globalShortcut();
|
|
connect( kaction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(slotWalkBackThroughWindowsAlternativeKeyChanged(QKeySequence)));
|
|
}
|
|
discardPopup(); // so that it's recreated next time
|
|
}
|
|
|
|
|
|
void Workspace::setupWindowShortcut( Client* c )
|
|
{
|
|
assert( client_keys_dialog == NULL );
|
|
// TODO: PORT ME (KGlobalAccel related)
|
|
//keys->setEnabled( false );
|
|
//disable_shortcuts_keys->setEnabled( false );
|
|
//client_keys->setEnabled( false );
|
|
client_keys_dialog = new ShortcutDialog( c->shortcut().primary());
|
|
client_keys_client = c;
|
|
connect( client_keys_dialog, SIGNAL( dialogDone( bool )), SLOT( setupWindowShortcutDone( bool )));
|
|
QRect r = clientArea( ScreenArea, c );
|
|
QSize size = client_keys_dialog->sizeHint();
|
|
QPoint pos = c->pos() + c->clientPos();
|
|
if( pos.x() + size.width() >= r.right())
|
|
pos.setX( r.right() - size.width());
|
|
if( pos.y() + size.height() >= r.bottom())
|
|
pos.setY( r.bottom() - size.height());
|
|
client_keys_dialog->move( pos );
|
|
client_keys_dialog->show();
|
|
active_popup = client_keys_dialog;
|
|
active_popup_client = c;
|
|
}
|
|
|
|
void Workspace::setupWindowShortcutDone( bool ok )
|
|
{
|
|
// keys->setEnabled( true );
|
|
// disable_shortcuts_keys->setEnabled( true );
|
|
// client_keys->setEnabled( true );
|
|
if( ok )
|
|
client_keys_client->setShortcut( KShortcut( client_keys_dialog->shortcut()).toString());
|
|
closeActivePopup();
|
|
client_keys_dialog->deleteLater();
|
|
client_keys_dialog = NULL;
|
|
client_keys_client = NULL;
|
|
}
|
|
|
|
void Workspace::clientShortcutUpdated( Client* c )
|
|
{
|
|
QString key = QString( "_k_session:%1" ).arg(c->window());
|
|
QAction* action = client_keys->action( key.toLatin1().constData() );
|
|
if( !c->shortcut().isEmpty())
|
|
{
|
|
if( action == NULL ) // new shortcut
|
|
{
|
|
action = client_keys->addAction(QString( key ));
|
|
action->setText( i18n("Activate Window (%1)", c->caption()) );
|
|
connect( action, SIGNAL(triggered(bool)), c, SLOT(shortcutActivated()) );
|
|
}
|
|
|
|
KAction *kaction = qobject_cast<KAction*>( action );
|
|
// no autoloading, since it's configured explicitly here and is not meant to be reused
|
|
// (the key is the window id anyway, which is kind of random)
|
|
kaction->setGlobalShortcut(
|
|
c->shortcut(), KAction::ActiveShortcut, KAction::NoAutoloading );
|
|
kaction->setEnabled( true );
|
|
}
|
|
else
|
|
{
|
|
KAction *kaction = qobject_cast<KAction*>( action );
|
|
if( kaction )
|
|
{
|
|
kaction->forgetGlobalShortcut();
|
|
}
|
|
delete action;
|
|
}
|
|
}
|
|
|
|
void Workspace::clientPopupActivated( QAction *action )
|
|
{
|
|
if ( !action->data().isValid() )
|
|
return;
|
|
|
|
WindowOperation op = static_cast< WindowOperation >( action->data().toInt() );
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
QString type;
|
|
switch( op )
|
|
{
|
|
case FullScreenOp:
|
|
if( !c->isFullScreen() && c->userCanSetFullScreen())
|
|
type = "fullscreenaltf3";
|
|
break;
|
|
case NoBorderOp:
|
|
if( !c->noBorder() && c->userCanSetNoBorder())
|
|
type = "noborderaltf3";
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
if( !type.isEmpty())
|
|
helperDialog( type, c );
|
|
performWindowOperation( c, op );
|
|
}
|
|
|
|
|
|
void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
|
|
{
|
|
if ( !c )
|
|
return;
|
|
|
|
if (op == Options::MoveOp || op == Options::UnrestrictedMoveOp )
|
|
QCursor::setPos( c->geometry().center() );
|
|
if (op == Options::ResizeOp || op == Options::UnrestrictedResizeOp )
|
|
QCursor::setPos( c->geometry().bottomRight());
|
|
switch ( op )
|
|
{
|
|
case Options::MoveOp:
|
|
c->performMouseCommand( Options::MouseMove, cursorPos() );
|
|
break;
|
|
case Options::UnrestrictedMoveOp:
|
|
c->performMouseCommand( Options::MouseUnrestrictedMove, cursorPos() );
|
|
break;
|
|
case Options::ResizeOp:
|
|
c->performMouseCommand( Options::MouseResize, cursorPos() );
|
|
break;
|
|
case Options::UnrestrictedResizeOp:
|
|
c->performMouseCommand( Options::MouseUnrestrictedResize, cursorPos() );
|
|
break;
|
|
case Options::CloseOp:
|
|
c->closeWindow();
|
|
break;
|
|
case Options::MaximizeOp:
|
|
c->maximize( c->maximizeMode() == Client::MaximizeFull
|
|
? Client::MaximizeRestore : Client::MaximizeFull );
|
|
break;
|
|
case Options::HMaximizeOp:
|
|
c->maximize( c->maximizeMode() ^ Client::MaximizeHorizontal );
|
|
break;
|
|
case Options::VMaximizeOp:
|
|
c->maximize( c->maximizeMode() ^ Client::MaximizeVertical );
|
|
break;
|
|
case Options::RestoreOp:
|
|
c->maximize( Client::MaximizeRestore );
|
|
break;
|
|
case Options::MinimizeOp:
|
|
c->minimize();
|
|
break;
|
|
case Options::ShadeOp:
|
|
c->performMouseCommand( Options::MouseShade, cursorPos());
|
|
break;
|
|
case Options::OnAllDesktopsOp:
|
|
c->setOnAllDesktops( !c->isOnAllDesktops() );
|
|
break;
|
|
case Options::FullScreenOp:
|
|
c->setFullScreen( !c->isFullScreen(), true );
|
|
break;
|
|
case Options::NoBorderOp:
|
|
c->setNoBorder( !c->noBorder());
|
|
break;
|
|
case Options::KeepAboveOp:
|
|
{
|
|
StackingUpdatesBlocker blocker( this );
|
|
bool was = c->keepAbove();
|
|
c->setKeepAbove( !c->keepAbove() );
|
|
if( was && !c->keepAbove())
|
|
raiseClient( c );
|
|
break;
|
|
}
|
|
case Options::KeepBelowOp:
|
|
{
|
|
StackingUpdatesBlocker blocker( this );
|
|
bool was = c->keepBelow();
|
|
c->setKeepBelow( !c->keepBelow() );
|
|
if( was && !c->keepBelow())
|
|
lowerClient( c );
|
|
break;
|
|
}
|
|
case Options::OperationsOp:
|
|
c->performMouseCommand( Options::MouseShade, cursorPos());
|
|
break;
|
|
case Options::WindowRulesOp:
|
|
editWindowRules( c, false );
|
|
break;
|
|
case Options::ApplicationRulesOp:
|
|
editWindowRules( c, true );
|
|
break;
|
|
case Options::SetupWindowShortcutOp:
|
|
setupWindowShortcut( c );
|
|
break;
|
|
case Options::LowerOp:
|
|
lowerClient(c);
|
|
break;
|
|
case Options::ClientGroupDragOp: // Handled by decoration itself
|
|
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();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called by the decoration in the new API to determine what buttons the user has configured for
|
|
* window tab dragging and the operations menu.
|
|
*/
|
|
Options::WindowOperation Client::mouseButtonToWindowOperation( Qt::MouseButtons button )
|
|
{
|
|
Options::MouseCommand com = Options::MouseNothing;
|
|
bool active = isActive();
|
|
if( !wantsInput() ) // we cannot be active, use it anyway
|
|
active = true;
|
|
|
|
if( button == Qt::LeftButton )
|
|
com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
|
|
else if( button == Qt::MidButton )
|
|
com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
|
|
else if( button == Qt::RightButton )
|
|
com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
|
|
|
|
// TODO: Complete the list
|
|
if( com == Options::MouseClientGroupDrag )
|
|
return Options::ClientGroupDragOp;
|
|
if( com == Options::MouseOperationsMenu )
|
|
return Options::OperationsOp;
|
|
return Options::NoOp;
|
|
}
|
|
|
|
/*!
|
|
Performs a mouse command on this client (see options.h)
|
|
*/
|
|
bool Client::performMouseCommand( Options::MouseCommand command, const QPoint &globalPos, bool handled )
|
|
{
|
|
bool replay = false;
|
|
switch (command)
|
|
{
|
|
case Options::MouseRaise:
|
|
workspace()->raiseClient( this );
|
|
break;
|
|
case Options::MouseLower:
|
|
workspace()->lowerClient( this );
|
|
// As this most likely makes the window no longer visible change the
|
|
// keyboard focus to the next available window.
|
|
//workspace()->activateNextClient( this ); // Doesn't work when we lower a child window
|
|
workspace()->activateClient( workspace()->topClientOnDesktop( workspace()->currentDesktop(), -1 ));
|
|
break;
|
|
case Options::MouseShade :
|
|
toggleShade();
|
|
cancelShadeHoverTimer();
|
|
break;
|
|
case Options::MouseSetShade:
|
|
setShade( ShadeNormal );
|
|
cancelShadeHoverTimer();
|
|
break;
|
|
case Options::MouseUnsetShade:
|
|
setShade( ShadeNone );
|
|
cancelShadeHoverTimer();
|
|
break;
|
|
case Options::MouseOperationsMenu:
|
|
if ( isActive() && options->clickRaise )
|
|
autoRaise();
|
|
workspace()->showWindowMenu( globalPos, this );
|
|
break;
|
|
case Options::MouseToggleRaiseAndLower:
|
|
workspace()->raiseOrLowerClient( this );
|
|
break;
|
|
case Options::MouseActivateAndRaise:
|
|
replay = isActive(); // for clickraise mode
|
|
workspace()->takeActivity( this, ActivityFocus | ActivityRaise, handled && replay );
|
|
workspace()->setActiveScreenMouse( globalPos );
|
|
break;
|
|
case Options::MouseActivateAndLower:
|
|
workspace()->requestFocus( this );
|
|
workspace()->lowerClient( this );
|
|
workspace()->setActiveScreenMouse( globalPos );
|
|
break;
|
|
case Options::MouseActivate:
|
|
replay = isActive(); // for clickraise mode
|
|
workspace()->takeActivity( this, ActivityFocus, handled && replay );
|
|
workspace()->setActiveScreenMouse( globalPos );
|
|
break;
|
|
case Options::MouseActivateRaiseAndPassClick:
|
|
workspace()->takeActivity( this, ActivityFocus | ActivityRaise, handled );
|
|
workspace()->setActiveScreenMouse( globalPos );
|
|
replay = true;
|
|
break;
|
|
case Options::MouseActivateAndPassClick:
|
|
workspace()->takeActivity( this, ActivityFocus, handled );
|
|
workspace()->setActiveScreenMouse( globalPos );
|
|
replay = true;
|
|
break;
|
|
case Options::MouseActivateRaiseAndMove:
|
|
case Options::MouseActivateRaiseAndUnrestrictedMove:
|
|
workspace()->raiseClient( this );
|
|
workspace()->requestFocus( this );
|
|
workspace()->setActiveScreenMouse( globalPos );
|
|
if( options->moveMode == Options::Transparent && isMovableAcrossScreens())
|
|
move_faked_activity = workspace()->fakeRequestedActivity( this );
|
|
// fallthrough
|
|
case Options::MouseMove:
|
|
case Options::MouseUnrestrictedMove:
|
|
{
|
|
if (!isMovableAcrossScreens())
|
|
break;
|
|
if( moveResizeMode )
|
|
finishMoveResize( false );
|
|
mode = PositionCenter;
|
|
buttonDown = true;
|
|
moveOffset = QPoint( globalPos.x() - x(), globalPos.y() - y()); // map from global
|
|
invertedMoveOffset = rect().bottomRight() - moveOffset;
|
|
unrestrictedMoveResize = ( command == Options::MouseActivateRaiseAndUnrestrictedMove
|
|
|| command == Options::MouseUnrestrictedMove );
|
|
if( !startMoveResize())
|
|
buttonDown = false;
|
|
updateCursor();
|
|
break;
|
|
}
|
|
case Options::MouseResize:
|
|
case Options::MouseUnrestrictedResize:
|
|
{
|
|
if (!isResizable() || isShade())
|
|
break;
|
|
if( moveResizeMode )
|
|
finishMoveResize( false );
|
|
buttonDown = true;
|
|
moveOffset = QPoint( globalPos.x() - x(), globalPos.y() - y()); // map from global
|
|
int x = moveOffset.x(), y = moveOffset.y();
|
|
bool left = x < width() / 3;
|
|
bool right = x >= 2 * width() / 3;
|
|
bool top = y < height() / 3;
|
|
bool bot = y >= 2 * height() / 3;
|
|
if (top)
|
|
mode = left ? PositionTopLeft : (right ? PositionTopRight : PositionTop);
|
|
else if (bot)
|
|
mode = left ? PositionBottomLeft : (right ? PositionBottomRight : PositionBottom);
|
|
else
|
|
mode = (x < width() / 2) ? PositionLeft : PositionRight;
|
|
invertedMoveOffset = rect().bottomRight() - moveOffset;
|
|
unrestrictedMoveResize = ( command == Options::MouseUnrestrictedResize );
|
|
if( !startMoveResize())
|
|
buttonDown = false;
|
|
updateCursor();
|
|
break;
|
|
}
|
|
case Options::MouseMaximize:
|
|
maximize( Client::MaximizeFull );
|
|
break;
|
|
case Options::MouseRestore:
|
|
maximize( Client::MaximizeRestore );
|
|
break;
|
|
case Options::MouseMinimize:
|
|
minimize();
|
|
break;
|
|
case Options::MouseAbove:
|
|
{
|
|
StackingUpdatesBlocker blocker( workspace());
|
|
if( keepBelow())
|
|
setKeepBelow( false );
|
|
else
|
|
setKeepAbove( true );
|
|
break;
|
|
}
|
|
case Options::MouseBelow:
|
|
{
|
|
StackingUpdatesBlocker blocker( workspace());
|
|
if( keepAbove())
|
|
setKeepAbove( false );
|
|
else
|
|
setKeepBelow( true );
|
|
break;
|
|
}
|
|
case Options::MousePreviousDesktop:
|
|
workspace()->windowToPreviousDesktop( this );
|
|
break;
|
|
case Options::MouseNextDesktop:
|
|
workspace()->windowToNextDesktop( this );
|
|
break;
|
|
case Options::MouseOpacityMore:
|
|
if( !isDesktop() ) // No point in changing the opacity of the desktop
|
|
setOpacity( qMin( opacity() + 0.1, 1.0 ));
|
|
break;
|
|
case Options::MouseOpacityLess:
|
|
if( !isDesktop() ) // No point in changing the opacity of the desktop
|
|
setOpacity( qMax( opacity() - 0.1, 0.1 ));
|
|
break;
|
|
case Options::MouseLeftGroupWindow:
|
|
{
|
|
int c_id = clientGroup()->indexOfClient( this );
|
|
int size = clientGroup()->clients().count();
|
|
if( c_id > 0 )
|
|
clientGroup()->setVisible( c_id - 1 );
|
|
else
|
|
clientGroup()->setVisible( size - 1 );
|
|
}
|
|
break;
|
|
case Options::MouseRightGroupWindow:
|
|
{
|
|
int c_id = clientGroup()->indexOfClient( this );
|
|
int size = clientGroup()->clients().count();
|
|
if( c_id < size - 1 )
|
|
clientGroup()->setVisible( c_id + 1 );
|
|
else
|
|
clientGroup()->setVisible( 0 );
|
|
}
|
|
break;
|
|
case Options::MouseClose:
|
|
closeWindow();
|
|
break;
|
|
case Options::MouseClientGroupDrag:
|
|
case Options::MouseNothing:
|
|
replay = true;
|
|
break;
|
|
}
|
|
return replay;
|
|
}
|
|
|
|
// KDE4 remove me
|
|
void Workspace::showWindowMenuAt( unsigned long, int, int )
|
|
{
|
|
slotWindowOperations();
|
|
}
|
|
|
|
void Workspace::loadEffect( const QString& name )
|
|
{
|
|
if( effects )
|
|
static_cast<EffectsHandlerImpl*>(effects)->loadEffect( name );
|
|
}
|
|
|
|
void Workspace::toggleEffect( const QString& name )
|
|
{
|
|
if( effects )
|
|
static_cast<EffectsHandlerImpl*>(effects)->toggleEffect( name );
|
|
}
|
|
|
|
void Workspace::unloadEffect( const QString& name )
|
|
{
|
|
if( effects )
|
|
static_cast<EffectsHandlerImpl*>(effects)->unloadEffect( name );
|
|
}
|
|
|
|
void Workspace::reconfigureEffect( const QString& name )
|
|
{
|
|
if( effects )
|
|
static_cast<EffectsHandlerImpl*>(effects)->reconfigureEffect( name );
|
|
}
|
|
|
|
QStringList Workspace::loadedEffects() const
|
|
{
|
|
QStringList listModulesLoaded;
|
|
if ( effects )
|
|
listModulesLoaded = static_cast<EffectsHandlerImpl*>(effects)->loadedEffects();
|
|
return listModulesLoaded;
|
|
}
|
|
|
|
QStringList Workspace::listOfEffects() const
|
|
{
|
|
QStringList listModules;
|
|
if ( effects )
|
|
listModules = static_cast<EffectsHandlerImpl*>(effects)->listOfEffects();
|
|
return listModules;
|
|
}
|
|
|
|
void Workspace::slotActivateAttentionWindow()
|
|
{
|
|
if( attention_chain.count() > 0 )
|
|
activateClient( attention_chain.first());
|
|
}
|
|
|
|
void Workspace::slotSwitchDesktopNext()
|
|
{
|
|
int d = currentDesktop() + 1;
|
|
if ( d > numberOfDesktops() )
|
|
{
|
|
if ( options->rollOverDesktops )
|
|
{
|
|
d = 1;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
setCurrentDesktop(d);
|
|
}
|
|
|
|
void Workspace::slotSwitchDesktopPrevious()
|
|
{
|
|
int d = currentDesktop() - 1;
|
|
if ( d <= 0 )
|
|
{
|
|
if ( options->rollOverDesktops )
|
|
d = numberOfDesktops();
|
|
else
|
|
return;
|
|
}
|
|
setCurrentDesktop(d);
|
|
}
|
|
|
|
void Workspace::slotSwitchDesktopRight()
|
|
{
|
|
int desktop = desktopToRight( currentDesktop(), options->rollOverDesktops);
|
|
if( desktop == currentDesktop())
|
|
return;
|
|
setCurrentDesktop( desktop );
|
|
}
|
|
|
|
void Workspace::slotSwitchDesktopLeft()
|
|
{
|
|
int desktop = desktopToLeft( currentDesktop(), options->rollOverDesktops);
|
|
if( desktop == currentDesktop())
|
|
return;
|
|
setCurrentDesktop( desktop );
|
|
}
|
|
|
|
void Workspace::slotSwitchDesktopUp()
|
|
{
|
|
int desktop = desktopAbove( currentDesktop(), options->rollOverDesktops);
|
|
if( desktop == currentDesktop())
|
|
return;
|
|
setCurrentDesktop( desktop );
|
|
}
|
|
|
|
void Workspace::slotSwitchDesktopDown()
|
|
{
|
|
int desktop = desktopBelow( currentDesktop(), options->rollOverDesktops);
|
|
if( desktop == currentDesktop())
|
|
return;
|
|
setCurrentDesktop( desktop );
|
|
}
|
|
|
|
void Workspace::slotSwitchToDesktop( int i )
|
|
{
|
|
setCurrentDesktop( i );
|
|
}
|
|
|
|
|
|
void Workspace::slotWindowToDesktop( int i )
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if( i >= 1 && i <= numberOfDesktops() && c
|
|
&& !c->isDesktop()
|
|
&& !c->isDock()
|
|
&& !c->isTopMenu())
|
|
sendClientToDesktop( c, i, true );
|
|
}
|
|
|
|
void Workspace::slotSwitchToScreen( int i )
|
|
{
|
|
setCurrentScreen( i );
|
|
}
|
|
|
|
void Workspace::slotSwitchToNextScreen()
|
|
{
|
|
slotSwitchToScreen(( activeScreen() + 1 ) % numScreens());
|
|
}
|
|
|
|
void Workspace::slotWindowToScreen( int i )
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if( i >= 0 && i <= numScreens() && c
|
|
&& !c->isDesktop()
|
|
&& !c->isDock()
|
|
&& !c->isTopMenu())
|
|
{
|
|
sendClientToScreen( c, i );
|
|
}
|
|
}
|
|
|
|
void Workspace::slotWindowToNextScreen()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if( c
|
|
&& !c->isDesktop()
|
|
&& !c->isDock()
|
|
&& !c->isTopMenu())
|
|
{
|
|
sendClientToScreen( c, ( c->screen() + 1 ) % numScreens());
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Maximizes the popup client
|
|
*/
|
|
void Workspace::slotWindowMaximize()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if ( c )
|
|
performWindowOperation( c, Options::MaximizeOp );
|
|
}
|
|
|
|
/*!
|
|
Maximizes the popup client vertically
|
|
*/
|
|
void Workspace::slotWindowMaximizeVertical()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if ( c )
|
|
performWindowOperation( c, Options::VMaximizeOp );
|
|
}
|
|
|
|
/*!
|
|
Maximizes the popup client horiozontally
|
|
*/
|
|
void Workspace::slotWindowMaximizeHorizontal()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if ( c )
|
|
performWindowOperation( c, Options::HMaximizeOp );
|
|
}
|
|
|
|
|
|
/*!
|
|
Minimizes the popup client
|
|
*/
|
|
void Workspace::slotWindowMinimize()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
performWindowOperation( c, Options::MinimizeOp );
|
|
}
|
|
|
|
/*!
|
|
Shades/unshades the popup client respectively
|
|
*/
|
|
void Workspace::slotWindowShade()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
performWindowOperation( c, Options::ShadeOp );
|
|
}
|
|
|
|
/*!
|
|
Raises the popup client
|
|
*/
|
|
void Workspace::slotWindowRaise()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if ( c )
|
|
raiseClient( c );
|
|
}
|
|
|
|
/*!
|
|
Lowers the popup client
|
|
*/
|
|
void Workspace::slotWindowLower()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if ( c )
|
|
{
|
|
lowerClient( c );
|
|
// As this most likely makes the window no longer visible change the
|
|
// keyboard focus to the next available window.
|
|
//activateNextClient( c ); // Doesn't work when we lower a child window
|
|
activateClient( topClientOnDesktop( currentDesktop(), -1 ));
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Does a toggle-raise-and-lower on the popup client;
|
|
*/
|
|
void Workspace::slotWindowRaiseOrLower()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if ( c )
|
|
raiseOrLowerClient( c );
|
|
}
|
|
|
|
void Workspace::slotWindowOnAllDesktops()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if( c )
|
|
c->setOnAllDesktops( !c->isOnAllDesktops());
|
|
}
|
|
|
|
void Workspace::slotWindowFullScreen()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if( c )
|
|
performWindowOperation( c, Options::FullScreenOp );
|
|
}
|
|
|
|
void Workspace::slotWindowNoBorder()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if( c )
|
|
performWindowOperation( c, Options::NoBorderOp );
|
|
}
|
|
|
|
void Workspace::slotWindowAbove()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if( c )
|
|
performWindowOperation( c, Options::KeepAboveOp );
|
|
}
|
|
|
|
void Workspace::slotWindowBelow()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if( c )
|
|
performWindowOperation( c, Options::KeepBelowOp );
|
|
}
|
|
void Workspace::slotSetupWindowShortcut()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if( c )
|
|
performWindowOperation( c, Options::SetupWindowShortcutOp );
|
|
}
|
|
|
|
/*!
|
|
Toggles show desktop
|
|
*/
|
|
void Workspace::slotToggleShowDesktop()
|
|
{
|
|
setShowingDesktop( !showingDesktop() );
|
|
}
|
|
|
|
/*!
|
|
Move window to next desktop
|
|
*/
|
|
void Workspace::slotWindowToNextDesktop()
|
|
{
|
|
windowToNextDesktop( active_popup_client ? active_popup_client : active_client );
|
|
}
|
|
|
|
void Workspace::windowToNextDesktop( Client* c )
|
|
{
|
|
int d = currentDesktop() + 1;
|
|
if ( d > numberOfDesktops() )
|
|
d = 1;
|
|
if (c && !c->isDesktop()
|
|
&& !c->isDock() && !c->isTopMenu())
|
|
{
|
|
setClientIsMoving( c );
|
|
setCurrentDesktop( d );
|
|
setClientIsMoving( NULL );
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Move window to previous desktop
|
|
*/
|
|
void Workspace::slotWindowToPreviousDesktop()
|
|
{
|
|
windowToPreviousDesktop( active_popup_client ? active_popup_client : active_client );
|
|
}
|
|
|
|
void Workspace::windowToPreviousDesktop( Client* c )
|
|
{
|
|
int d = currentDesktop() - 1;
|
|
if ( d <= 0 )
|
|
d = numberOfDesktops();
|
|
if (c && !c->isDesktop()
|
|
&& !c->isDock() && !c->isTopMenu())
|
|
{
|
|
setClientIsMoving( c );
|
|
setCurrentDesktop( d );
|
|
setClientIsMoving( NULL );
|
|
}
|
|
}
|
|
|
|
void Workspace::slotWindowToDesktopRight()
|
|
{
|
|
int d = desktopToRight( currentDesktop(), options->rollOverDesktops);
|
|
if( d == currentDesktop())
|
|
return;
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if (c && !c->isDesktop()
|
|
&& !c->isDock() && !c->isTopMenu())
|
|
{
|
|
setClientIsMoving( c );
|
|
setCurrentDesktop( d );
|
|
setClientIsMoving( NULL );
|
|
}
|
|
}
|
|
|
|
void Workspace::slotWindowToDesktopLeft()
|
|
{
|
|
int d = desktopToLeft( currentDesktop(), options->rollOverDesktops);
|
|
if( d == currentDesktop())
|
|
return;
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if (c && !c->isDesktop()
|
|
&& !c->isDock() && !c->isTopMenu())
|
|
{
|
|
setClientIsMoving( c );
|
|
setCurrentDesktop( d );
|
|
setClientIsMoving( NULL );
|
|
}
|
|
}
|
|
|
|
void Workspace::slotWindowToDesktopUp()
|
|
{
|
|
int d = desktopAbove( currentDesktop(), options->rollOverDesktops);
|
|
if( d == currentDesktop())
|
|
return;
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if (c && !c->isDesktop()
|
|
&& !c->isDock() && !c->isTopMenu())
|
|
{
|
|
setClientIsMoving( c );
|
|
setCurrentDesktop( d );
|
|
setClientIsMoving( NULL );
|
|
}
|
|
}
|
|
|
|
void Workspace::slotWindowToDesktopDown()
|
|
{
|
|
int d = desktopBelow( currentDesktop(), options->rollOverDesktops);
|
|
if( d == currentDesktop())
|
|
return;
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
if (c && !c->isDesktop()
|
|
&& !c->isDock() && !c->isTopMenu())
|
|
{
|
|
setClientIsMoving( c );
|
|
setCurrentDesktop( d );
|
|
setClientIsMoving( NULL );
|
|
}
|
|
}
|
|
|
|
void Workspace::slotSwitchToTabRight()
|
|
{
|
|
if( !active_client || !active_client->clientGroup() )
|
|
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 || !active_client->clientGroup() )
|
|
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 || !active_client->clientGroup() )
|
|
return;
|
|
active_client->clientGroup()->remove( active_client );
|
|
}
|
|
|
|
/*!
|
|
Kill Window feature, similar to xkill
|
|
*/
|
|
void Workspace::slotKillWindow()
|
|
{
|
|
KillWindow kill( this );
|
|
kill.start();
|
|
}
|
|
|
|
/*!
|
|
Sends the popup client to desktop \a desk
|
|
|
|
Internal slot for the window operation menu
|
|
*/
|
|
void Workspace::slotSendToDesktop( QAction *action )
|
|
{
|
|
int desk = action->data().toInt();
|
|
if ( !active_popup_client )
|
|
return;
|
|
if ( desk == 0 )
|
|
{ // the 'on_all_desktops' menu entry
|
|
active_popup_client->setOnAllDesktops( !active_popup_client->isOnAllDesktops());
|
|
return;
|
|
}
|
|
|
|
sendClientToDesktop( active_popup_client, desk, false );
|
|
|
|
}
|
|
|
|
/*!
|
|
Switches to the nearest window in given direction
|
|
*/
|
|
void Workspace::switchWindow( Direction direction )
|
|
{
|
|
if( !active_client )
|
|
return;
|
|
Client *c = active_client;
|
|
Client *switchTo = 0;
|
|
int bestScore = 0;
|
|
int d = c->desktop();
|
|
// Centre of the active window
|
|
QPoint curPos( c->pos().x() + c->geometry().width() / 2,
|
|
c->pos().y() + c->geometry().height() / 2 );
|
|
|
|
QList<Client *> clist = stackingOrder();
|
|
for( QList<Client *>::Iterator i = clist.begin(); i != clist.end(); ++i )
|
|
{
|
|
if( (*i)->wantsTabFocus() && *i != c &&
|
|
(*i)->desktop() == d && ! (*i)->isMinimized() )
|
|
{
|
|
// Centre of the other window
|
|
QPoint other( (*i)->pos().x() + (*i)->geometry().width() / 2,
|
|
(*i)->pos().y() + (*i)->geometry().height() / 2 );
|
|
|
|
int distance;
|
|
int offset;
|
|
switch( direction )
|
|
{
|
|
case DirectionNorth:
|
|
distance = curPos.y() - other.y();
|
|
offset = qAbs(other.x() - curPos.x());
|
|
break;
|
|
case DirectionEast:
|
|
distance = other.x() - curPos.x();
|
|
offset = qAbs(other.y() - curPos.y());
|
|
break;
|
|
case DirectionSouth:
|
|
distance = other.y() - curPos.y();
|
|
offset = qAbs(other.x() - curPos.x());
|
|
break;
|
|
case DirectionWest:
|
|
distance = curPos.x() - other.x();
|
|
offset = qAbs(other.y() - curPos.y());
|
|
break;
|
|
default:
|
|
distance = -1;
|
|
offset = -1;
|
|
}
|
|
|
|
if( distance > 0 )
|
|
{
|
|
// Inverse score
|
|
int score = distance + offset + ( (offset * offset) / distance );
|
|
if( score < bestScore || !switchTo )
|
|
{
|
|
switchTo = *i;
|
|
bestScore = score;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( switchTo )
|
|
activateClient( switchTo );
|
|
}
|
|
|
|
/*!
|
|
Switches to upper window
|
|
*/
|
|
void Workspace::slotSwitchWindowUp()
|
|
{
|
|
switchWindow( DirectionNorth );
|
|
}
|
|
|
|
/*!
|
|
Switches to lower window
|
|
*/
|
|
void Workspace::slotSwitchWindowDown()
|
|
{
|
|
switchWindow( DirectionSouth );
|
|
}
|
|
|
|
/*!
|
|
Switches to window on the right
|
|
*/
|
|
void Workspace::slotSwitchWindowRight()
|
|
{
|
|
switchWindow( DirectionEast );
|
|
}
|
|
|
|
/*!
|
|
Switches to window on the left
|
|
*/
|
|
void Workspace::slotSwitchWindowLeft()
|
|
{
|
|
switchWindow( DirectionWest );
|
|
}
|
|
|
|
/*!
|
|
Shows the window operations popup menu for the activeClient()
|
|
*/
|
|
void Workspace::slotWindowOperations()
|
|
{
|
|
if ( !active_client )
|
|
return;
|
|
QPoint pos = active_client->pos() + active_client->clientPos();
|
|
showWindowMenu( pos.x(), pos.y(), active_client );
|
|
}
|
|
|
|
void Workspace::showWindowMenu( const QRect &pos, Client* cl )
|
|
{
|
|
if (!KAuthorized::authorizeKAction("kwin_rmb"))
|
|
return;
|
|
if( !cl )
|
|
return;
|
|
if( active_popup_client != NULL ) // recursion
|
|
return;
|
|
if ( cl->isDesktop()
|
|
|| cl->isDock()
|
|
|| cl->isTopMenu())
|
|
return;
|
|
|
|
active_popup_client = cl;
|
|
QMenu* p = clientPopup();
|
|
active_popup = p;
|
|
int x = pos.left();
|
|
int y = pos.bottom();
|
|
if (y == pos.top())
|
|
p->exec( QPoint( x, y ) );
|
|
else
|
|
{
|
|
QRect area = clientArea(ScreenArea, QPoint(x, y), currentDesktop());
|
|
clientPopupAboutToShow(); // needed for sizeHint() to be correct :-/
|
|
int popupHeight = p->sizeHint().height();
|
|
if (y + popupHeight < area.height())
|
|
p->exec( QPoint( x, y ) );
|
|
else
|
|
p->exec( QPoint( x, pos.top() - popupHeight ) );
|
|
}
|
|
// active popup may be already changed (e.g. the window shortcut dialog)
|
|
if( active_popup == p )
|
|
closeActivePopup();
|
|
}
|
|
|
|
/*!
|
|
Closes the popup client
|
|
*/
|
|
void Workspace::slotWindowClose()
|
|
{
|
|
// TODO: why?
|
|
// if ( tab_box->isVisible())
|
|
// return;
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
performWindowOperation( c, Options::CloseOp );
|
|
}
|
|
|
|
/*!
|
|
Starts keyboard move mode for the popup client
|
|
*/
|
|
void Workspace::slotWindowMove()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
performWindowOperation( c, Options::UnrestrictedMoveOp );
|
|
}
|
|
|
|
/*!
|
|
Starts keyboard resize mode for the popup client
|
|
*/
|
|
void Workspace::slotWindowResize()
|
|
{
|
|
Client* c = active_popup_client ? active_popup_client : active_client;
|
|
performWindowOperation( c, Options::UnrestrictedResizeOp );
|
|
}
|
|
|
|
void Client::setShortcut( const QString& _cut )
|
|
{
|
|
QString cut = rules()->checkShortcut( _cut );
|
|
if( cut.isEmpty())
|
|
return setShortcutInternal( KShortcut());
|
|
// Format:
|
|
// base+(abcdef)<space>base+(abcdef)
|
|
// E.g. Alt+Ctrl+(ABCDEF) Win+X,Win+(ABCDEF)
|
|
if( !cut.contains( '(' ) && !cut.contains( ')' ) && !cut.contains( ' ' ))
|
|
{
|
|
if( workspace()->shortcutAvailable( KShortcut( cut ), this ))
|
|
setShortcutInternal( KShortcut( cut ));
|
|
else
|
|
setShortcutInternal( KShortcut());
|
|
return;
|
|
}
|
|
QList< KShortcut > keys;
|
|
QStringList groups = cut.split( ' ');
|
|
for( QStringList::ConstIterator it = groups.constBegin();
|
|
it != groups.constEnd();
|
|
++it )
|
|
{
|
|
QRegExp reg( "(.*\\+)\\((.*)\\)" );
|
|
if( reg.indexIn( *it ) > -1 )
|
|
{
|
|
QString base = reg.cap( 1 );
|
|
QString list = reg.cap( 2 );
|
|
for( int i = 0;
|
|
i < list.length();
|
|
++i )
|
|
{
|
|
KShortcut c( base + list[ i ] );
|
|
if( !c.isEmpty())
|
|
keys.append( c );
|
|
}
|
|
}
|
|
}
|
|
for( QList< KShortcut >::ConstIterator it = keys.constBegin();
|
|
it != keys.constEnd();
|
|
++it )
|
|
{
|
|
if( _shortcut == *it ) // current one is in the list
|
|
return;
|
|
}
|
|
for( QList< KShortcut >::ConstIterator it = keys.constBegin();
|
|
it != keys.constEnd();
|
|
++it )
|
|
{
|
|
if( workspace()->shortcutAvailable( *it, this ))
|
|
{
|
|
setShortcutInternal( *it );
|
|
return;
|
|
}
|
|
}
|
|
setShortcutInternal( KShortcut());
|
|
}
|
|
|
|
void Client::setShortcutInternal( const KShortcut& cut )
|
|
{
|
|
if( _shortcut == cut )
|
|
return;
|
|
_shortcut = cut;
|
|
updateCaption();
|
|
#if 0
|
|
workspace()->clientShortcutUpdated( this );
|
|
#else
|
|
// Workaround for kwin<->kglobalaccel deadlock, when KWin has X grab and the kded
|
|
// kglobalaccel module tries to create the key grab. KWin should preferably grab
|
|
// they keys itself anyway :(.
|
|
QTimer::singleShot( 0, this, SLOT( delayedSetShortcut()));
|
|
#endif
|
|
}
|
|
|
|
void Client::delayedSetShortcut()
|
|
{
|
|
workspace()->clientShortcutUpdated( this );
|
|
}
|
|
|
|
bool Workspace::shortcutAvailable( const KShortcut& cut, Client* ignore ) const
|
|
{
|
|
// TODO check global shortcuts etc.
|
|
for( ClientList::ConstIterator it = clients.constBegin();
|
|
it != clients.constEnd();
|
|
++it )
|
|
{
|
|
if( (*it) != ignore && (*it)->shortcut() == cut )
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|