Merge branch 'kwin/tabbox-window-strip' into integration

This commit is contained in:
Martin Gräßlin 2011-12-21 07:45:52 +01:00
commit 6f9f736973
20 changed files with 575 additions and 29 deletions

View file

@ -18,7 +18,6 @@ endif(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop")
if(KWIN_PLASMA_ACTIVE)
set(KWIN_BUILD_DECORATIONS OFF)
set(KWIN_BUILD_KCMS OFF)
set(KWIN_BUILD_TABBOX OFF)
set(KWIN_BUILD_TILING OFF)
set(KWIN_BUILD_DESKTOPCHANGEOSD OFF)
set(KWIN_BUILD_SCREENEDGES OFF)
@ -257,6 +256,7 @@ install( FILES
tabbox/qml/text.qml
tabbox/qml/thumbnails.qml
tabbox/qml/IconTabBox.qml
tabbox/qml/window_strip.qml
DESTINATION ${DATA_INSTALL_DIR}/kwin/tabbox )
kde4_install_icons( ${ICON_INSTALL_DIR} )

View file

@ -126,6 +126,9 @@ Atoms::Atoms()
atoms[n] = &kde_net_wm_tab_group;
names[n++] = (char*) "_KDE_NET_WM_TAB_GROUP";
atoms[n] = &kde_first_in_window_list;
names[n++] = (char*) "_KDE_FIRST_IN_WINDOWLIST";
assert(n <= max);
XInternAtoms(display(), names, n, false, atoms_return);

View file

@ -64,6 +64,7 @@ public:
Atom kde_net_wm_shadow;
Atom net_wm_opaque_region;
Atom kde_net_wm_tab_group;
Atom kde_first_in_window_list;
};

View file

@ -129,6 +129,7 @@ Client::Client(Workspace* ws)
, demandAttentionKNotifyTimer(NULL)
, m_responsibleForDecoPixmap(false)
, paintRedirector(0)
, m_firstInTabBox(false)
, electricMaximizing(false)
, activitiesDefined(false)
, needsSessionInteract(false)
@ -2408,6 +2409,24 @@ QRect Client::decorationRect() const
}
}
void Client::updateFirstInTabBox()
{
// TODO: move into KWindowInfo
Atom type;
int format, status;
unsigned long nitems = 0;
unsigned long extra = 0;
unsigned char *data = 0;
status = XGetWindowProperty(display(), window(), atoms->kde_first_in_window_list, 0, 1, false, atoms->kde_first_in_window_list, &type, &format, &nitems, &extra, &data);
if (status == Success && format == 32 && nitems == 1) {
setFirstInTabBox(true);
} else {
setFirstInTabBox(false);
}
if (data)
XFree(data);
}
} // namespace
#include "client.moc"

View file

@ -426,6 +426,13 @@ public:
TabBox::TabBoxClientImpl* tabBoxClient() const {
return m_tabBoxClient;
}
bool isFirstInTabBox() const {
return m_firstInTabBox;
}
void setFirstInTabBox(bool enable) {
m_firstInTabBox = enable;
}
void updateFirstInTabBox();
//sets whether the client should be treated as a SessionInteract window
void setSessionInteract(bool needed);
@ -719,6 +726,7 @@ private:
bool m_responsibleForDecoPixmap;
PaintRedirector* paintRedirector;
TabBox::TabBoxClientImpl* m_tabBoxClient;
bool m_firstInTabBox;
bool electricMaximizing;
QuickTileMode electricMode;

View file

@ -857,6 +857,8 @@ void Client::propertyNotifyEvent(XPropertyEvent* e)
checkActivities();
else if (e->atom == atoms->kde_net_wm_block_compositing)
updateCompositeBlocking(true);
else if (e->atom == atoms->kde_first_in_window_list)
updateFirstInTabBox();
break;
}
}

View file

@ -142,6 +142,7 @@ bool Client::manage(Window w, bool isMapped)
original_skip_taskbar = skip_taskbar = (info->state() & NET::SkipTaskbar) != 0;
skip_pager = (info->state() & NET::SkipPager) != 0;
updateFirstInTabBox();
setupCompositing();

View file

