315 lines
11 KiB
C++
315 lines
11 KiB
C++
/*
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
|
SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
|
|
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
// own
|
|
#include "netinfo.h"
|
|
// kwin
|
|
#include "rootinfo_filter.h"
|
|
#include "virtualdesktops.h"
|
|
#include "workspace.h"
|
|
#include "x11window.h"
|
|
// Qt
|
|
#include <QDebug>
|
|
|
|
namespace KWin
|
|
{
|
|
extern int screen_number;
|
|
|
|
RootInfo *RootInfo::s_self = nullptr;
|
|
|
|
RootInfo *RootInfo::create()
|
|
{
|
|
Q_ASSERT(!s_self);
|
|
xcb_window_t supportWindow = xcb_generate_id(kwinApp()->x11Connection());
|
|
const uint32_t values[] = {true};
|
|
xcb_create_window(kwinApp()->x11Connection(), XCB_COPY_FROM_PARENT, supportWindow, kwinApp()->x11RootWindow(),
|
|
0, 0, 1, 1, 0, XCB_COPY_FROM_PARENT,
|
|
XCB_COPY_FROM_PARENT, XCB_CW_OVERRIDE_REDIRECT, values);
|
|
const uint32_t lowerValues[] = {XCB_STACK_MODE_BELOW}; // See usage in layers.cpp
|
|
// we need to do the lower window with a roundtrip, otherwise NETRootInfo is not functioning
|
|
ScopedCPointer<xcb_generic_error_t> error(xcb_request_check(kwinApp()->x11Connection(),
|
|
xcb_configure_window_checked(kwinApp()->x11Connection(), supportWindow, XCB_CONFIG_WINDOW_STACK_MODE, lowerValues)));
|
|
if (!error.isNull()) {
|
|
qCDebug(KWIN_CORE) << "Error occurred while lowering support window: " << error->error_code;
|
|
}
|
|
|
|
const NET::Properties properties = NET::Supported
|
|
| NET::SupportingWMCheck
|
|
| NET::ClientList
|
|
| NET::ClientListStacking
|
|
| NET::DesktopGeometry
|
|
| NET::NumberOfDesktops
|
|
| NET::CurrentDesktop
|
|
| NET::ActiveWindow
|
|
| NET::WorkArea
|
|
| NET::CloseWindow
|
|
| NET::DesktopNames
|
|
| NET::WMName
|
|
| NET::WMVisibleName
|
|
| NET::WMDesktop
|
|
| NET::WMWindowType
|
|
| NET::WMState
|
|
| NET::WMStrut
|
|
| NET::WMIconGeometry
|
|
| NET::WMIcon
|
|
| NET::WMPid
|
|
| NET::WMMoveResize
|
|
| NET::WMFrameExtents
|
|
| NET::WMPing;
|
|
const NET::WindowTypes types = NET::NormalMask
|
|
| NET::DesktopMask
|
|
| NET::DockMask
|
|
| NET::ToolbarMask
|
|
| NET::MenuMask
|
|
| NET::DialogMask
|
|
| NET::OverrideMask
|
|
| NET::UtilityMask
|
|
| NET::SplashMask; // No compositing window types here unless we support them also as managed window types
|
|
const NET::States states = NET::Modal
|
|
// | NET::Sticky // Large desktops not supported (and probably never will be)
|
|
| NET::MaxVert
|
|
| NET::MaxHoriz
|
|
| NET::Shaded
|
|
| NET::SkipTaskbar
|
|
| NET::KeepAbove
|
|
// | NET::StaysOnTop // The same like KeepAbove
|
|
| NET::SkipPager
|
|
| NET::Hidden
|
|
| NET::FullScreen
|
|
| NET::KeepBelow
|
|
| NET::DemandsAttention
|
|
| NET::SkipSwitcher
|
|
| NET::Focused;
|
|
NET::Properties2 properties2 = NET::WM2UserTime
|
|
| NET::WM2StartupId
|
|
| NET::WM2AllowedActions
|
|
| NET::WM2RestackWindow
|
|
| NET::WM2MoveResizeWindow
|
|
| NET::WM2ExtendedStrut
|
|
| NET::WM2KDETemporaryRules
|
|
| NET::WM2ShowingDesktop
|
|
| NET::WM2DesktopLayout
|
|
| NET::WM2FullPlacement
|
|
| NET::WM2FullscreenMonitors
|
|
| NET::WM2KDEShadow
|
|
| NET::WM2OpaqueRegion
|
|
| NET::WM2GTKFrameExtents;
|
|
#if KWIN_BUILD_ACTIVITIES
|
|
properties2 |= NET::WM2Activities;
|
|
#endif
|
|
const NET::Actions actions = NET::ActionMove
|
|
| NET::ActionResize
|
|
| NET::ActionMinimize
|
|
| NET::ActionShade
|
|
// | NET::ActionStick // Sticky state is not supported
|
|
| NET::ActionMaxVert
|
|
| NET::ActionMaxHoriz
|
|
| NET::ActionFullScreen
|
|
| NET::ActionChangeDesktop
|
|
| NET::ActionClose;
|
|
|
|
s_self = new RootInfo(supportWindow, "KWin", properties, types, states, properties2, actions, screen_number);
|
|
return s_self;
|
|
}
|
|
|
|
void RootInfo::destroy()
|
|
{
|
|
if (!s_self) {
|
|
return;
|
|
}
|
|
xcb_window_t supportWindow = s_self->supportWindow();
|
|
delete s_self;
|
|
s_self = nullptr;
|
|
xcb_destroy_window(kwinApp()->x11Connection(), supportWindow);
|
|
}
|
|
|
|
RootInfo::RootInfo(xcb_window_t w, const char *name, NET::Properties properties, NET::WindowTypes types,
|
|
NET::States states, NET::Properties2 properties2, NET::Actions actions, int scr)
|
|
: NETRootInfo(kwinApp()->x11Connection(), w, name, properties, types, states, properties2, actions, scr)
|
|
, m_activeWindow(activeWindow())
|
|
, m_eventFilter(std::make_unique<RootInfoFilter>(this))
|
|
{
|
|
}
|
|
|
|
void RootInfo::changeNumberOfDesktops(int n)
|
|
{
|
|
VirtualDesktopManager::self()->setCount(n);
|
|
}
|
|
|
|
void RootInfo::changeCurrentDesktop(int d)
|
|
{
|
|
VirtualDesktopManager::self()->setCurrent(d);
|
|
}
|
|
|
|
void RootInfo::changeActiveWindow(xcb_window_t w, NET::RequestSource src, xcb_timestamp_t timestamp, xcb_window_t active_window)
|
|
{
|
|
Workspace *workspace = Workspace::self();
|
|
if (X11Window *c = workspace->findClient(Predicate::WindowMatch, w)) {
|
|
if (timestamp == XCB_CURRENT_TIME) {
|
|
timestamp = c->userTime();
|
|
}
|
|
if (src != NET::FromApplication && src != FromTool) {
|
|
src = NET::FromTool;
|
|
}
|
|
if (src == NET::FromTool) {
|
|
workspace->activateWindow(c, true); // force
|
|
} else if (c == workspace->mostRecentlyActivatedWindow()) {
|
|
return; // WORKAROUND? With > 1 plasma activities, we cause this ourselves. bug #240673
|
|
} else { // NET::FromApplication
|
|
X11Window *c2;
|
|
if (workspace->allowWindowActivation(c, timestamp, false, true)) {
|
|
workspace->activateWindow(c);
|
|
// if activation of the requestor's window would be allowed, allow activation too
|
|
} else if (active_window != XCB_WINDOW_NONE
|
|
&& (c2 = workspace->findClient(Predicate::WindowMatch, active_window)) != nullptr
|
|
&& workspace->allowWindowActivation(c2,
|
|
timestampCompare(timestamp, c2->userTime() > 0 ? timestamp : c2->userTime()), false, true)) {
|
|
workspace->activateWindow(c);
|
|
} else {
|
|
c->demandAttention();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RootInfo::restackWindow(xcb_window_t w, RequestSource src, xcb_window_t above, int detail, xcb_timestamp_t timestamp)
|
|
{
|
|
if (X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w)) {
|
|
if (timestamp == XCB_CURRENT_TIME) {
|
|
timestamp = c->userTime();
|
|
}
|
|
if (src != NET::FromApplication && src != FromTool) {
|
|
src = NET::FromTool;
|
|
}
|
|
c->restackWindow(above, detail, src, timestamp, true);
|
|
}
|
|
}
|
|
|
|
void RootInfo::closeWindow(xcb_window_t w)
|
|
{
|
|
X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w);
|
|
if (c) {
|
|
c->closeWindow();
|
|
}
|
|
}
|
|
|
|
void RootInfo::moveResize(xcb_window_t w, int x_root, int y_root, unsigned long direction)
|
|
{
|
|
X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w);
|
|
if (c) {
|
|
updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
|
|
c->NETMoveResize(x_root, y_root, (Direction)direction);
|
|
}
|
|
}
|
|
|
|
void RootInfo::moveResizeWindow(xcb_window_t w, int flags, int x, int y, int width, int height)
|
|
{
|
|
X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w);
|
|
if (c) {
|
|
c->NETMoveResizeWindow(flags, x, y, width, height);
|
|
}
|
|
}
|
|
|
|
void RootInfo::gotPing(xcb_window_t w, xcb_timestamp_t timestamp)
|
|
{
|
|
if (X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w)) {
|
|
c->gotPing(timestamp);
|
|
}
|
|
}
|
|
|
|
void RootInfo::changeShowingDesktop(bool showing)
|
|
{
|
|
Workspace::self()->setShowingDesktop(showing);
|
|
}
|
|
|
|
void RootInfo::setActiveClient(Window *client)
|
|
{
|
|
const xcb_window_t w = client ? client->window() : xcb_window_t{XCB_WINDOW_NONE};
|
|
if (m_activeWindow == w) {
|
|
return;
|
|
}
|
|
m_activeWindow = w;
|
|
setActiveWindow(m_activeWindow);
|
|
}
|
|
|
|
// ****************************************
|
|
// WinInfo
|
|
// ****************************************
|
|
|
|
WinInfo::WinInfo(X11Window *c, xcb_window_t window,
|
|
xcb_window_t rwin, NET::Properties properties, NET::Properties2 properties2)
|
|
: NETWinInfo(kwinApp()->x11Connection(), window, rwin, properties, properties2, NET::WindowManager)
|
|
, m_client(c)
|
|
{
|
|
}
|
|
|
|
void WinInfo::changeDesktop(int desktop)
|
|
{
|
|
Workspace::self()->sendWindowToDesktop(m_client, desktop, true);
|
|
}
|
|
|
|
void WinInfo::changeFullscreenMonitors(NETFullscreenMonitors topology)
|
|
{
|
|
m_client->updateFullscreenMonitors(topology);
|
|
}
|
|
|
|
void WinInfo::changeState(NET::States state, NET::States mask)
|
|
{
|
|
mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore
|
|
mask &= ~NET::Hidden; // clients are not allowed to change this directly
|
|
state &= mask; // for safety, clear all other bits
|
|
|
|
if ((mask & NET::FullScreen) != 0 && (state & NET::FullScreen) == 0) {
|
|
m_client->setFullScreen(false, false);
|
|
}
|
|
if ((mask & NET::Max) == NET::Max) {
|
|
m_client->setMaximize(state & NET::MaxVert, state & NET::MaxHoriz);
|
|
} else if (mask & NET::MaxVert) {
|
|
m_client->setMaximize(state & NET::MaxVert, m_client->maximizeMode() & MaximizeHorizontal);
|
|
} else if (mask & NET::MaxHoriz) {
|
|
m_client->setMaximize(m_client->maximizeMode() & MaximizeVertical, state & NET::MaxHoriz);
|
|
}
|
|
|
|
if (mask & NET::Shaded) {
|
|
m_client->setShade(state & NET::Shaded ? ShadeNormal : ShadeNone);
|
|
}
|
|
if (mask & NET::KeepAbove) {
|
|
m_client->setKeepAbove((state & NET::KeepAbove) != 0);
|
|
}
|
|
if (mask & NET::KeepBelow) {
|
|
m_client->setKeepBelow((state & NET::KeepBelow) != 0);
|
|
}
|
|
if (mask & NET::SkipTaskbar) {
|
|
m_client->setOriginalSkipTaskbar((state & NET::SkipTaskbar) != 0);
|
|
}
|
|
if (mask & NET::SkipPager) {
|
|
m_client->setSkipPager((state & NET::SkipPager) != 0);
|
|
}
|
|
if (mask & NET::SkipSwitcher) {
|
|
m_client->setSkipSwitcher((state & NET::SkipSwitcher) != 0);
|
|
}
|
|
if (mask & NET::DemandsAttention) {
|
|
m_client->demandAttention((state & NET::DemandsAttention) != 0);
|
|
}
|
|
if (mask & NET::Modal) {
|
|
m_client->setModal((state & NET::Modal) != 0);
|
|
}
|
|
// unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() )
|
|
if ((mask & NET::FullScreen) != 0 && (state & NET::FullScreen) != 0) {
|
|
m_client->setFullScreen(true, false);
|
|
}
|
|
}
|
|
|
|
void WinInfo::disable()
|
|
{
|
|
m_client = nullptr; // only used when the object is passed to Deleted
|
|
}
|
|
|
|
} // namespace
|