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