@ -419,8 +419,8 @@ void Scene::paintWindow(Window* w, int mask, QRegion region, WindowQuadList quad
} else {
thumbMask |= PAINT_WINDOW_TRANSLUCENT;
}
if (x < wImpl->x() || x + size.width() > wImpl->x() + wImpl->width() ||
y < wImpl->y() || y + size.height() > wImpl->y() + wImpl->height()) {
if (item->isClip() && (x < wImpl->x() || x + size.width() > wImpl->x() + wImpl->width() ||
y < wImpl->y() || y + size.height() > wImpl->y() + wImpl->height())) {
// don't render windows outside the containing window.
// TODO: improve by spliting out the window quads which do not fit
continue;

View file

@ -43,6 +43,7 @@ ClientModel::ClientModel(QObject* parent)
roles[DesktopNameRole] = "desktopName";
roles[MinimizedRole] = "minimized";
roles[WIdRole] = "windowId";
roles[CloseableRole] = "closeable";
setRoleNames(roles);
}
@ -80,6 +81,8 @@ QVariant ClientModel::data(const QModelIndex& index, int role) const
return qulonglong(m_clientList[ clientIndex ]->window());
case MinimizedRole:
return m_clientList[ clientIndex ]->isMinimized();
case CloseableRole:
return m_clientList[ clientIndex ]->isCloseable();
default:
return QVariant();
}
@ -172,6 +175,7 @@ void ClientModel::createClientList(int desktop, bool partialReset)
start = m_clientList.first();
m_clientList.clear();
QList<TabBoxClient*> stickyClients;
switch(tabBox->config().clientSwitchingMode()) {
case TabBoxConfig::FocusChainSwitching: {
@ -187,6 +191,9 @@ void ClientModel::createClientList(int desktop, bool partialReset)
m_clientList.prepend(add);
} else
m_clientList += add;
if (add->isFirstInTabBox()) {
stickyClients << add;
}
}
c = tabBox->nextClientFocusChain(c);
@ -211,6 +218,9 @@ void ClientModel::createClientList(int desktop, bool partialReset)
m_clientList.prepend(add);
} else
m_clientList += add;
if (add->isFirstInTabBox()) {
stickyClients << add;
}
}
if (index >= stacking.size() - 1) {
c = NULL;
@ -224,6 +234,10 @@ void ClientModel::createClientList(int desktop, bool partialReset)
break;
}
}
foreach (TabBoxClient *c, stickyClients) {
m_clientList.removeAll(c);
m_clientList.prepend(c);
}
if (tabBox->config().isShowDesktop()) {
TabBoxClient* desktopClient = tabBox->desktopClient();
if (desktopClient)
@ -232,5 +246,24 @@ void ClientModel::createClientList(int desktop, bool partialReset)
reset();
}
void ClientModel::close(int i)
{
QModelIndex ind = index(i, 0);
if (!ind.isValid()) {
return;
}
m_clientList.at(i)->close();
}
void ClientModel::activate(int i)
{
QModelIndex ind = index(i, 0);
if (!ind.isValid()) {
return;
}
tabBox->setCurrentIndex(ind);
tabBox->activateAndClose();
}
} // namespace Tabbox
} // namespace KWin

View file

@ -46,6 +46,7 @@ namespace TabBox
class ClientModel
: public QAbstractItemModel
{
Q_OBJECT
public:
enum {
ClientRole = Qt::UserRole, ///< The TabBoxClient
@ -54,7 +55,8 @@ public:
IconRole = Qt::UserRole + 3, // TODO: to be removed
EmptyRole = Qt::UserRole + 4, ///< Indicates if the model contains TabBoxClients
WIdRole = Qt::UserRole + 5, ///< The window ID of TabBoxClient
MinimizedRole = Qt::UserRole + 6 ///< TabBoxClient is minimized
MinimizedRole = Qt::UserRole + 6, ///< TabBoxClient is minimized
CloseableRole = Qt::UserRole + 7 ///< TabBoxClient can be closed
};
ClientModel(QObject* parent = 0);
~ClientModel();
@ -94,6 +96,14 @@ public:
return m_clientList;
}
public Q_SLOTS:
void close(int index);
/**
* Activates the client at @p index and closes the TabBox.
* @param index The row index
**/
void activate(int index);
private:
TabBoxClientList m_clientList;
};

View file

