1 | /******************************************************************** |
2 | KWin - the KDE window manager |
3 | This file is part of the KDE project. |
4 | |
5 | Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org> |
6 | Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> |
7 | Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org> |
8 | |
9 | This program is free software; you can redistribute it and/or modify |
10 | it under the terms of the GNU General Public License as published by |
11 | the Free Software Foundation; either version 2 of the License, or |
12 | (at your option) any later version. |
13 | |
14 | This program is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along 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 | |
32 | namespace KWin |
33 | { |
34 | extern int screen_number; |
35 | |
36 | RootInfo *RootInfo::s_self = NULL; |
37 | |
38 | RootInfo *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 | |
142 | void 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 | |
151 | RootInfo::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 | |
156 | void RootInfo::changeNumberOfDesktops(int n) |
157 | { |
158 | VirtualDesktopManager::self()->setCount(n); |
159 | } |
160 | |
161 | void RootInfo::changeCurrentDesktop(int d) |
162 | { |
163 | VirtualDesktopManager::self()->setCurrent(d); |
164 | } |
165 | |
166 | void 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 | |
194 | void 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 | |
205 | void 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 | |
212 | void RootInfo::closeWindow(Window w) |
213 | { |
214 | Client* c = Workspace::self()->findClient(WindowMatchPredicate(w)); |
215 | if (c) |
216 | c->closeWindow(); |
217 | } |
218 | |
219 | void 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 | |
228 | void 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 | |
235 | void RootInfo::gotPing(Window w, Time timestamp) |
236 | { |
237 | if (Client* c = Workspace::self()->findClient(WindowMatchPredicate(w))) |
238 | c->gotPing(timestamp); |
239 | } |
240 | |
241 | void RootInfo::changeShowingDesktop(bool showing) |
242 | { |
243 | Workspace::self()->setShowingDesktop(showing); |
244 | } |
245 | |
246 | // **************************************** |
247 | // WinInfo |
248 | // **************************************** |
249 | |
250 | WinInfo::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 | |
256 | void WinInfo::changeDesktop(int desktop) |
257 | { |
258 | Workspace::self()->sendClientToDesktop(m_client, desktop, true); |
259 | } |
260 | |
261 | void WinInfo::changeFullscreenMonitors(NETFullscreenMonitors topology) |
262 | { |
263 | m_client->updateFullscreenMonitors(topology); |
264 | } |
265 | |
266 | void 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 | |
300 | void WinInfo::disable() |
301 | { |
302 | m_client = NULL; // only used when the object is passed to Deleted |
303 | } |
304 | |
305 | } // namespace |
306 | |