Embedded mode for TabBox

DBus method to embedd the TabBox into another window. It follows
the geometry changes and keeps a defined offset to the borders of
the parent window.

Required for Plasma Active's window strip.
icc-effect-5.14.5
Martin Gräßlin 2011-12-01 08:48:18 +01:00
parent b57ef77bf7
commit 5eb5a60cc5
6 changed files with 198 additions and 10 deletions

View File

@ -39,6 +39,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kephal/screens.h> #include <kephal/screens.h>
// KWin // KWin
#include "thumbnailitem.h" #include "thumbnailitem.h"
#include <kwindowsystem.h>
namespace KWin namespace KWin
{ {
@ -104,10 +105,16 @@ DeclarativeView::DeclarativeView(QAbstractItemModel *model, QWidget *parent)
, m_currentScreenGeometry() , m_currentScreenGeometry()
, m_frame(new Plasma::FrameSvg(this)) , m_frame(new Plasma::FrameSvg(this))
, m_currentLayout() , m_currentLayout()
, m_cachedWidth(0)
, m_cachedHeight(0)
{ {
setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(Qt::X11BypassWindowManagerHint); setWindowFlags(Qt::X11BypassWindowManagerHint);
if (tabBox->embedded()) {
setResizeMode(QDeclarativeView::SizeRootObjectToView);
} else {
setResizeMode(QDeclarativeView::SizeViewToRootObject); setResizeMode(QDeclarativeView::SizeViewToRootObject);
}
QPalette pal = palette(); QPalette pal = palette();
pal.setColor(backgroundRole(), Qt::transparent); pal.setColor(backgroundRole(), Qt::transparent);
setPalette(pal); setPalette(pal);
@ -130,10 +137,14 @@ DeclarativeView::DeclarativeView(QAbstractItemModel *model, QWidget *parent)
m_frame->setEnabledBorders(Plasma::FrameSvg::AllBorders); m_frame->setEnabledBorders(Plasma::FrameSvg::AllBorders);
connect(tabBox, SIGNAL(configChanged()), SLOT(updateQmlSource())); connect(tabBox, SIGNAL(configChanged()), SLOT(updateQmlSource()));
connect(tabBox, SIGNAL(embeddedChanged(bool)), SLOT(slotEmbeddedChanged(bool)));
} }
void DeclarativeView::showEvent(QShowEvent *event) void DeclarativeView::showEvent(QShowEvent *event)
{ {
if (tabBox->embedded()) {
connect(KWindowSystem::self(), SIGNAL(windowChanged(WId,uint)), SLOT(slotWindowChanged(WId, uint)));
}
updateQmlSource(); updateQmlSource();
m_currentScreenGeometry = Kephal::ScreenUtils::screenGeometry(tabBox->activeScreen()); m_currentScreenGeometry = Kephal::ScreenUtils::screenGeometry(tabBox->activeScreen());
rootObject()->setProperty("screenWidth", m_currentScreenGeometry.width()); rootObject()->setProperty("screenWidth", m_currentScreenGeometry.width());
@ -154,10 +165,12 @@ void DeclarativeView::showEvent(QShowEvent *event)
void DeclarativeView::resizeEvent(QResizeEvent *event) void DeclarativeView::resizeEvent(QResizeEvent *event)
{ {
m_frame->resizeFrame(event->size()); m_frame->resizeFrame(event->size());
if (Plasma::Theme::defaultTheme()->windowTranslucencyEnabled()) { if (Plasma::Theme::defaultTheme()->windowTranslucencyEnabled() && !tabBox->embedded()) {
// blur background // blur background
Plasma::WindowEffects::enableBlurBehind(winId(), true, m_frame->mask()); Plasma::WindowEffects::enableBlurBehind(winId(), true, m_frame->mask());
Plasma::WindowEffects::overrideShadow(winId(), true); Plasma::WindowEffects::overrideShadow(winId(), true);
} else if (tabBox->embedded()) {
Plasma::WindowEffects::enableBlurBehind(winId(), false);
} else { } else {
// do not trim to mask with compositing enabled, otherwise shadows are cropped // do not trim to mask with compositing enabled, otherwise shadows are cropped
setMask(m_frame->mask()); setMask(m_frame->mask());
@ -165,14 +178,52 @@ void DeclarativeView::resizeEvent(QResizeEvent *event)
QDeclarativeView::resizeEvent(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)));
}
}
void DeclarativeView::slotUpdateGeometry() void DeclarativeView::slotUpdateGeometry()
{ {
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));
} else {
const int width = rootObject()->property("width").toInt(); const int width = rootObject()->property("width").toInt();
const int height = rootObject()->property("height").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, 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, m_currentScreenGeometry.y() + static_cast<qreal>(m_currentScreenGeometry.height()) * 0.5 - static_cast<qreal>(height) * 0.5,
width, height); width, height);
} }
}
void DeclarativeView::setCurrentIndex(const QModelIndex &index) void DeclarativeView::setCurrentIndex(const QModelIndex &index)
{ {
@ -201,9 +252,9 @@ void DeclarativeView::currentIndexChanged(int row)
tabBox->setCurrentIndex(m_model->index(row, 0)); 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; return;
} }
m_currentLayout = tabBox->config().layoutName(); m_currentLayout = tabBox->config().layoutName();
@ -215,5 +266,32 @@ void DeclarativeView::updateQmlSource()
rootObject()->setProperty("source", QUrl(file)); 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 TabBox
} // namespace KWin } // namespace KWin