@ -27,6 +27,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QtDeclarative/QDeclarativeEngine>
#include <QtGui/QGraphicsObject>
#include <QtGui/QResizeEvent>
#include <QX11Info>
// include KDE
#include <KDE/KDebug>
#include <KDE/KIconEffect>
@ -39,6 +41,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kephal/screens.h>
// KWin
#include "thumbnailitem.h"
#include <kwindowsystem.h>
namespace KWin
{
@ -104,10 +107,16 @@ DeclarativeView::DeclarativeView(QAbstractItemModel *model, QWidget *parent)
, m_currentScreenGeometry()
, m_frame(new Plasma::FrameSvg(this))
, m_currentLayout()
, m_cachedWidth(0)
, m_cachedHeight(0)
{
setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(Qt::X11BypassWindowManagerHint);
setResizeMode(QDeclarativeView::SizeViewToRootObject);
if (tabBox->embedded()) {
setResizeMode(QDeclarativeView::SizeRootObjectToView);
} else {
setResizeMode(QDeclarativeView::SizeViewToRootObject);
}
QPalette pal = palette();
pal.setColor(backgroundRole(), Qt::transparent);
setPalette(pal);
@ -130,10 +139,14 @@ DeclarativeView::DeclarativeView(QAbstractItemModel *model, QWidget *parent)
m_frame->setEnabledBorders(Plasma::FrameSvg::AllBorders);
connect(tabBox, SIGNAL(configChanged()), SLOT(updateQmlSource()));
connect(tabBox, SIGNAL(embeddedChanged(bool)), SLOT(slotEmbeddedChanged(bool)));
}
void DeclarativeView::showEvent(QShowEvent *event)
{
if (tabBox->embedded()) {
connect(KWindowSystem::self(), SIGNAL(windowChanged(WId,uint)), SLOT(slotWindowChanged(WId, uint)));
}
updateQmlSource();
m_currentScreenGeometry = Kephal::ScreenUtils::screenGeometry(tabBox->activeScreen());
rootObject()->setProperty("screenWidth", m_currentScreenGeometry.width());
@ -154,10 +167,12 @@ void DeclarativeView::showEvent(QShowEvent *event)
void DeclarativeView::resizeEvent(QResizeEvent *event)
{
m_frame->resizeFrame(event->size());
if (Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) {
if (Plasma::Theme::defaultTheme()->windowTranslucencyEnabled() && !tabBox->embedded()) {
// blur background
Plasma::WindowEffects::enableBlurBehind(winId(), true, m_frame->mask());
Plasma::WindowEffects::overrideShadow(winId(), true);
} else if (tabBox->embedded()) {
Plasma::WindowEffects::enableBlurBehind(winId(), false);
} else {
// do not trim to mask with compositing enabled, otherwise shadows are cropped
setMask(m_frame->mask());
@ -165,13 +180,76 @@ void DeclarativeView::resizeEvent(QResizeEvent *event)
QDeclarativeView::resizeEvent(event);
}
void DeclarativeView::hideEvent(QHideEvent *event)
{
QWidget::hideEvent(event);
if (tabBox->embedded()) {
disconnect(KWindowSystem::self(), SIGNAL(windowChanged(WId,uint)), this, SLOT(slotWindowChanged(WId,uint)));
}
}
bool DeclarativeView::x11Event(XEvent *e)
{
if (tabBox->embedded() &&
(e->type == ButtonPress || e->type == ButtonRelease || e->type == MotionNotify)) {
XEvent ev;
memcpy(&ev, e, sizeof(ev));
if (e->type == ButtonPress || e->type == ButtonRelease) {
ev.xbutton.x += m_relativePos.x();
ev.xbutton.y += m_relativePos.y();
ev.xbutton.window = tabBox->embedded();
} else if (e->type == MotionNotify) {
ev.xmotion.x += m_relativePos.x();
ev.xmotion.y += m_relativePos.y();
ev.xmotion.window = tabBox->embedded();
}
XSendEvent( QX11Info::display(), tabBox->embedded(), False, NoEventMask, &ev );
}
return QDeclarativeView::x11Event(e);
}
void DeclarativeView::slotUpdateGeometry()
{
const int width = rootObject()->property("width").toInt();
const int height = rootObject()->property("height").toInt();
setGeometry(m_currentScreenGeometry.x() + static_cast<qreal>(m_currentScreenGeometry.width()) * 0.5 - static_cast<qreal>(width) * 0.5,
m_currentScreenGeometry.y() + static_cast<qreal>(m_currentScreenGeometry.height()) * 0.5 - static_cast<qreal>(height) * 0.5,
width, height);
const WId embeddedId = tabBox->embedded();
if (embeddedId != 0) {
const KWindowInfo info = KWindowSystem::windowInfo(embeddedId, NET::WMGeometry);
const Qt::Alignment alignment = tabBox->embeddedAlignment();
const QPoint offset = tabBox->embeddedOffset();
int x = info.geometry().left();
int y = info.geometry().top();
int width = tabBox->embeddedSize().width();
int height = tabBox->embeddedSize().height();
if (alignment.testFlag(Qt::AlignLeft) || alignment.testFlag(Qt::AlignHCenter)) {
x += offset.x();
}
if (alignment.testFlag(Qt::AlignRight)) {
x = x + info.geometry().width() - offset.x() - width;
}
if (alignment.testFlag(Qt::AlignHCenter)) {
width = info.geometry().width() - 2 * offset.x();
}
if (alignment.testFlag(Qt::AlignTop) || alignment.testFlag(Qt::AlignVCenter)) {
y += offset.y();
}
if (alignment.testFlag(Qt::AlignBottom)) {
y = y + info.geometry().height() - offset.y() - height;
}
if (alignment.testFlag(Qt::AlignVCenter)) {
height = info.geometry().height() - 2 * offset.y();
}
setGeometry(QRect(x, y, width, height));
m_relativePos = QPoint(info.geometry().x(), info.geometry().x());
} else {
const int width = rootObject()->property("width").toInt();
const int height = rootObject()->property("height").toInt();
setGeometry(m_currentScreenGeometry.x() + static_cast<qreal>(m_currentScreenGeometry.width()) * 0.5 - static_cast<qreal>(width) * 0.5,
m_currentScreenGeometry.y() + static_cast<qreal>(m_currentScreenGeometry.height()) * 0.5 - static_cast<qreal>(height) * 0.5,
width, height);
m_relativePos = pos();
}
}
void DeclarativeView::setCurrentIndex(const QModelIndex &index)
@ -201,9 +279,9 @@ void DeclarativeView::currentIndexChanged(int row)
tabBox->setCurrentIndex(m_model->index(row, 0));
}
void DeclarativeView::updateQmlSource()
void DeclarativeView::updateQmlSource(bool force)
{
if (tabBox->config().layoutName() == m_currentLayout) {
if (!force && tabBox->config().layoutName() == m_currentLayout) {
return;
}
m_currentLayout = tabBox->config().layoutName();
@ -215,5 +293,32 @@ void DeclarativeView::updateQmlSource()
rootObject()->setProperty("source", QUrl(file));
}
void DeclarativeView::slotEmbeddedChanged(bool enabled)
{
if (enabled) {
// cache the width
setResizeMode(QDeclarativeView::SizeRootObjectToView);
m_cachedWidth = rootObject()->property("width").toInt();
m_cachedHeight = rootObject()->property("height").toInt();
} else {
setResizeMode(QDeclarativeView::SizeViewToRootObject);
if (m_cachedWidth != 0 && m_cachedHeight != 0) {
rootObject()->setProperty("width", m_cachedWidth);
rootObject()->setProperty("height", m_cachedHeight);
}
updateQmlSource(true);
}
}
void DeclarativeView::slotWindowChanged(WId wId, unsigned int properties)
{
if (wId != tabBox->embedded()) {
return;
}
if (properties & NET::WMGeometry) {
slotUpdateGeometry();
}
}
} // namespace TabBox
} // namespace KWin

View file

@ -58,11 +58,17 @@ public:
void setCurrentIndex(const QModelIndex &index);
QModelIndex indexAt(const QPoint &pos) const;
protected:
virtual void hideEvent(QHideEvent *event);
virtual bool x11Event(XEvent *e);
public Q_SLOTS:
void slotUpdateGeometry();
void slotEmbeddedChanged(bool enabled);
private Q_SLOTS:
void updateQmlSource();
void updateQmlSource(bool force = false);
void currentIndexChanged(int row);
void slotWindowChanged(WId wId, unsigned int properties);
private:
QAbstractItemModel *m_model;
QRect m_currentScreenGeometry;
@ -71,6 +77,10 @@ private:
*/
Plasma::FrameSvg* m_frame;
QString m_currentLayout;
int m_cachedWidth;
int m_cachedHeight;
//relative position to the embedding window
QPoint m_relativePos;
};
} // namespace TabBox

