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>
// KWin
#include "thumbnailitem.h"
#include <kwindowsystem.h>
namespace KWin
{
@ -104,10 +105,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 +137,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 +165,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 +178,51 @@ 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)));
}
}
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));
} 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);
}
}
void DeclarativeView::setCurrentIndex(const QModelIndex &index)
@ -201,9 +252,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 +266,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,16 @@ public:
void setCurrentIndex(const QModelIndex &index);
QModelIndex indexAt(const QPoint &pos) const;
protected:
virtual void hideEvent(QHideEvent *event);
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 +76,8 @@ private:
*/
Plasma::FrameSvg* m_frame;
QString m_currentLayout;
int m_cachedWidth;
int m_cachedHeight;
};
} // namespace TabBox

View File

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

View File

@ -175,6 +175,22 @@ public slots:
* 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);
void slotWalkThroughDesktops();
void slotWalkBackThroughDesktops();

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;
@ -698,6 +705,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

@ -315,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
*/
@ -348,6 +358,7 @@ signals:
*/
void configChanged();
void ready();
void embeddedChanged(bool enabled);
private:
friend class TabBoxHandlerPrivate;