View File

@ -58,11 +58,16 @@ public:
void setCurrentIndex(const QModelIndex &index); void setCurrentIndex(const QModelIndex &index);
QModelIndex indexAt(const QPoint &pos) const; QModelIndex indexAt(const QPoint &pos) const;
protected:
virtual void hideEvent(QHideEvent *event);
public Q_SLOTS: public Q_SLOTS:
void slotUpdateGeometry(); void slotUpdateGeometry();
void slotEmbeddedChanged(bool enabled);
private Q_SLOTS: private Q_SLOTS:
void updateQmlSource(); void updateQmlSource(bool force = false);
void currentIndexChanged(int row); void currentIndexChanged(int row);
void slotWindowChanged(WId wId, unsigned int properties);
private: private:
QAbstractItemModel *m_model; QAbstractItemModel *m_model;
QRect m_currentScreenGeometry; QRect m_currentScreenGeometry;
@ -71,6 +76,8 @@ private:
*/ */
Plasma::FrameSvg* m_frame; Plasma::FrameSvg* m_frame;
QString m_currentLayout; QString m_currentLayout;
int m_cachedWidth;
int m_cachedHeight;
}; };
} // namespace TabBox } // namespace TabBox

View File

@ -968,7 +968,23 @@ void TabBox::open(bool modal)
} else { } else {
m_tabGrab = false; 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; 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); setMode(TabBoxWindowsMode);
reset(); reset();
show(); show();
@ -980,6 +996,7 @@ bool TabBox::startKDEWalkThroughWindows(TabBoxMode mode)
return false; return false;
m_tabGrab = true; m_tabGrab = true;
m_noModifierGrab = false; m_noModifierGrab = false;
tabBox->resetEmbedded();
modalActionsSwitch(false); modalActionsSwitch(false);
setMode(mode); setMode(mode);
reset(); reset();

View File

@ -175,6 +175,22 @@ public slots:
* mode or whether the TabBox is controlled externally (e.g. through an effect). * mode or whether the TabBox is controlled externally (e.g. through an effect).
**/ **/
Q_SCRIPTABLE void open(bool modal = true); 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 close(bool abort = false);
void slotWalkThroughDesktops(); void slotWalkThroughDesktops();
void slotWalkBackThroughDesktops(); void slotWalkBackThroughDesktops();

View File

@ -89,11 +89,18 @@ public:
bool isShown; bool isShown;
QMap< QString, ItemLayoutConfig > tabBoxLayouts; QMap< QString, ItemLayoutConfig > tabBoxLayouts;
TabBoxClient *lastRaisedClient, *lastRaisedClientSucc; TabBoxClient *lastRaisedClient, *lastRaisedClientSucc;
WId m_embedded;
QPoint m_embeddedOffset;
QSize m_embeddedSize;
Qt::Alignment m_embeddedAlignment;
}; };
TabBoxHandlerPrivate::TabBoxHandlerPrivate(TabBoxHandler *q) TabBoxHandlerPrivate::TabBoxHandlerPrivate(TabBoxHandler *q)
: view(NULL) : view(NULL)
, m_declarativeView(NULL) , m_declarativeView(NULL)
, m_embedded(0)
, m_embeddedOffset(QPoint(0, 0))
, m_embeddedSize(QSize(0, 0))
{ {
this->q = q; this->q = q;
isShown = false; isShown = false;
@ -698,6 +705,58 @@ QWidget* TabBoxHandler::tabBoxView() const
return d->view; 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; TabBoxHandler* tabBox = 0;
TabBoxClient::TabBoxClient() TabBoxClient::TabBoxClient()

View File

@ -315,6 +315,16 @@ public:
*/ */
QModelIndex first() const; 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 * @return The tabBoxView Widget
*/ */
@ -348,6 +358,7 @@ signals:
*/ */
void configChanged(); void configChanged();
void ready(); void ready();
void embeddedChanged(bool enabled);
private: private:
friend class TabBoxHandlerPrivate; friend class TabBoxHandlerPrivate;