145
tabbox/qml/window_strip.qml Normal file
View file

@ -0,0 +1,145 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2011 Marco Martin <mart@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/>.
*********************************************************************/
import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.plasma.components 0.1 as PlasmaComponents
import org.kde.plasma.mobilecomponents 0.1 as MobileComponents
import org.kde.qtextracomponents 0.1
import org.kde.kwin 0.1 as KWin
Item {
id: thumbnailTabBox
property int screenWidth
property bool canStretchX: false
property bool canStretchY: false
width: screenWidth
height: 150
clip: true
function setModel(model) {
thumbnailListView.model = model;
}
// just to get the margin sizes
PlasmaCore.FrameSvgItem {
id: hoverItem
imagePath: "widgets/viewitem"
prefix: "hover"
visible: false
}
PlasmaCore.Theme {
id: theme
}
PlasmaCore.Svg {
id: iconsSvg
imagePath: "widgets/configuration-icons"
}
ListView {
/**
* Called from C++ to get the index at a mouse pos.
**/
function indexAtMousePos(pos) {
return thumbnailListView.indexAt(pos.x, pos.y);
}
signal currentIndexChanged(int index)
id: thumbnailListView
objectName: "listView"
orientation: ListView.Horizontal
height: parent.height
spacing: 10
anchors.fill: parent
clip: true
delegate: Item {
id: delegateItem
width: thumbnailListView.height * 1.6 + 48
height: thumbnailListView.height
KWin.ThumbnailItem {
id: thumbnailItem
wId: windowId
width: parent.width - closeButtonContainer.width - 20
height: thumbnailListView.height - 40
clip: false
anchors.centerIn: parent
MouseArea {
anchors.fill: parent
onClicked: {
thumbnailListView.currentIndex = index;
thumbnailListView.currentIndexChanged(index);
}
}
}
PlasmaComponents.Label {
id: windowTitle
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter;
anchors.topMargin: 4
text: caption
elide: Text.ElideRight
color: theme.textColor
width: parent.width - 40
horizontalAlignment: Text.AlignHCenter
}
PlasmaCore.FrameSvgItem {
id: closeButtonContainer
imagePath: "widgets/button"
prefix: "shadow"
width: closeButton.width + margins.left + margins.right
height: closeButton.height + margins.top + margins.bottom
visible: closeable
anchors {
top: parent.top
right: parent.right
topMargin: 32
}
PlasmaCore.FrameSvgItem {
id: closeButton
imagePath: "widgets/button"
prefix: "normal"
//a bit more left margin
width: closeButtonSvg.width + margins.left + margins.right + 16
height: closeButtonSvg.height + margins.top + margins.bottom
x: parent.margins.left
y: parent.margins.top
MobileComponents.ActionButton {
id: closeButtonSvg
svg: iconsSvg
iconSize: 22
backgroundVisible: false
elementId: "close"
anchors {
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: parent.margins.right
}
onClicked: thumbnailListView.model.close(index)
}
}
}
}
}
}

