1 /*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
7 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
8
9 SPDX-License-Identifier: GPL-2.0-or-later
10 */
11 // own
12 #include "netinfo.h"
13 // kwin
14 #include "x11client.h"
15 #include "rootinfo_filter.h"
16 #include "virtualdesktops.h"
17 #include "workspace.h"
18 // Qt
19 #include <QDebug>
20
21 namespace KWin
22 {
23 extern int screen_number;
24
25 RootInfo *RootInfo::s_self = nullptr;
26
create()27 RootInfo *RootInfo::create()
28 {
29 Q_ASSERT(!s_self);
30 xcb_window_t supportWindow = xcb_generate_id(connection());
31 const uint32_t values[] = {true};
32 xcb_create_window(connection(), XCB_COPY_FROM_PARENT, supportWindow, KWin::rootWindow(),
33 0, 0, 1, 1, 0, XCB_COPY_FROM_PARENT,
34 XCB_COPY_FROM_PARENT, XCB_CW_OVERRIDE_REDIRECT, values);
35 const uint32_t lowerValues[] = { XCB_STACK_MODE_BELOW }; // See usage in layers.cpp
36 // we need to do the lower window with a roundtrip, otherwise NETRootInfo is not functioning
37 ScopedCPointer<xcb_generic_error_t> error(xcb_request_check(connection(),
38 xcb_configure_window_checked(connection(), supportWindow, XCB_CONFIG_WINDOW_STACK_MODE, lowerValues)));
39 if (!error.isNull()) {
40 qCDebug(KWIN_CORE) << "Error occurred while lowering support window: " << error->error_code;
41 }
42
43 const NET::Properties properties = NET::Supported |
44 NET::SupportingWMCheck |
45 NET::ClientList |
46 NET::ClientListStacking |
47 NET::DesktopGeometry |
48 NET::NumberOfDesktops |
49 NET::CurrentDesktop |
50 NET::ActiveWindow |
51 NET::WorkArea |
52 NET::CloseWindow |
53 NET::DesktopNames |
54 NET::WMName |
55 NET::WMVisibleName |
56 NET::WMDesktop |
57 NET::WMWindowType |
58 NET::WMState |
59 NET::WMStrut |
60 NET::WMIconGeometry |
61 NET::WMIcon |
62 NET::WMPid |
63 NET::WMMoveResize |
64 NET::WMFrameExtents |
65 NET::WMPing;
66 const NET::WindowTypes types = NET::NormalMask |
67 NET::DesktopMask |
68 NET::DockMask |
69 NET::ToolbarMask |
70 NET::MenuMask |
71 NET::DialogMask |
72 NET::OverrideMask |
73 NET::UtilityMask |
74 NET::SplashMask; // No compositing window types here unless we support them also as managed window types
75 const NET::States states = NET::Modal |
76 //NET::Sticky | // Large desktops not supported (and probably never will be)
77 NET::MaxVert |
78 NET::MaxHoriz |
79 NET::Shaded |
80 NET::SkipTaskbar |
81 NET::KeepAbove |
82 //NET::StaysOnTop | // The same like KeepAbove
83 NET::SkipPager |
84 NET::Hidden |
85 NET::FullScreen |
86 NET::KeepBelow |
87 NET::DemandsAttention |
88 NET::SkipSwitcher |
89 NET::Focused;
90 NET::Properties2 properties2 = NET::WM2UserTime |
91 NET::WM2StartupId |
92 NET::WM2AllowedActions |
93 NET::WM2RestackWindow |
94 NET::WM2MoveResizeWindow |
95 NET::WM2ExtendedStrut |
96 NET::WM2KDETemporaryRules |
97 NET::WM2ShowingDesktop |
98 NET::WM2DesktopLayout |
99 NET::WM2FullPlacement |
100 NET::WM2FullscreenMonitors |
101 NET::WM2KDEShadow |
102 NET::WM2OpaqueRegion |
103 NET::WM2GTKFrameExtents;
104 #ifdef KWIN_BUILD_ACTIVITIES
105 properties2 |= NET::WM2Activities;
106 #endif
107 const NET::Actions actions = NET::ActionMove |
108 NET::ActionResize |
109 NET::ActionMinimize |
110 NET::ActionShade |
111 //NET::ActionStick | // Sticky state is not supported
112 NET::ActionMaxVert |
113 NET::ActionMaxHoriz |
114 NET::ActionFullScreen |
115 NET::ActionChangeDesktop |
116 NET::ActionClose;
117
118 s_self = new RootInfo(supportWindow, "KWin", properties, types, states, properties2, actions, screen_number);
119 return s_self;
120 }
121
destroy()122 void RootInfo::destroy()
123 {
124 if (!s_self) {
125 return;
126 }
127 xcb_window_t supportWindow = s_self->supportWindow();
128 delete s_self;
129 s_self = nullptr;
130 xcb_destroy_window(connection(), supportWindow);
131 }
132
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)133 RootInfo::RootInfo(xcb_window_t w, const char *name, NET::Properties properties, NET::WindowTypes types,
134 NET::States states, NET::Properties2 properties2, NET::Actions actions, int scr)
135 : NETRootInfo(connection(), w, name, properties, types, states, properties2, actions, scr)
136 , m_activeWindow(activeWindow())
137 , m_eventFilter(std::make_unique<RootInfoFilter>(this))
138 {
139 }
140
changeNumberOfDesktops(int n)141 void RootInfo::changeNumberOfDesktops(int n)
142 {
143 VirtualDesktopManager::self()->setCount(n);
144 }
145
changeCurrentDesktop(int d)146 void RootInfo::changeCurrentDesktop(int d)
147 {
148 VirtualDesktopManager::self()->setCurrent(d);
149 }
150
changeActiveWindow(xcb_window_t w,NET::RequestSource src,xcb_timestamp_t timestamp,xcb_window_t active_window)151 void RootInfo::changeActiveWindow(xcb_window_t w, NET::RequestSource src, xcb_timestamp_t timestamp, xcb_window_t active_window)
152 {
153 Workspace *workspace = Workspace::self();
154 if (X11Client *c = workspace->findClient(Predicate::WindowMatch, w)) {
155 if (timestamp == XCB_CURRENT_TIME)
156 timestamp = c->userTime();
157 if (src != NET::FromApplication && src != FromTool)
158 src = NET::FromTool;
159 if (src == NET::FromTool)
160 workspace->activateClient(c, true); // force
161 else if (c == workspace->mostRecentlyActivatedClient()) {
162 return; // WORKAROUND? With > 1 plasma activities, we cause this ourselves. bug #240673
163 } else { // NET::FromApplication
164 X11Client *c2;
165 if (workspace->allowClientActivation(c, timestamp, false, true))
166 workspace->activateClient(c);
167 // if activation of the requestor's window would be allowed, allow activation too
168 else if (active_window != XCB_WINDOW_NONE
169 && (c2 = workspace->findClient(Predicate::WindowMatch, active_window)) != nullptr
170 && workspace->allowClientActivation(c2,
171 timestampCompare(timestamp, c2->userTime() > 0 ? timestamp : c2->userTime()), false, true)) {
172 workspace->activateClient(c);
173 } else
174 c->demandAttention();
175 }
176 }
177 }
178
restackWindow(xcb_window_t w,RequestSource src,xcb_window_t above,int detail,xcb_timestamp_t timestamp)179 void RootInfo::restackWindow(xcb_window_t w, RequestSource src, xcb_window_t above, int detail, xcb_timestamp_t timestamp)
180 {
181 if (X11Client *c = Workspace::self()->findClient(Predicate::WindowMatch, w)) {
182 if (timestamp == XCB_CURRENT_TIME)
183 timestamp = c->userTime();
184 if (src != NET::FromApplication && src != FromTool)
185 src = NET::FromTool;
186 c->restackWindow(above, detail, src, timestamp, true);
187 }
188 }
189
closeWindow(xcb_window_t w)190 void RootInfo::closeWindow(xcb_window_t w)
191 {
192 X11Client *c = Workspace::self()->findClient(Predicate::WindowMatch, w);
193 if (c)
194 c->closeWindow();
195 }
196
moveResize(xcb_window_t w,int x_root,int y_root,unsigned long direction)197 void RootInfo::moveResize(xcb_window_t w, int x_root, int y_root, unsigned long direction)
198 {
199 X11Client *c = Workspace::self()->findClient(Predicate::WindowMatch, w);
200 if (c) {
201 updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
202 c->NETMoveResize(x_root, y_root, (Direction)direction);
203 }
204 }
205
moveResizeWindow(xcb_window_t w,int flags,int x,int y,int width,int height)206 void RootInfo::moveResizeWindow(xcb_window_t w, int flags, int x, int y, int width, int height)
207 {
208 X11Client *c = Workspace::self()->findClient(Predicate::WindowMatch, w);
209 if (c)
210 c->NETMoveResizeWindow(flags, x, y, width, height);
211 }
212
gotPing(xcb_window_t w,xcb_timestamp_t timestamp)213 void RootInfo::gotPing(xcb_window_t w, xcb_timestamp_t timestamp)
214 {
215 if (X11Client *c = Workspace::self()->findClient(Predicate::WindowMatch, w))
216 c->gotPing(timestamp);
217 }
218
changeShowingDesktop(bool showing)219 void RootInfo::changeShowingDesktop(bool showing)
220 {
221 Workspace::self()->setShowingDesktop(showing);
222 }
223
setActiveClient(AbstractClient * client)224 void RootInfo::setActiveClient(AbstractClient *client)
225 {
226 const xcb_window_t w = client ? client->window() : xcb_window_t{XCB_WINDOW_NONE};
227 if (m_activeWindow == w) {
228 return;
229 }
230 m_activeWindow = w;
231 setActiveWindow(m_activeWindow);
232 }
233
234 // ****************************************
235 // WinInfo
236 // ****************************************
237
WinInfo(X11Client * c,xcb_window_t window,xcb_window_t rwin,NET::Properties properties,NET::Properties2 properties2)238 WinInfo::WinInfo(X11Client *c, xcb_window_t window,
239 xcb_window_t rwin, NET::Properties properties, NET::Properties2 properties2)
240 : NETWinInfo(connection(), window, rwin, properties, properties2, NET::WindowManager), m_client(c)
241 {
242 }
243
changeDesktop(int desktop)244 void WinInfo::changeDesktop(int desktop)
245 {
246 Workspace::self()->sendClientToDesktop(m_client, desktop, true);
247 }
248
changeFullscreenMonitors(NETFullscreenMonitors topology)249 void WinInfo::changeFullscreenMonitors(NETFullscreenMonitors topology)
250 {
251 m_client->updateFullscreenMonitors(topology);
252 }
253
changeState(NET::States state,NET::States mask)254 void WinInfo::changeState(NET::States state, NET::States mask)
255 {
256 mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore
257 mask &= ~NET::Hidden; // clients are not allowed to change this directly
258 state &= mask; // for safety, clear all other bits
259
260 if ((mask & NET::FullScreen) != 0 && (state & NET::FullScreen) == 0)
261 m_client->setFullScreen(false, false);
262 if ((mask & NET::Max) == NET::Max)
263 m_client->setMaximize(state & NET::MaxVert, state & NET::MaxHoriz);
264 else if (mask & NET::MaxVert)
265 m_client->setMaximize(state & NET::MaxVert, m_client->maximizeMode() & MaximizeHorizontal);
266 else if (mask & NET::MaxHoriz)
267 m_client->setMaximize(m_client->maximizeMode() & MaximizeVertical, state & NET::MaxHoriz);
268
269 if (mask & NET::Shaded)
270 m_client->setShade(state & NET::Shaded ? ShadeNormal : ShadeNone);
271 if (mask & NET::KeepAbove)
272 m_client->setKeepAbove((state & NET::KeepAbove) != 0);
273 if (mask & NET::KeepBelow)
274 m_client->setKeepBelow((state & NET::KeepBelow) != 0);
275 if (mask & NET::SkipTaskbar)
276 m_client->setOriginalSkipTaskbar((state & NET::SkipTaskbar) != 0);
277 if (mask & NET::SkipPager)
278 m_client->setSkipPager((state & NET::SkipPager) != 0);
279 if (mask & NET::SkipSwitcher)
280 m_client->setSkipSwitcher((state & NET::SkipSwitcher) != 0);
281 if (mask & NET::DemandsAttention)
282 m_client->demandAttention((state & NET::DemandsAttention) != 0);
283 if (mask & NET::Modal)
284 m_client->setModal((state & NET::Modal) != 0);
285 // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() )
286 if ((mask & NET::FullScreen) != 0 && (state & NET::FullScreen) != 0)
287 m_client->setFullScreen(true, false);
288 }
289
disable()290 void WinInfo::disable()
291 {
292 m_client = nullptr; // only used when the object is passed to Deleted
293 }
294
295 } // namespace
296