kde-workspace/plasma/desktop/shell/panelview.cpp

1679 lines
57 KiB
C++
Raw Normal View History

2014-11-13 19:30:51 +02:00
/*
* Copyright 2007 by Matt Broadstone <mbroadst@kde.org>
* Copyright 2007 by Robert Knight <robertknight@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2,
* 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 Library 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 "panelview.h"
#include <QApplication>
#include <QGraphicsLinearLayout>
#include <QPropertyAnimation>
#include <QTimer>
#ifdef Q_WS_X11
#include <X11/Xatom.h>
#include <QX11Info>
#include <X11/extensions/shape.h>
#endif
#include <KDebug>
#include <KIdleTime>
#include <KWindowSystem>
#include <Plasma/Containment>
#include <Plasma/Corona>
#include <Plasma/Plasma>
#include <Plasma/PopupApplet>
#include <Plasma/Svg>
#include <Plasma/Theme>
#include <Plasma/WindowEffects>
#include <kephal/screens.h>
#include "desktopcorona.h"
#include "panelappletoverlay.h"
#include "panelcontroller.h"
#include "panelshadows.h"
#include "plasmaapp.h"
class GlowBar : public QWidget
{
public:
GlowBar(Plasma::Direction direction, const QRect &triggerZone)
: QWidget(0),
m_strength(0.3),
m_svg(new Plasma::Svg(this)),
m_direction(direction)
{
setAttribute(Qt::WA_TranslucentBackground);
KWindowSystem::setOnAllDesktops(winId(), true);
KWindowSystem::setType(winId(), NET::Dock);
m_svg->setImagePath("widgets/glowbar");
QPalette pal = palette();
pal.setColor(backgroundRole(), Qt::transparent);
setPalette(pal);
#ifdef Q_WS_X11
QRegion region(QRect(0,0,1,1));
XShapeCombineRegion(QX11Info::display(), winId(), ShapeInput, 0, 0,
region.handle(), ShapeSet);
#endif
QRect glowGeom = triggerZone;
QSize s = sizeHint();
switch (m_direction) {
case Plasma::Up:
glowGeom.setY(glowGeom.y() - s.height() + 1);
// fallthrough
case Plasma::Down:
glowGeom.setHeight(s.height());
break;
case Plasma::Left:
glowGeom.setX(glowGeom.x() - s.width() + 1);
// fallthrough
case Plasma::Right:
glowGeom.setWidth(s.width());
break;
}
//kDebug() << "glow geom is" << glowGeom << "from" << triggerZone;
setGeometry(glowGeom);
m_buffer = QPixmap(size());
}
void paintEvent(QPaintEvent* e)
{
Q_UNUSED(e)
QPixmap l, r, c;
const QSize glowRadius = m_svg->elementSize("hint-glow-radius");
QPoint pixmapPosition(0, 0);
m_buffer.fill(QColor(0, 0, 0, int(qreal(255)*m_strength)));
QPainter p(&m_buffer);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
switch (m_direction) {
case Plasma::Down:
l = m_svg->pixmap("bottomleft");
r = m_svg->pixmap("bottomright");
c = m_svg->pixmap("bottom");
pixmapPosition = QPoint(0, -glowRadius.height());
break;
case Plasma::Up:
l = m_svg->pixmap("topleft");
r = m_svg->pixmap("topright");
c = m_svg->pixmap("top");
break;
case Plasma::Right:
l = m_svg->pixmap("topright");
r = m_svg->pixmap("bottomright");
c = m_svg->pixmap("right");
pixmapPosition = QPoint(-glowRadius.width(), 0);
break;
case Plasma::Left:
l = m_svg->pixmap("topleft");
r = m_svg->pixmap("bottomleft");
c = m_svg->pixmap("left");
break;
}
if (m_direction == Plasma::Left || m_direction == Plasma::Right) {
p.drawPixmap(pixmapPosition, l);
p.drawTiledPixmap(QRect(pixmapPosition.x(), l.height(), c.width(), height() - l.height() - r.height()), c);
p.drawPixmap(QPoint(pixmapPosition.x(), height() - r.height()), r);
} else {
p.drawPixmap(pixmapPosition, l);
p.drawTiledPixmap(QRect(l.width(), pixmapPosition.y(), width() - l.width() - r.width(), c.height()), c);
p.drawPixmap(QPoint(width() - r.width(), pixmapPosition.y()), r);
}
p.end();
p.begin(this);
p.drawPixmap(QPoint(0, 0), m_buffer);
}
QSize sizeHint() const
{
return m_svg->elementSize("bottomright") - m_svg->elementSize("hint-glow-radius");
}
void updateStrength(QPoint point)
{
QPoint localPoint = mapFromGlobal(point);
qreal newStrength;
switch (m_direction) {
case Plasma::Up: // when the panel is at the bottom.
newStrength = 1 - qreal(-localPoint.y())/m_triggerDistance;
break;
case Plasma::Right:
newStrength = 1 - qreal(localPoint.x())/m_triggerDistance;
break;
case Plasma::Left: // when the panel is right-aligned
newStrength = 1 - qreal(-localPoint.x())/m_triggerDistance;
break;
case Plasma::Down:
default:
newStrength = 1- qreal(localPoint.y())/m_triggerDistance;
break;
}
if (qAbs(newStrength - m_strength) > 0.01 && newStrength >= 0 && newStrength <= 1) {
m_strength = newStrength;
update();
}
}
private:
static const int m_triggerDistance = 30;
qreal m_strength;
Plasma::Svg *m_svg;
Plasma::Direction m_direction;
QPixmap m_buffer;
};
PanelView::PanelView(Plasma::Containment *panel, int id, QWidget *parent)
: Plasma::View(panel, id, parent),
m_panelController(0),
m_glowBar(0),
m_mousePollTimer(0),
m_strutsTimer(new QTimer(this)),
m_rehideAfterAutounhideTimer(new QTimer(this)),
m_spacer(0),
m_spacerIndex(-1),
#ifdef Q_WS_X11
m_unhideTrigger(None),
#endif
m_visibilityMode(NormalPanel),
m_lastHorizontal(true),
m_editing(false),
m_triggerEntered(false),
m_respectStatus(true)
{
setAttribute(Qt::WA_TranslucentBackground);
PlasmaApp::self()->panelShadows()->addWindow(this);
// KWin setup
KWindowSystem::setOnAllDesktops(winId(), true);
KWindowSystem::setType(winId(), NET::Dock);
setWindowRole(QString("panel_%1").arg(id));
m_strutsTimer->setSingleShot(true);
connect(m_strutsTimer, SIGNAL(timeout()), this, SLOT(updateStruts()));
// this timer controls checks to re-hide a panel after it's been unhidden
// for the user because, e.g., something is demanding attention
m_rehideAfterAutounhideTimer->setSingleShot(true);
connect(m_rehideAfterAutounhideTimer, SIGNAL(timeout()), this, SLOT(checkAutounhide()));
// Graphics view setup
setFrameStyle(QFrame::NoFrame);
setInteractive(true);
setAcceptDrops(true);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QPalette pal = palette();
pal.setBrush(backgroundRole(), Qt::transparent);
setPalette(pal);
KConfigGroup viewConfig = config();
KConfigGroup sizes = KConfigGroup(&viewConfig, "Sizes");
m_lastHorizontal = isHorizontal();
const bool onScreen = panel->screen() < PlasmaApp::self()->corona()->numScreens();
const QRect screenRect = onScreen ? PlasmaApp::self()->corona()->screenGeometry(panel->screen()) : QRect();
const int sw = screenRect.width();
const int sh = screenRect.height();
m_lastSeenSize = sizes.readEntry("lastsize", m_lastHorizontal ? sw : sh);
if (onScreen) {
const QString last = m_lastHorizontal ? QString::fromLatin1("Horizontal%1").arg(QString::number(sw)) :
QString::fromLatin1("Vertical%1").arg(QString::number(sh));
if (sizes.hasGroup(last)) {
KConfigGroup thisSize(&sizes, last);
resize(thisSize.readEntry("size", m_lastHorizontal ? QSize(sw, 27) : QSize(27, sh)));
}
} else {
resize(panel->size().toSize());
}
m_alignment = alignmentFilter((Qt::Alignment)viewConfig.readEntry("Alignment", (int)Qt::AlignLeft));
KConfigGroup sizeConfig(&viewConfig, (m_lastHorizontal ? "Horizontal" : "Vertical") +
QString::number(m_lastSeenSize));
m_offset = sizeConfig.readEntry("offset", 0);
setVisibilityMode((VisibilityMode)viewConfig.readEntry("panelVisibility", (int)m_visibilityMode));
connect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
Kephal::Screens *screens = Kephal::Screens::self();
connect(screens, SIGNAL(screenResized(Kephal::Screen*,QSize,QSize)),
this, SLOT(pinchContainmentToCurrentScreen()));
connect(screens, SIGNAL(screenMoved(Kephal::Screen*,QPoint,QPoint)),
this, SLOT(updatePanelGeometry()));
connect(screens, SIGNAL(screenAdded(Kephal::Screen*)),
this, SLOT(updateStruts()));
connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeChanged()), Qt::QueuedConnection);
}
PanelView::~PanelView()
{
if (m_panelController) {
disconnect(m_panelController, 0, this, 0);
delete m_panelController;
}
delete m_glowBar;
destroyUnhideTrigger();
}
void PanelView::setContainment(Plasma::Containment *containment)
{
kDebug() << "Panel geometry is" << containment->geometry();
Plasma::Containment *oldContainment = this->containment();
if (oldContainment) {
disconnect(oldContainment);
}
PlasmaApp::self()->prepareContainment(containment);
connect(containment, SIGNAL(newStatus(Plasma::ItemStatus)), this, SLOT(statusUpdated(Plasma::ItemStatus)));
connect(containment, SIGNAL(destroyed(QObject*)), this, SLOT(panelDeleted()));
connect(containment, SIGNAL(toolBoxToggled()), this, SLOT(togglePanelController()));
connect(containment, SIGNAL(appletAdded(Plasma::Applet*,QPointF)), this, SLOT(appletAdded(Plasma::Applet*)));
connect(containment, SIGNAL(showAddWidgetsInterface(QPointF)), this, SLOT(showWidgetExplorer()));
connect(containment, SIGNAL(screenChanged(int,int,Plasma::Containment*)), this, SLOT(pinchContainmentToCurrentScreen()));
connect(containment, SIGNAL(immutabilityChanged(Plasma::ImmutabilityType)), this, SLOT(immutabilityChanged(Plasma::ImmutabilityType)));
KConfigGroup viewIds(KGlobal::config(), "ViewIds");
if (oldContainment) {
viewIds.deleteEntry(QString::number(oldContainment->id()));
}
if (containment) {
viewIds.writeEntry(QString::number(containment->id()), id());
if (containment->corona()) {
containment->corona()->requestConfigSync();
}
}
// ensure we aren't overlapping other panels
const QRect screenRect = PlasmaApp::self()->corona()->screenGeometry(containment->screen());
View::setContainment(containment);
// pinchContainment calls updatePanelGeometry for us
pinchContainment(screenRect);
m_lastMin = containment->minimumSize();
m_lastMax = containment->maximumSize();
kDebug() << "about to set the containment" << (QObject*)containment;
updateStruts();
// if we are an autohiding panel, then see if the status mandates we do something about it
if (m_visibilityMode != NormalPanel && m_visibilityMode != WindowsGoBelow) {
checkUnhide(containment->status());
}
// disable removing widgets from the context menu
containment->setProperty("hideCloseAppletInContextMenu", true);
}
void PanelView::themeChanged()
{
recreateUnhideTrigger();
}
void PanelView::setPanelDragPosition(const QPoint &point)
{
QRect screenGeom = PlasmaApp::self()->corona()->screenGeometry(containment()->screen());
QRect geom = geometry();
geom.translate(-point);
if (screenGeom.contains(geom)) {
move(pos() - point);
if (m_panelController) {
m_panelController->move(m_panelController->pos() - point);
}
}
}
void PanelView::setLocation(Plasma::Location location)
{
Plasma::Containment *c = containment();
QSizeF s = c->size();
QSizeF min = c->minimumSize();
QSizeF max = c->maximumSize();
qreal panelWidth = s.width();
qreal panelHeight = s.height();
Plasma::FormFactor formFactor = c->formFactor();
bool wasHorizontal = formFactor == Plasma::Horizontal;
bool wasFullSize = m_lastSeenSize == (wasHorizontal ? s.width() : s.height());
if (location == Plasma::TopEdge || location == Plasma::BottomEdge) {
if (!wasHorizontal) {
// we're switching! swap the sizes about
panelHeight = s.width();
if (wasFullSize) {
QRect screenGeom = PlasmaApp::self()->corona()->screenGeometry(c->screen());
panelWidth = screenGeom.width();
} else {
panelWidth = s.height();
}
min = QSizeF(panelWidth, min.width());
max = QSizeF(panelWidth, max.width());
}
formFactor = Plasma::Horizontal;
} else {
if (wasHorizontal) {
// we're switching! swap the sizes about
if (wasFullSize) {
QRect screenGeom = PlasmaApp::self()->corona()->screenGeometry(c->screen());
panelHeight = screenGeom.height();
} else {
panelHeight = s.width();
}
panelWidth = s.height();
min = QSizeF(min.height(), panelHeight);
max = QSizeF(max.height(), panelHeight);
}
formFactor = Plasma::Vertical;
}
//kDebug() << "!!!!!!!!!!!!!!!!!! about to set to" << location << panelHeight << formFactor;
disconnect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
c->setFormFactor(formFactor);
c->setLocation(location);
c->setMinimumSize(0, 0);
c->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
c->resize(panelWidth, panelHeight);
c->setMinimumSize(min);
c->setMaximumSize(max);
const QRect screenRect = PlasmaApp::self()->corona()->screenGeometry(c->screen());
pinchContainment(screenRect);
KWindowSystem::setOnAllDesktops(winId(), true);
connect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
}
Plasma::Location PanelView::location() const
{
if (containment()) {
return containment()->location();
} else {
return Plasma::BottomEdge;
}
}
void PanelView::setVisibilityMode(PanelView::VisibilityMode mode)
{
m_visibilityMode = mode;
if (mode == LetWindowsCover) {
KWindowSystem::setState(winId(), NET::KeepBelow);
} else {
KWindowSystem::clearState(winId(), NET::KeepBelow);
}
//life is vastly simpler if we ensure we're visible now
unhide();
disconnect(containment(), SIGNAL(activate()), this, SLOT(unhide()));
disconnect(containment(), SIGNAL(newStatus(Plasma::ItemStatus)), this, SLOT(checkUnhide(Plasma::ItemStatus)));
if (mode == NormalPanel || mode == WindowsGoBelow) {
//remove the last remnants of hide/unhide
delete m_mousePollTimer;
m_mousePollTimer = 0;
} else {
connect(containment(), SIGNAL(activate()), this, SLOT(unhide()));
connect(containment(), SIGNAL(newStatus(Plasma::ItemStatus)), this, SLOT(checkUnhide(Plasma::ItemStatus)));
}
config().writeEntry("panelVisibility", (int)mode);
//if the user didn't cause this, hide again in a bit
if (!m_editing) {
updateStruts();
if (mode == AutoHide || mode == LetWindowsCover) {
if (m_mousePollTimer) {
m_mousePollTimer->stop();
}
QTimer::singleShot(2000, this, SLOT(startAutoHide()));
}
}
KWindowSystem::setOnAllDesktops(winId(), true);
}
PanelView::VisibilityMode PanelView::visibilityMode() const
{
return m_visibilityMode;
}
void PanelView::updatePanelGeometry()
{
Plasma::Containment *c = containment();
if (!c) {
return;
}
kDebug() << "New panel geometry is" << c->geometry();
QSize size = c->size().expandedTo(c->minimumSize()).toSize();
QRect geom(QPoint(0,0), size);
int screen = c->screen();
if (screen < 0) {
//TODO: is there a valid use for -1 with a panel? floating maybe?
screen = 0;
}
QRect screenGeom = PlasmaApp::self()->corona()->screenGeometry(screen);
if (m_alignment != Qt::AlignCenter) {
m_offset = qMax(m_offset, 0);
}
//Sanity controls
switch (location()) {
case Plasma::TopEdge:
case Plasma::BottomEdge:
//resize the panel if is too large
if (geom.width() > screenGeom.width()) {
geom.setWidth(screenGeom.width());
}
//move the panel left/right if there is not enough room
if (m_alignment == Qt::AlignLeft) {
if (m_offset + geom.width() > screenGeom.width() + 1) {
m_offset = screenGeom.width() - geom.width();
}
} else if (m_alignment == Qt::AlignRight) {
if (screenGeom.width() - m_offset - geom.width() < -1 ) {
m_offset = screenGeom.width() - geom.width();
}
} else if (m_alignment == Qt::AlignCenter) {
if (screenGeom.center().x() - screenGeom.x() + m_offset + geom.width()/2 > screenGeom.width() + 1) {
m_offset = screenGeom.width() - geom.width()/2 - (screenGeom.center().x() - screenGeom.x());
} else if (screenGeom.center().x() - screenGeom.x() + m_offset - geom.width()/2 < -1) {
m_offset = (screenGeom.center().x() - screenGeom.x()) - geom.width()/2;
}
}
break;
case Plasma::LeftEdge:
case Plasma::RightEdge:
//resize the panel if is too tall
if (geom.height() > screenGeom.height()) {
geom.setHeight(screenGeom.height());
}
//move the panel bottom if there is not enough room
//FIXME: still using alignleft/alignright is simpler and less error prone, but aligntop/alignbottom is more correct?
if (m_alignment == Qt::AlignLeft) {
if (m_offset + geom.height() > screenGeom.height() + 1) {
m_offset = screenGeom.height() - geom.height();
}
} else if (m_alignment == Qt::AlignRight) {
if (screenGeom.height() - m_offset - geom.height() < -1) {
m_offset = screenGeom.height() - geom.height();
}
} else if (m_alignment == Qt::AlignCenter) {
if (screenGeom.center().y() - screenGeom.top() + m_offset + geom.height()/2 > screenGeom.height() + 1) {
m_offset = screenGeom.height() - geom.height()/2 - (screenGeom.center().y() - screenGeom.top());
} else if (screenGeom.center().y() - screenGeom.top() + m_offset - geom.height()/2 < -1) {
m_offset = (screenGeom.center().y() - screenGeom.top()) - geom.width()/2;
}
}
break;
//TODO: floating panels (probably they will save their own geometry)
default:
break;
}
//Actual movement
switch (location()) {
case Plasma::TopEdge:
if (m_alignment == Qt::AlignLeft) {
geom.moveTopLeft(QPoint(m_offset + screenGeom.left(), screenGeom.top()));
} else if (m_alignment == Qt::AlignRight) {
geom.moveTopRight(QPoint(screenGeom.right() - m_offset, screenGeom.top()));
} else if (m_alignment == Qt::AlignCenter) {
geom.moveTopLeft(QPoint(screenGeom.center().x() - geom.width()/2 + 1 - geom.width()%2 + m_offset, screenGeom.top()));
}
break;
case Plasma::LeftEdge:
if (m_alignment == Qt::AlignLeft) {
geom.moveTopLeft(QPoint(screenGeom.left(), m_offset + screenGeom.top()));
} else if (m_alignment == Qt::AlignRight) {
geom.moveBottomLeft(QPoint(screenGeom.left(), screenGeom.bottom() - m_offset));
} else if (m_alignment == Qt::AlignCenter) {
geom.moveTopLeft(QPoint(screenGeom.left(), screenGeom.center().y() - geom.height()/2 + 1 - geom.height()%2 + m_offset));
}
break;
case Plasma::RightEdge:
if (m_alignment == Qt::AlignLeft) {
geom.moveTopRight(QPoint(screenGeom.right(), m_offset + screenGeom.top()));
} else if (m_alignment == Qt::AlignRight) {
geom.moveBottomRight(QPoint(screenGeom.right(), screenGeom.bottom() - m_offset));
} else if (m_alignment == Qt::AlignCenter) {
geom.moveTopRight(QPoint(screenGeom.right(), screenGeom.center().y() - geom.height()/2 + 1 - geom.height()%2 + m_offset));
}
break;
case Plasma::BottomEdge:
default:
if (m_alignment == Qt::AlignLeft) {
geom.moveBottomLeft(QPoint(m_offset + screenGeom.left(), screenGeom.bottom()));
} else if (m_alignment == Qt::AlignRight) {
geom.moveBottomRight(QPoint(screenGeom.right() - m_offset, screenGeom.bottom()));
} else if (m_alignment == Qt::AlignCenter) {
geom.moveBottomLeft(QPoint(screenGeom.center().x() - geom.width()/2 + 1 - geom.width()%2 + m_offset, screenGeom.bottom()));
}
break;
}
kDebug() << (QObject*)this << "thinks its panel is at " << geom << "was" << geometry();
if (geom == geometry()) {
// our geometry is the same, but the panel moved around
// so make sure our struts are still valid
m_strutsTimer->stop();
m_strutsTimer->start(STRUTSTIMERDELAY);
// this is probably papering over some real bug, but it fixes bug 283974
setGeometry(geom);
} else {
if (m_panelController && QPoint(pos() - geom.topLeft()).manhattanLength() > 100) {
resize(geom.size());
QPropertyAnimation *panelAnimation = new QPropertyAnimation(this, "pos", this);
panelAnimation->setEasingCurve(QEasingCurve::InOutQuad);
panelAnimation->setDuration(300);
panelAnimation->setStartValue(pos());
panelAnimation->setEndValue(geom.topLeft());
panelAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPropertyAnimation *controllerAnimation = new QPropertyAnimation(m_panelController, "pos", m_panelController);
controllerAnimation->setEasingCurve(QEasingCurve::InOutQuad);
controllerAnimation->setDuration(300);
controllerAnimation->setStartValue(m_panelController->pos());
controllerAnimation->setEndValue(m_panelController->positionForPanelGeometry(geom));
controllerAnimation->start(QAbstractAnimation::DeleteWhenStopped);
} else {
setGeometry(geom);
}
}
m_lastMin = c->minimumSize();
m_lastMax = c->maximumSize();
//update the panel controller location position and size
if (m_panelController) {
m_panelController->setLocation(c->location());
foreach (PanelAppletOverlay *o, m_appletOverlays) {
o->syncOrientation();
}
}
recreateUnhideTrigger();
}
bool PanelView::isHorizontal() const
{
return location() == Plasma::BottomEdge ||
location() == Plasma::TopEdge;
}
void PanelView::pinchContainmentToCurrentScreen()
{
kDebug() << "pinching to current screen";
const QRect screenRect = PlasmaApp::self()->corona()->screenGeometry(containment()->screen());
pinchContainment(screenRect);
}
void PanelView::pinchContainment(const QRect &screenGeom)
{
kDebug() << "**************************** pinching" << screenGeom << m_lastSeenSize;
disconnect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
bool horizontal = isHorizontal();
const int oldOffset = m_offset;
const int sw = screenGeom.width();
const int sh = screenGeom.height();
Plasma::Containment *c = containment();
QSizeF min = c->minimumSize();
QSizeF max = c->maximumSize();
KConfigGroup sizes = config();
sizes = KConfigGroup(&sizes, "Sizes");
if (m_lastHorizontal != horizontal || m_lastSeenSize != (horizontal ? sw : sh)) {
// we're adjusting size. store the current size now
KConfigGroup lastSize(&sizes, (m_lastHorizontal ? "Horizontal" : "Vertical") +
QString::number(m_lastSeenSize));
lastSize.writeEntry("size", size());
lastSize.writeEntry("offset", m_offset);
lastSize.writeEntry("min", m_lastMin);
lastSize.writeEntry("max", m_lastMax);
configNeedsSaving();
const QString last = horizontal ? QString::fromLatin1("Horizontal%1").arg(QString::number(sw)) :
QString::fromLatin1("Vertical%1").arg(QString::number(sh));
if (sizes.hasGroup(last)) {
KConfigGroup thisSize(&sizes, last);
/*
kDebug() << "has saved properties..." << last
<< thisSize.readEntry("min", min)
<< thisSize.readEntry("max", max)
<< thisSize.readEntry("size", c->geometry().size())
<< thisSize.readEntry("offset", 0);
*/
c->setMinimumSize(0, 0);
c->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
c->resize(thisSize.readEntry("size", c->geometry().size()));
c->setMinimumSize(thisSize.readEntry("min", min));
c->setMaximumSize(thisSize.readEntry("max", max));
m_offset = thisSize.readEntry("offset", 0);
}
if (m_lastSeenSize < (horizontal ? sw : sh) &&
(horizontal ? c->geometry().width() :
c->geometry().height()) >= m_lastSeenSize) {
// we are moving from a smaller space where we are 100% to a larger one
kDebug() << "we are moving from a smaller space where we are 100% to a larger one";
c->setMinimumSize(0, 0);
c->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
if (horizontal) {
c->setMaximumSize(sw, max.height());
c->resize(sw, c->geometry().height());
if (min.width() == max.width()) {
c->setMinimumSize(sw, min.height());
}
} else {
c->setMaximumSize(max.width(), sh);
c->resize(c->geometry().width(), sh);
if (min.height() == max.height()) {
c->setMinimumSize(min.width(), sh);
}
}
} else if (m_lastSeenSize > (horizontal ? sw : sh) &&
(m_offset + (horizontal ? c->geometry().width() :
c->geometry().height())) > (horizontal ? sw : sh)) {
kDebug() << "we are moving from a bigger space to a smaller one where the panel won't fit!!";
if ((horizontal ? c->geometry().width() :
c->geometry().height()) > (horizontal ? sw : sh)) {
kDebug() << "panel is larger than screen, adjusting panel size";
setOffset(0);
c->setMinimumSize(0, 0);
c->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
if (horizontal) {
c->setMaximumSize(sw, max.height());
c->resize(sw, c->geometry().height());
if (min.width() == max.width()) {
c->setMinimumSize(sw, min.height());
}
} else {
c->setMaximumSize(max.width(), sh);
c->resize(c->geometry().width(), sh);
if (min.height() == max.height()) {
c->setMinimumSize(min.width(), sh);
}
}
} else {
kDebug() << "reducing offset so the panel fits in screen";
setOffset((horizontal ? sw : sh) -
(horizontal ? c->geometry().width() : c->geometry().height()));
}
}
}
// Pinching strategy:
// if our containment is too big for the size of the screen we are now on,
// then we first try and limit the offset and then if that still doesn't
// give us enough room, we limit the size of the panel itself by setting
// the minimum and maximum sizes.
//kDebug() << "checking panel" << c->geometry() << "against" << screenGeom;
// resize to max if for some reason the size is empty
// otherwise its not possible to interact with the panel at all
if (c->size().isEmpty()) {
c->resize(max);
}
// write to the config file if the size has changed, or if we haven't recorded the lastsize
// previously which ensures we'll always have a value even after first run
const bool writeConfig = m_lastSeenSize != (horizontal ? sw : sh) || !sizes.hasKey("lastsize");
m_lastHorizontal = horizontal;
m_lastSeenSize = (horizontal ? sw : sh);
if (writeConfig) {
sizes.writeEntry("lastsize", m_lastSeenSize);
configNeedsSaving();
}
updatePanelGeometry();
if (m_offset != oldOffset) {
sizes.writeEntry("offset", m_lastSeenSize);
configNeedsSaving();
}
if (m_panelController) {
m_panelController->setOffset(m_offset);
}
connect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(pinchContainmentToCurrentScreen()));
recreateUnhideTrigger();
kDebug() << "Done pinching, containment's geom" << c->geometry() << "own geom" << geometry();
}
void PanelView::setOffset(int newOffset)
{
m_offset = newOffset;
//TODO: do we ever need to worry about pinching here, or
// do we just assume that the offset is always < screenSize - containmentSize?
updatePanelGeometry();
KConfigGroup viewConfig = config();
viewConfig = KConfigGroup(&viewConfig, (m_lastHorizontal ? "Horizontal" : "Vertical") +
QString::number(m_lastSeenSize));
viewConfig.writeEntry("offset", m_offset);
configNeedsSaving();
}
int PanelView::offset() const
{
return m_offset;
}
void PanelView::setAlignment(Qt::Alignment align)
{
m_alignment = alignmentFilter(align);
KConfigGroup viewConfig = config();
viewConfig.writeEntry("Alignment", (int)m_alignment);
configNeedsSaving();
}
Qt::Alignment PanelView::alignment() const
{
return m_alignment;
}
void PanelView::immutabilityChanged(Plasma::ImmutabilityType immutability)
{
if (immutability != Plasma::Mutable) {
delete m_panelController;
m_panelController = 0;
}
}
void PanelView::togglePanelController()
{
//kDebug();
m_editing = false;
if (containment()->immutability() != Plasma::Mutable) {
delete m_panelController;
m_panelController = 0;
return;
}
if (!m_panelController) {
m_panelController = new PanelController(0);
m_panelController->setContainment(containment());
m_panelController->setLocation(containment()->location());
m_panelController->setAlignment(m_alignment);
m_panelController->setOffset(m_offset);
m_panelController->setVisibilityMode(m_visibilityMode);
connect(m_panelController, SIGNAL(destroyed(QObject*)), this, SLOT(editingComplete()));
connect(m_panelController, SIGNAL(offsetChanged(int)), this, SLOT(setOffset(int)));
connect(m_panelController, SIGNAL(partialMove(QPoint)), this, SLOT(setPanelDragPosition(QPoint)));
connect(m_panelController, SIGNAL(alignmentChanged(Qt::Alignment)), this, SLOT(setAlignment(Qt::Alignment)));
connect(m_panelController, SIGNAL(locationChanged(Plasma::Location)), this, SLOT(setLocation(Plasma::Location)));
connect(m_panelController, SIGNAL(panelVisibilityModeChanged(PanelView::VisibilityMode)), this, SLOT(setVisibilityMode(PanelView::VisibilityMode)));
if (containment()->containmentType() == Plasma::Containment::PanelContainment &&
dynamic_cast<QGraphicsLinearLayout*>(containment()->layout())) {
setTabOrder(0, m_panelController);
QWidget *prior = m_panelController;
// we only support mouse over drags for panels with linear layouts
QColor overlayColor(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor));
QBrush overlayBrush(overlayColor);
QPalette p(palette());
p.setBrush(QPalette::Window, overlayBrush);
foreach (Plasma::Applet *applet, containment()->applets()) {
PanelAppletOverlay *moveOverlay = new PanelAppletOverlay(applet, this);
connect(moveOverlay, SIGNAL(removedWithApplet(PanelAppletOverlay*)),
this, SLOT(overlayDestroyed(PanelAppletOverlay*)));
connect(moveOverlay, SIGNAL(moved(PanelAppletOverlay*)),
this, SLOT(overlayMoved(PanelAppletOverlay*)));
moveOverlay->setPalette(p);
moveOverlay->show();
moveOverlay->raise();
m_appletOverlays << moveOverlay;
//kDebug() << moveOverlay << moveOverlay->geometry();
setTabOrder(prior, moveOverlay);
prior = moveOverlay;
}
}
}
if (m_panelController->isVisible()) {
if (m_panelController->showingWidgetExplorer() ||
m_panelController->showingActivityManager()) {
m_panelController->switchToController();
m_panelController->move(m_panelController->positionForPanelGeometry(geometry()));
} else {
Plasma::WindowEffects::slideWindow(m_panelController, location());
m_panelController->close();
updateStruts();
}
} else {
m_editing = true;
m_panelController->resize(m_panelController->sizeHint());
m_panelController->move(m_panelController->positionForPanelGeometry(geometry()));
Plasma::WindowEffects::slideWindow(m_panelController, location());
kDebug() << "showing panel controller!" << m_panelController->geometry();
m_panelController->show();
}
containment()->setProperty("hideCloseAppletInContextMenu", false);
}
void PanelView::editingComplete()
{
//kDebug();
m_panelController = 0;
m_editing = false;
qDeleteAll(m_appletOverlays);
m_appletOverlays.clear();
if (!containment()) {
return;
}
containment()->closeToolBox();
containment()->setProperty("hideCloseAppletInContextMenu", true);
updateStruts();
if (m_visibilityMode == LetWindowsCover || m_visibilityMode == AutoHide) {
startAutoHide();
}
}
void PanelView::overlayDestroyed(PanelAppletOverlay *overlay)
{
m_appletOverlays.remove(overlay);
}
void PanelView::overlayMoved(PanelAppletOverlay *overlay)
{
Q_UNUSED(overlay)
foreach (PanelAppletOverlay *o, m_appletOverlays) {
o->syncIndex();
}
}
Qt::Alignment PanelView::alignmentFilter(Qt::Alignment align) const
{
//If it's not a supported alignment default to Qt::AlignLeft
if (align == Qt::AlignLeft || align == Qt::AlignRight || align == Qt::AlignCenter) {
return align;
} else {
return Qt::AlignLeft;
}
}
void PanelView::updateStruts()
{
if (!containment()) {
return;
}
NETExtendedStrut strut;
if (m_visibilityMode == NormalPanel) {
const QRect thisScreen = PlasmaApp::self()->corona()->screenGeometry(containment()->screen());
const QRect wholeScreen = Kephal::ScreenUtils::desktopGeometry();
//Extended struts against a screen edge near to another screen are really harmful, so windows maximized under the panel is a lesser pain
//TODO: force "windows can cover" in those cases?
const int numScreens = PlasmaApp::self()->corona()->numScreens();
for (int i = 0; i < numScreens; ++i) {
if (i == containment()->screen()) {
continue;
}
const QRect otherScreen = PlasmaApp::self()->corona()->screenGeometry(i);
switch (location())
{
case Plasma::TopEdge:
if (otherScreen.bottom() <= thisScreen.top()) {
KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
return;
}
break;
case Plasma::BottomEdge:
if (otherScreen.top() >= thisScreen.bottom()) {
KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
return;
}
break;
case Plasma::RightEdge:
if (otherScreen.left() >= thisScreen.right()) {
KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
return;
}
break;
case Plasma::LeftEdge:
if (otherScreen.right() <= thisScreen.left()) {
KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
return;
}
break;
default:
return;
}
}
// extended struts are to the combined screen geoms, not the single screen
int leftOffset = wholeScreen.x() - thisScreen.x();
int rightOffset = wholeScreen.right() - thisScreen.right();
int bottomOffset = wholeScreen.bottom() - thisScreen.bottom();
int topOffset = wholeScreen.top() - thisScreen.top();
kDebug() << "screen l/r/b/t offsets are:" << leftOffset << rightOffset << bottomOffset << topOffset << location();
switch (location())
{
case Plasma::TopEdge:
strut.top_width = height() + topOffset;
strut.top_start = x();
strut.top_end = x() + width() - 1;
break;
case Plasma::BottomEdge:
strut.bottom_width = height() + bottomOffset;
strut.bottom_start = x();
strut.bottom_end = x() + width() - 1;
//kDebug() << "setting bottom edge to" << strut.bottom_width
// << strut.bottom_start << strut.bottom_end;
break;
case Plasma::RightEdge:
strut.right_width = width() + rightOffset;
strut.right_start = y();
strut.right_end = y() + height() - 1;
break;
case Plasma::LeftEdge:
strut.left_width = width() + leftOffset;
strut.left_start = y();
strut.left_end = y() + height() - 1;
break;
default:
//kDebug() << "where are we?";
break;
}
}
KWindowSystem::setExtendedStrut(winId(), strut.left_width,
strut.left_start,
strut.left_end,
strut.right_width,
strut.right_start,
strut.right_end,
strut.top_width,
strut.top_start,
strut.top_end,
strut.bottom_width,
strut.bottom_start,
strut.bottom_end);
if (m_panelController) {
m_panelController->setLocation(containment()->location());
if (m_panelController->isVisible()) {
m_panelController->resize(m_panelController->sizeHint());
m_panelController->move(m_panelController->positionForPanelGeometry(geometry()));
Plasma::WindowEffects::slideWindow(m_panelController, location());
}
foreach (PanelAppletOverlay *o, m_appletOverlays) {
o->syncOrientation();
}
}
recreateUnhideTrigger();
}
bool PanelView:: migratedFrom(int screenId) const
{
KConfigGroup cg = config();
const QList<int> migrations = cg.readEntry("Migrations", QList<int>());
return migrations.contains(screenId);
}
void PanelView::migrateTo(int screenId)
{
KConfigGroup cg = config();
QList<int> migrations = cg.readEntry("Migrations", QList<int>());
const int index = migrations.indexOf(screenId);
if (index == -1) {
migrations.append(screenId);
} else {
migrations = migrations.mid(0, migrations.length() - index - 1);
}
cg.writeEntry("Migrations", migrations);
setScreen(screenId);
}
void PanelView::showWidgetExplorer()
{
if (!containment()) {
return;
}
if (!m_panelController) {
m_editing = true;
ControllerWindow *controller = PlasmaApp::self()->showWidgetExplorer(screen(), containment());
connect(controller, SIGNAL(destroyed(QObject*)), this, SLOT(editingComplete()), Qt::UniqueConnection);
} else {
m_panelController->showWidgetExplorer();
}
containment()->setProperty("hideCloseAppletInContextMenu", false);
}
void PanelView::moveEvent(QMoveEvent *event)
{
Plasma::View::moveEvent(event);
m_strutsTimer->stop();
m_strutsTimer->start(STRUTSTIMERDELAY);
recreateUnhideTrigger();
if (containment()) {
foreach (Plasma::Applet *applet, containment()->applets()) {
applet->updateConstraints(Plasma::PopupConstraint);
}
}
}
void PanelView::resizeEvent(QResizeEvent *event)
{
//kDebug() << event->oldSize() << event->size();
Plasma::View::resizeEvent(event);
recreateUnhideTrigger();
m_strutsTimer->stop();
m_strutsTimer->start(STRUTSTIMERDELAY);
if (containment()) {
foreach (Plasma::Applet *applet, containment()->applets()) {
applet->updateConstraints(Plasma::PopupConstraint);
}
}
}
void PanelView::updateHinter()
{
#ifdef Q_WS_X11
QPoint mousePos = QCursor::pos();
m_glowBar->updateStrength(mousePos);
if (!m_unhideTriggerGeom.contains(mousePos)) {
hideHinter();
XMoveResizeWindow(QX11Info::display(), m_unhideTrigger, m_unhideTriggerGeom.x(), m_unhideTriggerGeom.y(), m_unhideTriggerGeom.width(), m_unhideTriggerGeom.height());
}
#endif
}
QRect PanelView::unhideHintGeometry() const
{
#ifdef Q_WS_X11
return m_unhideTriggerGeom;
#else
return QRect();
#endif
}
bool PanelView::hintOrUnhide(const QPoint &point, bool dueToDnd)
{
#ifdef Q_WS_X11
if (m_visibilityMode != LetWindowsCover && isVisible()) {
return false;
}
KWindowInfo activeWindow = KWindowSystem::windowInfo(KWindowSystem::activeWindow(), NET::WMState);
if (activeWindow.state() & NET::FullScreen) {
return false;
}
if (!shouldHintHide()) {
//kDebug() << "should not hint hide";
unhide(!dueToDnd);
return true;
}
//kDebug() << point << m_triggerZone;
if (m_triggerZone.contains(point)) {
//kDebug() << "unhide!" << point;
unhide(!dueToDnd);
return true;
} else if (!m_glowBar) {
Plasma::Direction direction = Plasma::locationToDirection(location());
m_glowBar = new GlowBar(direction, m_triggerZone);
m_glowBar->show();
XMoveResizeWindow(QX11Info::display(), m_unhideTrigger, m_triggerZone.x(), m_triggerZone.y(), m_triggerZone.width(), m_triggerZone.height());
//FIXME: This is ugly as hell but well, yeah
if (!m_mousePollTimer) {
m_mousePollTimer = new QTimer(this);
}
connect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(updateHinter()), Qt::UniqueConnection);
m_mousePollTimer->start(200);
}
return false;
#else
return false;
#endif
}
void PanelView::hideHinter()
{
//kDebug() << "hide the glow";
if (m_mousePollTimer) {
m_mousePollTimer->stop();
disconnect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(updateHinter()));
}
delete m_glowBar;
m_glowBar = 0;
}
bool PanelView::hasPopup()
{
if (QApplication::activePopupWidget() || m_panelController) {
return true;
}
if (containment()) {
foreach (Plasma::Applet *applet, containment()->applets()) {
if (applet->isPopupShowing()) {
return true;
}
}
}
return false;
}
void PanelView::unhide(bool destroyTrigger)
{
//kill the unhide stuff
hideHinter();
if (destroyTrigger) {
destroyUnhideTrigger();
}
//ensure it's visible
if (!isVisible()) {
Plasma::WindowEffects::slideWindow(this, location());
show();
KWindowSystem::raiseWindow(winId());
}
KWindowSystem::setOnAllDesktops(winId(), true);
//non-hiding panels stop here
if (m_visibilityMode == NormalPanel || m_visibilityMode == WindowsGoBelow) {
return;
}
//set up the re-hiding stuff
if (!m_mousePollTimer) {
m_mousePollTimer = new QTimer(this);
}
connect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(startAutoHide()), Qt::UniqueConnection);
m_mousePollTimer->start(500);
//avoid hide-show loops
if (m_visibilityMode == LetWindowsCover) {
m_triggerEntered = true;
KWindowSystem::clearState(winId(), NET::KeepBelow);
KWindowSystem::raiseWindow(winId());
QTimer::singleShot(0, this, SLOT(resetTriggerEnteredSuppression()));
}
}
void PanelView::statusUpdated(Plasma::ItemStatus newStatus)
{
if (newStatus == Plasma::AcceptingInputStatus) {
KWindowSystem::forceActiveWindow(winId());
}
}
void PanelView::checkUnhide(Plasma::ItemStatus newStatus)
{
//kDebug() << "================= got a status: " << newStatus << Plasma::ActiveStatus;
m_respectStatus = true;
if (newStatus > Plasma::ActiveStatus) {
unhide();
if (newStatus == Plasma::NeedsAttentionStatus) {
//kDebug() << "starting the timer!";
// start our rehide timer, so that the panel doesn't stay up and stuck forever and a day
m_rehideAfterAutounhideTimer->start(AUTOUNHIDE_CHECK_DELAY);
}
} else {
//kDebug() << "new status, just autohiding";
startAutoHide();
}
}
void PanelView::checkAutounhide()
{
//kDebug() << "***************************" << KIdleTime::instance()->idleTime();
if (KIdleTime::instance()->idleTime() >= AUTOUNHIDE_CHECK_DELAY) {
// the user is idle .. let's not hige the panel on them quite yet, but rather given them a
// chance to see this thing!
connect(KIdleTime::instance(), SIGNAL(resumingFromIdle()), this, SLOT(checkAutounhide()),
Qt::UniqueConnection);
KIdleTime::instance()->catchNextResumeEvent();
//kDebug() << "exit 1 ***************************";
return;
}
m_respectStatus = false;
//kDebug() << "in to check ... who's resonsible?" << sender() << KIdleTime::instance();
if (sender() == KIdleTime::instance()) {
//kDebug() << "doing a 2s wait";
QTimer::singleShot(2000, this, SLOT(startAutoHide()));
} else {
//kDebug() << "just starting autohide!";
startAutoHide();
}
// this line must come after the check on sender() as it *clears* that value!
disconnect(KIdleTime::instance(), SIGNAL(resumingFromIdle()), this, SLOT(checkAutounhide()));
//kDebug() << "exit 0 ***************************";
}
void PanelView::unhide()
{
unhide(true);
}
void PanelView::resetTriggerEnteredSuppression()
{
m_triggerEntered = false;
}
void PanelView::startAutoHide()
{
/*
kDebug() << m_editing << (containment() ? containment()->status() : 0) << Plasma::ActiveStatus
<< geometry().adjusted(-10, -10, 10, 10).contains(QCursor::pos()) << hasPopup();
if (containment() && containment()->status() > Plasma::ActiveStatus) {
foreach (Plasma::Applet *applet, containment()->applets()) {
kDebug() << " " << applet->name() << applet->status();
}
}
*/
if (m_editing || (m_respectStatus && (containment() && containment()->status() > Plasma::ActiveStatus))) {
if (m_mousePollTimer) {
m_mousePollTimer->stop();
disconnect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(startAutoHide()));
}
return;
}
// since we've gotten this far, we don't need to worry about rehiding-after-auto-unhide, so just
// stop the timer
m_rehideAfterAutounhideTimer->stop();
if (geometry().adjusted(-10, -10, 10, 10).contains(QCursor::pos()) || hasPopup()) {
if (!m_mousePollTimer) {
leaveEvent(0);
}
return;
}
if (m_mousePollTimer) {
m_mousePollTimer->stop();
disconnect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(startAutoHide()));
}
updatePanelGeometry();
if (m_visibilityMode == LetWindowsCover) {
KWindowSystem::setState(winId(), NET::KeepBelow);
KWindowSystem::lowerWindow(winId());
createUnhideTrigger();
} else {
Plasma::WindowEffects::slideWindow(this, location());
createUnhideTrigger();
hide();
}
}
void PanelView::leaveEvent(QEvent *event)
{
if (m_visibilityMode == LetWindowsCover && m_triggerEntered) {
//this prevents crazy hide-unhide loops that can happen at times
m_triggerEntered = false;
} else if (containment() &&
(m_visibilityMode == AutoHide || m_visibilityMode == LetWindowsCover) && !m_editing) {
// even if we dont have a popup, we'll start a timer, so
// that the panel stays if the mouse only leaves for a
// few ms
if (!m_mousePollTimer) {
m_mousePollTimer = new QTimer(this);
}
connect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(startAutoHide()), Qt::UniqueConnection);
m_mousePollTimer->start(500);
}
if (event) {
// startAutoHide calls this with a null event pointer, so we have to check it
Plasma::View::leaveEvent(event);
}
}
void PanelView::appletAdded(Plasma::Applet *applet)
{
if (m_panelController && containment()->containmentType() == Plasma::Containment::PanelContainment) {
QColor overlayColor(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor));
QBrush overlayBrush(overlayColor);
QPalette p(palette());
p.setBrush(QPalette::Window, overlayBrush);
PanelAppletOverlay *moveOverlay = new PanelAppletOverlay(applet, this);
connect(moveOverlay, SIGNAL(removedWithApplet(PanelAppletOverlay*)),
this, SLOT(overlayDestroyed(PanelAppletOverlay*)));
moveOverlay->setPalette(p);
moveOverlay->show();
moveOverlay->raise();
m_appletOverlays << moveOverlay;
QWidget *prior = m_panelController;
Plasma::Applet *priorApplet = 0;
foreach (Plasma::Applet *otherApplet, containment()->applets()) {
if (applet == otherApplet) {
break;
}
priorApplet = otherApplet;
}
if (priorApplet) {
foreach (PanelAppletOverlay *overlay, m_appletOverlays) {
if (overlay->applet() == priorApplet) {
prior = overlay;
break;
}
}
}
setTabOrder(prior, moveOverlay);
}
}
bool PanelView::shouldHintHide() const
{
return m_visibilityMode == AutoHide && PlasmaApp::hasComposite();
}
void PanelView::recreateUnhideTrigger()
{
#ifdef Q_WS_X11
if (m_unhideTrigger == None) {
return;
}
XDestroyWindow(QX11Info::display(), m_unhideTrigger);
m_unhideTrigger = None;
createUnhideTrigger();
#endif
}
void PanelView::createUnhideTrigger()
{
#ifdef Q_WS_X11
//kDebug() << m_unhideTrigger << None;
if (m_unhideTrigger != None) {
return;
}
bool fancy = shouldHintHide();
int actualWidth = 1;
int actualHeight = 1;
int triggerWidth = fancy ? 30 : 1;
int triggerHeight = fancy ? 30 : 1;
QPoint actualTriggerPoint = pos();
QPoint triggerPoint = pos();
switch (location()) {
case Plasma::TopEdge:
actualWidth = triggerWidth = width();
if (fancy) {
triggerWidth += 30;
triggerPoint.setX(qMax(0, triggerPoint.x() - 15));
}
break;
case Plasma::BottomEdge:
actualWidth = triggerWidth = width();
actualTriggerPoint = triggerPoint = geometry().bottomLeft();
if (fancy) {
triggerWidth += 30;
triggerPoint.setX(qMax(0, triggerPoint.x() - 15));
triggerPoint.setY(qMax(0, triggerPoint.y() - 29));
}
break;
case Plasma::RightEdge:
actualHeight = triggerHeight = height();
actualTriggerPoint = triggerPoint = geometry().topRight();
if (fancy) {
triggerHeight += 30;
triggerPoint.setY(qMax(0, triggerPoint.y() - 15));
triggerPoint.setX(qMax(0, triggerPoint.x() - 29));
}
break;
case Plasma::LeftEdge:
actualHeight = triggerHeight = height();
if (fancy) {
triggerHeight += 30;
triggerPoint.setY(qMax(0, triggerPoint.y() - 15));
}
break;
default:
// no hiding unless we're on an edge.
return;
break;
}
XSetWindowAttributes attributes;
attributes.override_redirect = True;
attributes.event_mask = EnterWindowMask;
attributes.event_mask = EnterWindowMask | LeaveWindowMask | PointerMotionMask |
KeyPressMask | ButtonPressMask |
ButtonReleaseMask | ButtonMotionMask |
KeymapStateMask | VisibilityChangeMask |
StructureNotifyMask | ResizeRedirectMask |
SubstructureNotifyMask |
SubstructureRedirectMask | FocusChangeMask |
PropertyChangeMask | ColormapChangeMask | OwnerGrabButtonMask;
unsigned long valuemask = CWOverrideRedirect | CWEventMask;
m_unhideTrigger = XCreateWindow(QX11Info::display(), QX11Info::appRootWindow(),
triggerPoint.x(), triggerPoint.y(), triggerWidth, triggerHeight,
0, CopyFromParent, InputOnly, CopyFromParent,
valuemask, &attributes);
XChangeProperty(QX11Info::display(), m_unhideTrigger, PlasmaApp::self()->m_XdndAwareAtom,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&PlasmaApp::self()->m_XdndVersionAtom, 1);
XMapWindow(QX11Info::display(), m_unhideTrigger);
m_unhideTriggerGeom = QRect(triggerPoint, QSize(triggerWidth, triggerHeight));
m_triggerZone = QRect(actualTriggerPoint, QSize(actualWidth, actualHeight));
#endif
//kDebug() << m_unhideTrigger;
PlasmaApp::self()->panelHidden(true);
}
void PanelView::destroyUnhideTrigger()
{
#ifdef Q_WS_X11
if (m_unhideTrigger == None) {
return;
}
//kDebug();
XDestroyWindow(QX11Info::display(), m_unhideTrigger);
m_unhideTrigger = None;
m_triggerZone = m_unhideTriggerGeom = QRect();
#endif
//kDebug();
PlasmaApp::self()->panelHidden(false);
}
void PanelView::panelDeleted()
{
if (!QApplication::closingDown()) {
// the panel was removed at runtime; clean up our configuration object as well
KConfigGroup c = config();
c.deleteGroup();
configNeedsSaving();
}
delete m_mousePollTimer;
m_mousePollTimer = 0;
m_strutsTimer->stop();
deleteLater();
}
void PanelView::positionSpacer(const QPoint pos)
{
if (!containment()) {
return;
}
QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout*>(containment()->layout());
if (!lay) {
return;
}
Plasma::FormFactor f = containment()->formFactor();
int insertIndex = -1;
//FIXME: needed in two places, make it a function?
for (int i = 0; i < lay->count(); ++i) {
QRectF siblingGeometry = lay->itemAt(i)->geometry();
if (f == Plasma::Horizontal) {
qreal middle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0;
if (pos.x() < middle) {
insertIndex = i;
break;
} else if (pos.x() <= siblingGeometry.right()) {
insertIndex = i + 1;
break;
}
} else { // Plasma::Vertical
qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
if (pos.y() < middle) {
insertIndex = i;
break;
} else if (pos.y() <= siblingGeometry.bottom()) {
insertIndex = i + 1;
break;
}
}
}
m_spacerIndex = insertIndex;
if (insertIndex != -1) {
if (!m_spacer) {
m_spacer = new QGraphicsWidget(containment());
//m_spacer->panel = this;
}
lay->removeItem(m_spacer);
m_spacer->show();
lay->insertItem(insertIndex, m_spacer);
}
}
void PanelView::dragLeaveEvent(QDragLeaveEvent *event)
{
if (containment()) {
containment()->showDropZone(QPoint());
}
Plasma::View::dragLeaveEvent(event);
}
void PanelView::dropEvent(QDropEvent *event)
{
Plasma::View::dropEvent(event);
if (containment()) {
containment()->showDropZone(QPoint());
}
}
#include "panelview.moc"