View file

@ -34,6 +34,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Qt
#include <QAction>
#include <QX11Info>
#include <QtDBus/QDBusConnection>
// KDE
#include <KActionCollection>
#include <KConfig>
@ -213,6 +214,10 @@ QVector< Window > TabBoxHandlerImpl::outlineWindowIds() const
return Workspace::self()->outline()->windowIds();
}
void TabBoxHandlerImpl::activateAndClose()
{
m_tabBox->accept();
}
/*********************************************************
* TabBoxClientImpl
@ -270,6 +275,20 @@ int TabBoxClientImpl::height() const
return m_client->height();
}
bool TabBoxClientImpl::isCloseable() const
{
return m_client->isCloseable();
}
void TabBoxClientImpl::close()
{
m_client->closeWindow();
}
bool TabBoxClientImpl::isFirstInTabBox() const
{
return m_client->isFirstInTabBox();
}
/*********************************************************
* TabBox
@ -279,6 +298,7 @@ TabBox::TabBox(QObject *parent)
, m_displayRefcount(0)
, m_desktopGrab(false)
, m_tabGrab(false)
, m_noModifierGrab(false)
, m_forcedGlobalMouseGrab(false)
, m_ready(false)
{
@ -310,14 +330,17 @@ TabBox::TabBox(QObject *parent)
m_desktopListConfig.setLayout(TabBoxConfig::VerticalLayout);
m_tabBox = new TabBoxHandlerImpl(this);
connect(m_tabBox, SIGNAL(ready()), SLOT(handlerReady()));
connect(m_tabBox, SIGNAL(selectedIndexChanged()), SIGNAL(itemSelected()));
m_tabBoxMode = TabBoxDesktopMode; // init variables
connect(&m_delayedShowTimer, SIGNAL(timeout()), this, SLOT(show()));
connect(Workspace::self(), SIGNAL(configChanged()), this, SLOT(reconfigure()));
QDBusConnection::sessionBus().registerObject("/TabBox", this, QDBusConnection::ExportScriptableContents);
}
TabBox::~TabBox()
{
QDBusConnection::sessionBus().unregisterObject("/TabBox");
}
void TabBox::handlerReady()
@ -659,6 +682,11 @@ void TabBox::grabbedKeyEvent(QKeyEvent* event)
// tabbox has been replaced, check effects
return;
}
if (m_noModifierGrab) {
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return || event->key() == Qt::Key_Space) {
accept();
}
}
setCurrentIndex(m_tabBox->grabbedKeyEvent(event));
}
@ -913,11 +941,48 @@ void TabBox::modalActionsSwitch(bool enabled)
action->setEnabled(enabled);
}
void TabBox::open(bool modal)
{
if (isDisplayed()) {
return;
}
if (modal) {
if (!establishTabBoxGrab()) {
return;
}
m_tabGrab = true;
} else {
m_tabGrab = false;
}
m_noModifierGrab = !modal;
setMode(TabBoxWindowsMode);
reset();
show();
}
void TabBox::openEmbedded(qulonglong wid, QPoint offset, QSize size, int horizontalAlignment, int verticalAlignment)
{
if (isDisplayed()) {
return;
}
m_tabGrab = false;
m_noModifierGrab = true;
tabBox->setEmbedded(static_cast<WId>(wid));
tabBox->setEmbeddedOffset(offset);
tabBox->setEmbeddedSize(size);
tabBox->setEmbeddedAlignment(static_cast<Qt::AlignmentFlag>(horizontalAlignment) | static_cast<Qt::AlignmentFlag>(verticalAlignment));
setMode(TabBoxWindowsMode);
reset();
show();
}
bool TabBox::startKDEWalkThroughWindows(TabBoxMode mode)
{
if (!establishTabBoxGrab())
return false;
m_tabGrab = true;
m_noModifierGrab = false;
tabBox->resetEmbedded();
modalActionsSwitch(false);
setMode(mode);
reset();
@ -929,6 +994,7 @@ bool TabBox::startWalkThroughDesktops(TabBoxMode mode)
if (!establishTabBoxGrab())
return false;
m_desktopGrab = true;
m_noModifierGrab = false;
modalActionsSwitch(false);
setMode(mode);
reset();
@ -1091,11 +1157,32 @@ void TabBox::keyPress(int keyQt)
void TabBox::close(bool abort)
{
removeTabBoxGrab();
if (isGrabbed()) {
removeTabBoxGrab();
}
hide(abort);
modalActionsSwitch(true);
m_tabGrab = false;
m_desktopGrab = false;
m_noModifierGrab = false;
}
void TabBox::accept()
{
Client* c = currentClient();
close();
if (c) {
Workspace::self()->activateClient(c);
if (c->isShade() && options->shadeHover)
c->setShade(ShadeActivated);
if (c->isDesktop())
Workspace::self()->setShowingDesktop(!Workspace::self()->showingDesktop());
}
}
void TabBox::reject()
{
close(true);
}
/*!
@ -1103,6 +1190,9 @@ void TabBox::close(bool abort)
*/
void TabBox::keyRelease(const XKeyEvent& ev)
{
if (m_noModifierGrab) {
return;
}
unsigned int mk = ev.state &
(KKeyServer::modXShift() |
KKeyServer::modXCtrl() |
@ -1136,16 +1226,8 @@ void TabBox::keyRelease(const XKeyEvent& ev)
return;
if (m_tabGrab) {
bool old_control_grab = m_desktopGrab;
Client* c = currentClient();
close();
accept();
m_desktopGrab = old_control_grab;
if (c) {
Workspace::self()->activateClient(c);
if (c->isShade() && options->shadeHover)
c->setShade(ShadeActivated);
if (c->isDesktop())
Workspace::self()->setShowingDesktop(!Workspace::self()->showingDesktop());
}
}
if (m_desktopGrab) {
bool old_tab_grab = m_tabGrab;

View file

@ -61,6 +61,7 @@ public:
virtual void hideOutline();
virtual void showOutline(const QRect &outline);
virtual QVector< Window > outlineWindowIds() const;
virtual void activateAndClose();
private:
TabBox* m_tabBox;
@ -80,6 +81,9 @@ public:
virtual int y() const;
virtual int width() const;
virtual int height() const;
virtual bool isCloseable() const;
virtual void close();
virtual bool isFirstInTabBox() const;
Client* client() const {
return m_client;
@ -95,6 +99,7 @@ private:
class TabBox : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin")
public:
TabBox(QObject *parent = NULL);
~TabBox();
@ -160,12 +165,36 @@ public:
int previousDesktopFocusChain(int iDesktop) const;
int nextDesktopStatic(int iDesktop) const;
int previousDesktopStatic(int iDesktop) const;
void close(bool abort = false);
void keyPress(int key);
void keyRelease(const XKeyEvent& ev);
public slots:
void show();
/**
* Only for DBus Interface to start primary KDE Walk through windows.
* @param modal Whether the TabBox should grab keyboard and mouse, that is go into modal
* mode or whether the TabBox is controlled externally (e.g. through an effect).
**/
Q_SCRIPTABLE void open(bool modal = true);
/**
* Opens the TabBox view embedded on a different window. This implies non-modal mode.
* The geometry of the TabBox is determined by offset, size and the alignment flags.
* If the alignment flags are set to center the view scales with the container. That is if
* the window where the TabBox is embedded onto resizes, the TabBox resizes, too.
* The alignment in combination with the offset determines to what border the TabBox is snapped.
* E.g. if horizontal alignment is right the offset is interpreted as the offset between right
* corner of TabBox view and the container view. When the container changes its geometry this
* offset is kept. So the offset on the left side would increase.
* @param wid The window Id the TabBox should be embedded onto
* @param offset The offset to one of the size borders
* @param size The size of the TabBox. To use the same size as the container, set alignment to center
* @param horizontalAlignment Either Qt::AlignLeft, Qt::AlignHCenter or Qt::AlignRight
* @param verticalAlignment Either Qt::AlignTop, Qt::AlignVCenter or Qt::AlignBottom
**/
Q_SCRIPTABLE void openEmbedded(qulonglong wid, QPoint offset, QSize size, int horizontalAlignment, int verticalAlignment);
Q_SCRIPTABLE void close(bool abort = false);
Q_SCRIPTABLE void accept();
Q_SCRIPTABLE void reject();
void slotWalkThroughDesktops();
void slotWalkBackThroughDesktops();
void slotWalkThroughDesktopList();
@ -190,7 +219,8 @@ public slots:
signals:
void tabBoxAdded(int);
void tabBoxClosed();
Q_SCRIPTABLE void tabBoxClosed();
Q_SCRIPTABLE void itemSelected();
void tabBoxUpdated();
void tabBoxKeyEvent(QKeyEvent*);
@ -235,6 +265,8 @@ private:
bool m_isShown;
bool m_desktopGrab;
bool m_tabGrab;
// true if tabbox is in modal mode which does not require holding a modifier
bool m_noModifierGrab;
KShortcut m_cutWalkThroughDesktops, m_cutWalkThroughDesktopsReverse;
KShortcut m_cutWalkThroughDesktopList, m_cutWalkThroughDesktopListReverse;
KShortcut m_cutWalkThroughWindows, m_cutWalkThroughWindowsReverse;

View file

@ -89,11 +89,18 @@ public:
bool isShown;
QMap< QString, ItemLayoutConfig > tabBoxLayouts;
TabBoxClient *lastRaisedClient, *lastRaisedClientSucc;
WId m_embedded;
QPoint m_embeddedOffset;
QSize m_embeddedSize;
Qt::Alignment m_embeddedAlignment;
};
TabBoxHandlerPrivate::TabBoxHandlerPrivate(TabBoxHandler *q)
: view(NULL)
, m_declarativeView(NULL)
, m_embedded(0)
, m_embeddedOffset(QPoint(0, 0))
, m_embeddedSize(QSize(0, 0))
{
this->q = q;
isShown = false;
@ -552,6 +559,7 @@ void TabBoxHandler::setCurrentIndex(const QModelIndex& index)
d->updateHighlightWindows();
}
}
emit selectedIndexChanged();
}
const QModelIndex& TabBoxHandler::currentIndex() const
@ -586,11 +594,13 @@ QModelIndex TabBoxHandler::grabbedKeyEvent(QKeyEvent* event) const
if (column >= model->columnCount())
column = 0;
break;
case Qt::Key_Backtab:
case Qt::Key_Up:
row--;
if (row < 0)
row = model->rowCount() - 1;
break;
case Qt::Key_Tab:
case Qt::Key_Down:
row++;
if (row >= model->rowCount())
@ -696,6 +706,58 @@ QWidget* TabBoxHandler::tabBoxView() const
return d->view;
}
WId TabBoxHandler::embedded() const
{
return d->m_embedded;
}
void TabBoxHandler::setEmbedded(WId wid)
{
d->m_embedded = wid;
emit embeddedChanged(wid != 0);
}
void TabBoxHandler::setEmbeddedOffset(const QPoint &offset)
{
d->m_embeddedOffset = offset;
}
void TabBoxHandler::setEmbeddedSize(const QSize &size)
{
d->m_embeddedSize = size;
}
const QPoint &TabBoxHandler::embeddedOffset() const
{
return d->m_embeddedOffset;
}
const QSize &TabBoxHandler::embeddedSize() const
{
return d->m_embeddedSize;
}
Qt::Alignment TabBoxHandler::embeddedAlignment() const
{
return d->m_embeddedAlignment;
}
void TabBoxHandler::setEmbeddedAlignment(Qt::Alignment alignment)
{
d->m_embeddedAlignment = alignment;
}
void TabBoxHandler::resetEmbedded()
{
if (d->m_embedded == 0) {
return;
}
d->m_embedded = 0;
d->m_embeddedOffset = QPoint(0, 0);
d->m_embeddedSize = QSize(0, 0);
emit embeddedChanged(false);
}
TabBoxHandler* tabBox = 0;
TabBoxClient::TabBoxClient()

