1
0
mirror of https://github.com/KDE/latte-dock.git synced 2024-12-26 11:21:40 +03:00
latte-dock/app/xwindowinterface.cpp

294 lines
9.6 KiB
C++
Raw Normal View History

2017-01-03 01:05:30 +03:00
/*
* 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"
2016-12-29 08:37:53 +03:00
#include "../liblattedock/extras.h"
2016-12-29 08:37:53 +03:00
#include <QDebug>
#include <QTimer>
2016-12-28 10:57:31 +03:00
#include <QtX11Extras/QX11Info>
#include <KWindowSystem>
#include <KWindowInfo>
2016-12-28 10:57:31 +03:00
#include <NETWM>
2016-12-28 10:57:31 +03:00
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);
}
2016-12-28 10:57:31 +03:00
}
};
connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, addWindow);
2017-06-29 23:50:11 +03:00
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);
}
2016-12-28 10:57:31 +03:00
});
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)
{
2016-12-28 10:57:31 +03:00
NETWinInfo winfo(QX11Info::connection()
, static_cast<xcb_window_t>(view.winId())
, static_cast<xcb_window_t>(view.winId())
2016-12-28 10:57:31 +03:00
, 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"});
}
2017-06-29 23:50:11 +03:00
void XWindowInterface::setDockStruts(QWindow &view, const QRect &rect
, Plasma::Types::Location location)
2016-12-29 08:37:53 +03:00
{
NETExtendedStrut strut;
2017-01-16 22:07:49 +03:00
2017-06-24 00:00:16 +03:00
const auto screen = view.screen();
const QRect currentScreen {screen->geometry()};
const QRect wholeScreen {{0, 0}, screen->virtualSize()};
2016-12-29 08:37:53 +03:00
switch (location) {
case Plasma::Types::TopEdge: {
const int topOffset {screen->geometry().top()};
2017-06-29 23:50:11 +03:00
strut.top_width = rect.height() + topOffset;
strut.top_start = rect.x();
strut.top_end = rect.x() + rect.width() - 1;
2016-12-29 08:37:53 +03:00
break;
}
2017-01-16 22:07:49 +03:00
case Plasma::Types::BottomEdge: {
const int bottomOffset {wholeScreen.bottom() - currentScreen.bottom()};
2017-06-29 23:50:11 +03:00
strut.bottom_width = rect.height() + bottomOffset;
strut.bottom_start = rect.x();
strut.bottom_end = rect.x() + rect.width() - 1;
2016-12-29 08:37:53 +03:00
break;
}
case Plasma::Types::LeftEdge: {
const int leftOffset = {screen->geometry().left()};
2017-06-29 23:50:11 +03:00
strut.left_width = rect.width() + leftOffset;
strut.left_start = rect.y();
strut.left_end = rect.y() + rect.height() - 1;
2016-12-29 08:37:53 +03:00
break;
}
case Plasma::Types::RightEdge: {
const int rightOffset = {wholeScreen.right() - currentScreen.right()};
2017-06-29 23:50:11 +03:00
strut.right_width = rect.width() + rightOffset;
strut.right_start = rect.y();
strut.right_end = rect.y() + rect.height() - 1;
2016-12-29 08:37:53 +03:00
break;
}
2016-12-29 08:37:53 +03:00
default:
qWarning() << "wrong location:" << qEnumToStr(location);
return;
}
2017-01-16 22:07:49 +03:00
KWindowSystem::setExtendedStrut(view.winId(),
2016-12-29 08:37:53 +03:00
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
2016-12-29 08:37:53 +03:00
{
KWindowEffects::enableBlurBehind(view.winId());
2016-12-29 08:37:53 +03:00
}
WindowInfoWrap XWindowInterface::requestInfoActive() const
{
2016-12-28 10:57:31 +03:00
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
2017-03-15 10:57:42 +03:00
| NET::WMWindowType
| NET::WMGeometry
| NET::WMState};
2016-12-28 10:57:31 +03:00
WindowInfoWrap winfoWrap;
2017-01-16 22:07:49 +03:00
2017-03-15 10:57:42 +03:00
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));
2017-02-11 09:58:25 +03:00
winfoWrap.setGeometry(winfo.frameGeometry());
winfoWrap.setIsKeepAbove(winfo.hasState(NET::KeepAbove));
} else if (m_desktopId == wid) {
winfoWrap.setIsValid(true);
winfoWrap.setIsPlasmaDesktop(true);
winfoWrap.setWid(wid);
}
2017-01-16 22:07:49 +03:00
2016-12-28 10:57:31 +03:00
return winfoWrap;
}
bool XWindowInterface::isValidWindow(const KWindowInfo &winfo) const
2016-12-28 10:57:31 +03:00
{
2017-03-15 10:57:42 +03:00
constexpr auto types = NET::DockMask | NET::MenuMask | NET::SplashMask | NET::NormalMask;
auto winType = winfo.windowType(types);
2017-01-16 22:07:49 +03:00
2017-01-24 22:27:57 +03:00
if (winType == -1) {
2017-03-15 10:57:42 +03:00
// Trying to get more types for verify if the window have any other type
winType = winfo.windowType(~types & NET::AllTypesMask);
2017-01-16 22:07:49 +03:00
2017-03-15 10:57:42 +03:00
if (winType == -1) {
qWarning() << KWindowInfo(winfo.win(), 0, NET::WM2WindowClass).windowClassName()
<< "doesn't have any WindowType, assuming as NET::Normal";
2017-01-24 22:27:57 +03:00
return true;
2017-03-15 10:57:42 +03:00
}
2017-01-24 22:27:57 +03:00
}
return !((winType & NET::Menu) || (winType & NET::Dock) || (winType & NET::Splash));
}
2016-12-28 10:57:31 +03:00
void XWindowInterface::windowChangedProxy(WId wid, NET::Properties prop1, NET::Properties2 prop2)
{
2016-12-28 10:57:31 +03:00
//! if the dock changed is ignored
if (std::find(m_docks.cbegin(), m_docks.cend(), wid) != m_docks.cend())
2016-12-28 10:57:31 +03:00
return;
2017-01-16 22:07:49 +03:00
const auto winType = KWindowInfo(wid, NET::WMWindowType).windowType(NET::DesktopMask);
2017-01-16 22:07:49 +03:00
if (winType != -1 && (winType & NET::Desktop)) {
m_desktopId = wid;
emit windowChanged(wid);
2016-12-28 10:57:31 +03:00
return;
}
2017-01-16 22:07:49 +03:00
//! ignore when, eg: the user presses a key, or a window is sending X events
//! without needing to (e.g. Firefox, https://bugzilla.mozilla.org/show_bug.cgi?id=1389953)
if (prop1 == 0 && (prop2 == NET::WM2UserTime || prop2 == NET::WM2IconPixmap)) {
return;
}
2017-01-16 22:07:49 +03:00
2016-12-28 10:57:31 +03:00
if (prop1 && !(prop1 & NET::WMState || prop1 & NET::WMGeometry || prop1 & NET::ActiveWindow))
return;
2017-01-16 22:07:49 +03:00
emit windowChanged(wid);
}
}