1
0
mirror of https://github.com/KDE/latte-dock.git synced 2025-01-31 13:47:20 +03:00
latte-dock/app/xwindowinterface.cpp
Michail Vourlakos d86fdfd2ff fix #810,support smart/dynamic background
the dynamic background feature is enhanced and
becomes smarter. It understands snapped windows, windows
that touch the panel edge etc. The criteria in
order for the background to become solid are:
   - any active window that is touching the panel
edge (that includes krunner)
   - any inactive window that is snapped and touches
the panel edge (concerning its geometry: quarter-snapped or half-snapped)
   - maximized windows
   - an inactive window but keepAbove is touching
the panel edge (this catches also the yakuake case)
   - panel popups
2018-01-02 11:49:38 +02:00

293 lines
9.4 KiB
C++

/*
* Copyright 2016 Smith AR <audoban@openmailbox.org>
* Michail Vourlakos <mvourlakos@gmail.com>
*
* This file is part of Latte-Dock
*
* Latte-Dock 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.
*
* Latte-Dock 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/>.
*/
#include "xwindowinterface.h"
#include "../liblattedock/extras.h"
#include <QDebug>
#include <QTimer>
#include <QtX11Extras/QX11Info>
#include <KWindowSystem>
#include <KWindowInfo>
#include <NETWM>
namespace Latte {
XWindowInterface::XWindowInterface(QObject *parent)
: AbstractWindowInterface(parent)
{
m_activities = new KActivities::Consumer(this);
connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged
, this, &AbstractWindowInterface::activeWindowChanged);
connect(KWindowSystem::self()
, static_cast<void (KWindowSystem::*)(WId, NET::Properties, NET::Properties2)>
(&KWindowSystem::windowChanged)
, this, &XWindowInterface::windowChangedProxy);
auto addWindow = [&](WindowId wid) {
if (std::find(m_windows.cbegin(), m_windows.cend(), wid) == m_windows.cend()) {
if (isValidWindow(KWindowInfo(wid.value<WId>(), NET::WMWindowType))) {
m_windows.push_back(wid);
emit windowAdded(wid);
}
}
};
connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, addWindow);
connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, [this](WindowId wid) noexcept {
if (std::find(m_windows.cbegin(), m_windows.cend(), wid) != m_windows.end()) {
m_windows.remove(wid);
emit windowRemoved(wid);
}
});
connect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged
, this, &XWindowInterface::currentDesktopChanged);
connect(m_activities.data(), &KActivities::Consumer::currentActivityChanged
, this, &XWindowInterface::currentActivityChanged);
// fill windows list
foreach (const auto &wid, KWindowSystem::self()->windows()) {
addWindow(wid);
}
}
XWindowInterface::~XWindowInterface()
{
}
void XWindowInterface::setDockExtraFlags(QWindow &view)
{
NETWinInfo winfo(QX11Info::connection()
, static_cast<xcb_window_t>(view.winId())
, static_cast<xcb_window_t>(view.winId())
, 0, 0);
winfo.setAllowedActions(NET::ActionChangeDesktop);
KWindowSystem::setType(view.winId(), NET::Dock);
KWindowSystem::setState(view.winId(), NET::SkipTaskbar | NET::SkipPager);
KWindowSystem::setOnAllDesktops(view.winId(), true);
KWindowSystem::setOnActivities(view.winId(), {"0"});
}
void XWindowInterface::setDockStruts(QWindow &view, const QRect &rect
, Plasma::Types::Location location)
{
NETExtendedStrut strut;
const auto screen = view.screen();
const QRect currentScreen {screen->geometry()};
const QRect wholeScreen {{0, 0}, screen->virtualSize()};
switch (location) {
case Plasma::Types::TopEdge: {
const int topOffset {screen->geometry().top()};
strut.top_width = rect.height() + topOffset;
strut.top_start = rect.x();
strut.top_end = rect.x() + rect.width() - 1;
break;
}
case Plasma::Types::BottomEdge: {
const int bottomOffset {wholeScreen.bottom() - currentScreen.bottom()};
strut.bottom_width = rect.height() + bottomOffset;
strut.bottom_start = rect.x();
strut.bottom_end = rect.x() + rect.width() - 1;
break;
}
case Plasma::Types::LeftEdge: {
const int leftOffset = {screen->geometry().left()};
strut.left_width = rect.width() + leftOffset;
strut.left_start = rect.y();
strut.left_end = rect.y() + rect.height() - 1;
break;
}
case Plasma::Types::RightEdge: {
const int rightOffset = {wholeScreen.right() - currentScreen.right()};
strut.right_width = rect.width() + rightOffset;
strut.right_start = rect.y();
strut.right_end = rect.y() + rect.height() - 1;
break;
}
default:
qWarning() << "wrong location:" << qEnumToStr(location);
return;
}
KWindowSystem::setExtendedStrut(view.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
);
}
void XWindowInterface::removeDockStruts(QWindow &view) const
{
KWindowSystem::setStrut(view.winId(), 0, 0, 0, 0);
}
WindowId XWindowInterface::activeWindow() const
{
return KWindowSystem::self()->activeWindow();
}
const std::list<WindowId> &XWindowInterface::windows() const
{
return m_windows;
}
void XWindowInterface::skipTaskBar(const QDialog &dialog) const
{
KWindowSystem::setState(dialog.winId(), NET::SkipTaskbar);
}
void XWindowInterface::slideWindow(QWindow &view, AbstractWindowInterface::Slide location) const
{
auto slideLocation = KWindowEffects::NoEdge;
switch (location) {
case Slide::Top:
slideLocation = KWindowEffects::TopEdge;
break;
case Slide::Bottom:
slideLocation = KWindowEffects::BottomEdge;
break;
case Slide::Left:
slideLocation = KWindowEffects::LeftEdge;
break;
case Slide::Right:
slideLocation = KWindowEffects::RightEdge;
break;
default:
break;
}
KWindowEffects::slideWindow(view.winId(), slideLocation, -1);
}
void XWindowInterface::enableBlurBehind(QWindow &view) const
{
KWindowEffects::enableBlurBehind(view.winId());
}
WindowInfoWrap XWindowInterface::requestInfoActive() const
{
return requestInfo(KWindowSystem::activeWindow());
}
bool XWindowInterface::isOnCurrentDesktop(WindowId wid) const
{
KWindowInfo winfo(wid.value<WId>(), NET::WMDesktop);
return winfo.valid() && winfo.isOnCurrentDesktop();
}
bool XWindowInterface::isOnCurrentActivity(WindowId wid) const
{
KWindowInfo winfo(wid.value<WId>(), 0, NET::WM2Activities);
return winfo.valid()
&& (winfo.activities().contains(m_activities->currentActivity()) || winfo.activities().empty());
}
WindowInfoWrap XWindowInterface::requestInfo(WindowId wid) const
{
const KWindowInfo winfo{wid.value<WId>(), NET::WMFrameExtents
| NET::WMWindowType
| NET::WMGeometry
| NET::WMState};
WindowInfoWrap winfoWrap;
if (isValidWindow(winfo)) {
winfoWrap.setIsValid(true);
winfoWrap.setWid(wid);
winfoWrap.setIsActive(KWindowSystem::activeWindow() == wid.value<WId>());
winfoWrap.setIsMinimized(winfo.hasState(NET::Hidden));
winfoWrap.setIsMaxVert(winfo.hasState(NET::MaxVert));
winfoWrap.setIsMaxHoriz(winfo.hasState(NET::MaxHoriz));
winfoWrap.setIsFullscreen(winfo.hasState(NET::FullScreen));
winfoWrap.setIsShaded(winfo.hasState(NET::Shaded));
winfoWrap.setGeometry(winfo.frameGeometry());
winfoWrap.setIsKeepAbove(winfo.hasState(NET::KeepAbove));
} else if (m_desktopId == wid) {
winfoWrap.setIsValid(true);
winfoWrap.setIsPlasmaDesktop(true);
winfoWrap.setWid(wid);
}
return winfoWrap;
}
bool XWindowInterface::isValidWindow(const KWindowInfo &winfo) const
{
constexpr auto types = NET::DockMask | NET::MenuMask | NET::SplashMask | NET::NormalMask;
auto winType = winfo.windowType(types);
if (winType == -1) {
// Trying to get more types for verify if the window have any other type
winType = winfo.windowType(~types & NET::AllTypesMask);
if (winType == -1) {
qWarning() << KWindowInfo(winfo.win(), 0, NET::WM2WindowClass).windowClassName()
<< "doesn't have any WindowType, assuming as NET::Normal";
return true;
}
}
return !((winType & NET::Menu) || (winType & NET::Dock) || (winType & NET::Splash));
}
void XWindowInterface::windowChangedProxy(WId wid, NET::Properties prop1, NET::Properties2 prop2)
{
//! if the dock changed is ignored
if (std::find(m_docks.cbegin(), m_docks.cend(), wid) != m_docks.cend())
return;
const auto winType = KWindowInfo(wid, NET::WMWindowType).windowType(NET::DesktopMask);
if (winType != -1 && (winType & NET::Desktop)) {
m_desktopId = wid;
emit windowChanged(wid);
return;
}
//! ignore when, eg: the user presses a key
if (prop1 == 0 && prop2 == NET::WM2UserTime) {
return;
}
if (prop1 && !(prop1 & NET::WMState || prop1 & NET::WMGeometry || prop1 & NET::ActiveWindow))
return;
emit windowChanged(wid);
}
}