View file

@ -173,6 +173,10 @@ public:
* @return The first desktop window in the stacking order.
*/
virtual TabBoxClient* desktopClient() const = 0;
/**
* Activates the currently selected client and closes the TabBox.
**/
virtual void activateAndClose() = 0;
/**
* @return The currently used TabBoxConfig
@ -311,6 +315,16 @@ public:
*/
QModelIndex first() const;
void setEmbedded(WId wid);
WId embedded() const;
void setEmbeddedOffset(const QPoint &offset);
const QPoint &embeddedOffset() const;
void setEmbeddedSize(const QSize &size);
const QSize &embeddedSize() const;
void setEmbeddedAlignment(Qt::Alignment alignment);
Qt::Alignment embeddedAlignment() const;
void resetEmbedded();
/**
* @return The tabBoxView Widget
*/
@ -344,6 +358,8 @@ signals:
*/
void configChanged();
void ready();
void embeddedChanged(bool enabled);
void selectedIndexChanged();
private:
friend class TabBoxHandlerPrivate;
@ -384,6 +400,9 @@ public:
virtual int y() const = 0;
virtual int width() const = 0;
virtual int height() const = 0;
virtual bool isCloseable() const = 0;
virtual void close() = 0;
virtual bool isFirstInTabBox() const = 0;
};
/**

View file

@ -35,6 +35,7 @@ namespace KWin
ThumbnailItem::ThumbnailItem(QDeclarativeItem* parent)
: QDeclarativeItem(parent)
, m_wId(0)
, m_clip(true)
, m_parent(QWeakPointer<EffectWindowImpl>())
{
setFlags(flags() & ~QGraphicsItem::ItemHasNoContents);
@ -81,6 +82,12 @@ void ThumbnailItem::setWId(qulonglong wId)
emit wIdChanged(wId);
}
void ThumbnailItem::setClip(bool clip)
{
m_clip = clip;
emit clipChanged(clip);
}
void ThumbnailItem::effectWindowAdded()
{
// the window might be added before the EffectWindow is created

View file

@ -34,6 +34,7 @@ class ThumbnailItem : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(qulonglong wId READ wId WRITE setWId NOTIFY wIdChanged SCRIPTABLE true)
Q_PROPERTY(bool clip READ isClip WRITE setClip NOTIFY clipChanged SCRIPTABLE true)
public:
ThumbnailItem(QDeclarativeItem *parent = 0);
virtual ~ThumbnailItem();
@ -42,15 +43,21 @@ public:
return m_wId;
}
void setWId(qulonglong wId);
bool isClip() const {
return m_clip;
}
void setClip(bool clip);
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
Q_SIGNALS:
void wIdChanged(qulonglong wid);
void clipChanged(bool clipped);
private Q_SLOTS:
void init();
void effectWindowAdded();
private:
void findParentEffectWindow();
qulonglong m_wId;
bool m_clip;
QWeakPointer<EffectWindowImpl> m_parent;
};

View file

@ -638,7 +638,7 @@ void Workspace::addClient(Client* c, allowed_t)
updateToolWindows(true);
checkNonExistentClients();
#ifdef KWIN_BUILD_TABBOX
if (tabBox()->isGrabbed())
if (tabBox()->isDisplayed())
tab_box->reset(true);
#endif
}
@ -672,7 +672,7 @@ void Workspace::removeClient(Client* c, allowed_t)
Notify::raise(Notify::Delete);
#ifdef KWIN_BUILD_TABBOX
if (tabBox()->isGrabbed() && tabBox()->currentClient() == c)
if (tabBox()->isDisplayed() && tabBox()->currentClient() == c)
tab_box->nextPrev(true);
#endif
@ -708,7 +708,7 @@ void Workspace::removeClient(Client* c, allowed_t)
updateCompositeBlocking();
#ifdef KWIN_BUILD_TABBOX
if (tabBox()->isGrabbed())
if (tabBox()->isDisplayed())
tab_box->reset(true);
#endif