kwin/kcmkwin/kwindecoration/preview.cpp
2011-01-31 20:07:03 +01:00

598 lines
14 KiB
C++

/*
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "preview.h"
#include <kapplication.h>
#include <klocale.h>
#include <kconfig.h>
#include <kglobal.h>
#include <QLabel>
#include <QStyle>
#include <QPainter>
#include <QMouseEvent>
#include <QResizeEvent>
#include <QVector>
#include <kicon.h>
#include <X11/Xlib.h>
#include <X11/extensions/shape.h>
#include <kdecorationfactory.h>
#include <kdecoration_plugins_p.h>
#include <QX11Info>
#include <kwindowsystem.h>
#include <QTextDocument>
KDecorationPreview::KDecorationPreview(QWidget* parent)
: QWidget(parent)
{
options = new KDecorationPreviewOptions;
bridge[Active] = new KDecorationPreviewBridge(this, true);
bridge[Inactive] = new KDecorationPreviewBridge(this, false);
deco[Active] = deco[Inactive] = NULL;
no_preview = new QLabel(i18n("No preview available.\n"
"Most probably there\n"
"was a problem loading the plugin."), this);
no_preview->setAlignment(Qt::AlignCenter);
setMinimumSize(100, 100);
no_preview->resize(size());
}
KDecorationPreview::~KDecorationPreview()
{
for (int i = 0; i < NumWindows; i++) {
delete deco[i];
delete bridge[i];
}
delete options;
}
bool KDecorationPreview::recreateDecoration(KDecorationPlugins* plugins)
{
for (int i = 0; i < NumWindows; i++) {
delete deco[i]; // deletes also window
deco[i] = plugins->createDecoration(bridge[i]);
deco[i]->init();
}
if (deco[Active] == NULL || deco[Inactive] == NULL) {
return false;
}
positionPreviews();
//deco[Inactive]->widget()->show();
//deco[Active]->widget()->show();
//deco[Inactive]->widget()->render( this, deco[Inactive]->widget()->mapToParent( QPoint(0,0) ) );
return true;
}
void KDecorationPreview::enablePreview()
{
no_preview->hide();
}
void KDecorationPreview::disablePreview()
{
delete deco[Active];
delete deco[Inactive];
deco[Active] = deco[Inactive] = NULL;
no_preview->show();
}
void KDecorationPreview::paintEvent(QPaintEvent* e)
{
Q_UNUSED(e);
QPainter painter(this);
QPoint delta = mapTo(window(), QPoint(0, 0));
if (deco[Inactive]) {
QWidget *w = deco[Inactive]->widget();
w->render(&painter, delta + w->mapToParent(QPoint(0, 0)));
}
if (deco[Active]) {
QWidget *w = deco[Active]->widget();
w->render(&painter, delta + w->mapToParent(QPoint(0, 0)));
}
}
QPixmap KDecorationPreview::preview(QTextDocument* document, QWidget* widget)
{
Q_UNUSED(document);
Q_UNUSED(widget);
QPixmap pixmap(size());
pixmap.fill(Qt::transparent);
if (deco[Inactive]) {
QWidget *w = deco[Inactive]->widget();
w->render(&pixmap, w->mapToParent(QPoint(0, 0)));
}
if (deco[Active]) {
QWidget *w = deco[Active]->widget();
w->render(&pixmap, w->mapToParent(QPoint(0, 0)));
}
return pixmap;
}
void KDecorationPreview::resizeEvent(QResizeEvent* e)
{
QWidget::resizeEvent(e);
positionPreviews();
}
void KDecorationPreview::positionPreviews()
{
int titleBarHeight, leftBorder, rightBorder, xoffset,
dummy1, dummy2, dummy3;
QRect geometry;
QSize size;
no_preview->resize(this->size());
if (!deco[Active] || !deco[Inactive])
return;
// don't have more than one reference to the same dummy variable in one borders() call.
deco[Active]->borders(dummy1, dummy2, titleBarHeight, dummy3);
deco[Inactive]->borders(leftBorder, rightBorder, dummy1, dummy2);
titleBarHeight = qMin(int(titleBarHeight * .9), 30);
xoffset = qMin(qMax(10, QApplication::isRightToLeft()
? leftBorder : rightBorder), 30);
// Resize the active window
size = QSize(width() - xoffset, height() - titleBarHeight)
.expandedTo(deco[Active]->minimumSize());
geometry = QRect(QPoint(0, titleBarHeight), size);
if (KDecorationUnstable *unstable = qobject_cast<KDecorationUnstable *>(deco[Active])) {
int padLeft, padRight, padTop, padBottom;
unstable->padding(padLeft, padRight, padTop, padBottom);
geometry.adjust(-padLeft, -padTop, padRight, padBottom);
}
geometry.adjust(10, 10, -10, -10);
deco[Active]->widget()->setGeometry(QStyle::visualRect(this->layoutDirection(), this->rect(), geometry));
// Resize the inactive window
size = QSize(width() - xoffset, height() - titleBarHeight)
.expandedTo(deco[Inactive]->minimumSize());
geometry = QRect(QPoint(xoffset, 0), size);
if (KDecorationUnstable *unstable = qobject_cast<KDecorationUnstable *>(deco[Inactive])) {
int padLeft, padRight, padTop, padBottom;
unstable->padding(padLeft, padRight, padTop, padBottom);
geometry.adjust(-padLeft, -padTop, padRight, padBottom);
}
geometry.adjust(10, 10, -10, -10);
deco[Inactive]->widget()->setGeometry(QStyle::visualRect(this->layoutDirection(), this->rect(), geometry));
}
void KDecorationPreview::setPreviewMask(const QRegion& reg, int mode, bool active)
{
QWidget *widget = active ? deco[Active]->widget() : deco[Inactive]->widget();
// FRAME duped from client.cpp
if (mode == Unsorted) {
XShapeCombineRegion(QX11Info::display(), widget->winId(), ShapeBounding, 0, 0,
reg.handle(), ShapeSet);
} else {
QVector< QRect > rects = reg.rects();
XRectangle* xrects = new XRectangle[ rects.count()];
for (int i = 0;
i < rects.count();
++i) {
xrects[ i ].x = rects[ i ].x();
xrects[ i ].y = rects[ i ].y();
xrects[ i ].width = rects[ i ].width();
xrects[ i ].height = rects[ i ].height();
}
XShapeCombineRectangles(QX11Info::display(), widget->winId(), ShapeBounding, 0, 0,
xrects, rects.count(), ShapeSet, mode);
delete[] xrects;
}
if (active)
mask = reg; // keep shape of the active window for unobscuredRegion()
}
QRect KDecorationPreview::windowGeometry(bool active) const
{
QWidget *widget = active ? deco[Active]->widget() : deco[Inactive]->widget();
return widget->geometry();
}
void KDecorationPreview::setTempBorderSize(KDecorationPlugins* plugin, KDecorationDefines::BorderSize size)
{
options->setCustomBorderSize(size);
if (plugin->factory()->reset(KDecorationDefines::SettingBorder)) {
// can't handle the change, recreate decorations then
recreateDecoration(plugin);
} else {
// handles the update, only update position...
positionPreviews();
}
}
void KDecorationPreview::setTempButtons(KDecorationPlugins* plugin, bool customEnabled, const QString &left, const QString &right)
{
options->setCustomTitleButtonsEnabled(customEnabled);
options->setCustomTitleButtons(left, right);
if (plugin->factory()->reset(KDecorationDefines::SettingButtons)) {
// can't handle the change, recreate decorations then
recreateDecoration(plugin);
} else {
// handles the update, only update position...
positionPreviews();
}
}
QRegion KDecorationPreview::unobscuredRegion(bool active, const QRegion& r) const
{
if (active) // this one is not obscured
return r;
else {
// copied from KWin core's code
QRegion ret = r;
QRegion r2 = mask;
if (r2.isEmpty())
r2 = QRegion(windowGeometry(true));
r2.translate(windowGeometry(true).x() - windowGeometry(false).x(),
windowGeometry(true).y() - windowGeometry(false).y());
ret -= r2;
return ret;
}
}
KDecorationPreviewBridge::KDecorationPreviewBridge(KDecorationPreview* p, bool a)
: preview(p), active(a)
{
}
QWidget* KDecorationPreviewBridge::initialParentWidget() const
{
return preview;
}
Qt::WFlags KDecorationPreviewBridge::initialWFlags() const
{
return 0;
}
bool KDecorationPreviewBridge::isActive() const
{
return active;
}
bool KDecorationPreviewBridge::isCloseable() const
{
return true;
}
bool KDecorationPreviewBridge::isMaximizable() const
{
return true;
}
KDecoration::MaximizeMode KDecorationPreviewBridge::maximizeMode() const
{
return KDecoration::MaximizeRestore;
}
bool KDecorationPreviewBridge::isMinimizable() const
{
return true;
}
bool KDecorationPreviewBridge::providesContextHelp() const
{
return true;
}
int KDecorationPreviewBridge::desktop() const
{
return 1;
}
bool KDecorationPreviewBridge::isModal() const
{
return false;
}
bool KDecorationPreviewBridge::isShadeable() const
{
return true;
}
bool KDecorationPreviewBridge::isShade() const
{
return false;
}
bool KDecorationPreviewBridge::isSetShade() const
{
return false;
}
bool KDecorationPreviewBridge::keepAbove() const
{
return false;
}
bool KDecorationPreviewBridge::keepBelow() const
{
return false;
}
bool KDecorationPreviewBridge::isMovable() const
{
return true;
}
bool KDecorationPreviewBridge::isResizable() const
{
return true;
}
NET::WindowType KDecorationPreviewBridge::windowType(unsigned long) const
{
return NET::Normal;
}
QIcon KDecorationPreviewBridge::icon() const
{
return KIcon("xorg");
}
QString KDecorationPreviewBridge::caption() const
{
return active ? i18n("Active Window") : i18n("Inactive Window");
}
void KDecorationPreviewBridge::processMousePressEvent(QMouseEvent*)
{
}
void KDecorationPreviewBridge::showWindowMenu(const QRect &)
{
}
void KDecorationPreviewBridge::showWindowMenu(const QPoint &)
{
}
void KDecorationPreviewBridge::performWindowOperation(WindowOperation)
{
}
void KDecorationPreviewBridge::setMask(const QRegion& reg, int mode)
{
preview->setPreviewMask(reg, mode, active);
}
bool KDecorationPreviewBridge::isPreview() const
{
return true;
}
QRect KDecorationPreviewBridge::geometry() const
{
return preview->windowGeometry(active);
}
QRect KDecorationPreviewBridge::iconGeometry() const
{
return QRect();
}
QRegion KDecorationPreviewBridge::unobscuredRegion(const QRegion& r) const
{
return preview->unobscuredRegion(active, r);
}
WId KDecorationPreviewBridge::windowId() const
{
return 0; // no decorated window
}
void KDecorationPreviewBridge::closeWindow()
{
}
void KDecorationPreviewBridge::maximize(MaximizeMode)
{
}
void KDecorationPreviewBridge::minimize()
{
}
void KDecorationPreviewBridge::showContextHelp()
{
}
void KDecorationPreviewBridge::setDesktop(int)
{
}
void KDecorationPreviewBridge::titlebarDblClickOperation()
{
}
void KDecorationPreviewBridge::titlebarMouseWheelOperation(int)
{
}
void KDecorationPreviewBridge::setShade(bool)
{
}
void KDecorationPreviewBridge::setKeepAbove(bool)
{
}
void KDecorationPreviewBridge::setKeepBelow(bool)
{
}
int KDecorationPreviewBridge::currentDesktop() const
{
return 1;
}
void KDecorationPreviewBridge::grabXServer(bool)
{
}
bool KDecorationPreviewBridge::compositingActive() const
{
return KWindowSystem::compositingActive();
}
QRect KDecorationPreviewBridge::transparentRect() const
{
return QRect();
}
// Window tabbing
bool KDecorationPreviewBridge::isClientGroupActive()
{
return active;
}
QList< ClientGroupItem > KDecorationPreviewBridge::clientGroupItems() const
{
return QList< ClientGroupItem >() << ClientGroupItem(
active ? "Active Window" : "Inactive Window", icon());
}
long KDecorationPreviewBridge::itemId(int)
{
return 0;
}
int KDecorationPreviewBridge::visibleClientGroupItem()
{
return 0;
}
void KDecorationPreviewBridge::setVisibleClientGroupItem(int)
{
}
void KDecorationPreviewBridge::moveItemInClientGroup(int, int)
{
}
void KDecorationPreviewBridge::moveItemToClientGroup(long, int)
{
}
void KDecorationPreviewBridge::removeFromClientGroup(int, const QRect&)
{
}
void KDecorationPreviewBridge::closeClientGroupItem(int)
{
}
void KDecorationPreviewBridge::closeAllInClientGroup()
{
}
void KDecorationPreviewBridge::displayClientMenu(int, const QPoint&)
{
}
KDecoration::WindowOperation KDecorationPreviewBridge::buttonToWindowOperation(Qt::MouseButtons)
{
return KDecoration::NoOp;
}
KDecorationPreviewOptions::KDecorationPreviewOptions()
{
customBorderSize = BordersCount; // invalid
customButtonsChanged = false; // invalid
customButtons = true;
customTitleButtonsLeft.clear(); // invalid
customTitleButtonsRight.clear(); // invalid
updateSettings();
}
KDecorationPreviewOptions::~KDecorationPreviewOptions()
{
}
unsigned long KDecorationPreviewOptions::updateSettings()
{
KConfig cfg("kwinrc");
unsigned long changed = 0;
changed |= KDecorationOptions::updateSettings(&cfg);
// set custom border size/buttons
if (customBorderSize != BordersCount)
setBorderSize(customBorderSize);
if (customButtonsChanged)
setCustomButtonPositions(customButtons);
if (customButtons) {
if (!customTitleButtonsLeft.isNull())
setTitleButtonsLeft(customTitleButtonsLeft);
if (!customTitleButtonsRight.isNull())
setTitleButtonsRight(customTitleButtonsRight);
} else {
setTitleButtonsLeft(KDecorationOptions::defaultTitleButtonsLeft());
setTitleButtonsRight(KDecorationOptions::defaultTitleButtonsRight());
}
return changed;
}
void KDecorationPreviewOptions::setCustomBorderSize(BorderSize size)
{
customBorderSize = size;
updateSettings();
}
void KDecorationPreviewOptions::setCustomTitleButtonsEnabled(bool enabled)
{
customButtonsChanged = true;
customButtons = enabled;
updateSettings();
}
void KDecorationPreviewOptions::setCustomTitleButtons(const QString &left, const QString &right)
{
customTitleButtonsLeft = left;
customTitleButtonsRight = right;
updateSettings();
}
bool KDecorationPreviewPlugins::provides(Requirement)
{
return false;
}
#include "preview.moc"