aboutsummaryrefslogtreecommitdiff
path: root/src/Ewmh.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ewmh.cc')
-rw-r--r--src/Ewmh.cc453
1 files changed, 453 insertions, 0 deletions
diff --git a/src/Ewmh.cc b/src/Ewmh.cc
new file mode 100644
index 0000000..10fa722
--- /dev/null
+++ b/src/Ewmh.cc
@@ -0,0 +1,453 @@
1// Ewmh.cc for fluxbox
2// Copyright (c) 2002-2003 Henrik Kinnunen (fluxgen at user.sourceforge.net)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22// $Id: Ewmh.cc,v 1.29 2003/07/04 01:03:40 rathnor Exp $
23
24#include "Ewmh.hh"
25
26#include "Screen.hh"
27#include "Window.hh"
28#include "WinClient.hh"
29#include "Workspace.hh"
30
31#include <iostream>
32#include <algorithm>
33#include <new>
34using namespace std;
35
36Ewmh::Ewmh() {
37 createAtoms();
38 enableUpdate();
39}
40
41Ewmh::~Ewmh() {
42 while (!m_windows.empty()) {
43 XDestroyWindow(FbTk::App::instance()->display(), m_windows.back());
44 m_windows.pop_back();
45 }
46}
47
48void Ewmh::initForScreen(BScreen &screen) {
49 Display *disp = FbTk::App::instance()->display();
50
51
52 Window wincheck = XCreateSimpleWindow(disp,
53 screen.rootWindow().window(),
54 0, 0, 5, 5, 0, 0, 0);
55
56 if (wincheck != None) {
57 m_windows.push_back(wincheck);
58
59 screen.rootWindow().changeProperty(m_net_supporting_wm_check, XA_WINDOW, 32,
60 PropModeReplace, (unsigned char *) &wincheck, 1);
61 XChangeProperty(disp, wincheck, m_net_supporting_wm_check, XA_WINDOW, 32,
62 PropModeReplace, (unsigned char *) &wincheck, 1);
63
64 XChangeProperty(disp, wincheck, m_net_wm_name, XA_STRING, 8,
65 PropModeReplace, (unsigned char *) "Fluxbox", strlen("Fluxbox"));
66 }
67
68 //set supported atoms
69 Atom atomsupported[] = {
70 // window properties
71 m_net_wm_strut,
72 m_net_wm_state,
73 // states that we support:
74 m_net_wm_state_sticky,
75 m_net_wm_state_shaded,
76
77 m_net_wm_desktop,
78
79 // root properties
80 m_net_client_list,
81 m_net_number_of_desktops,
82 m_net_current_desktop,
83 m_net_active_window,
84 m_net_close_window,
85 m_net_moveresize_window,
86 m_net_desktop_names,
87 m_net_supporting_wm_check
88 };
89
90 screen.rootWindow().changeProperty(m_net_supported, XA_ATOM, 32,
91 PropModeReplace,
92 (unsigned char *) &atomsupported,
93 (sizeof atomsupported)/sizeof atomsupported[0]);
94
95
96}
97
98void Ewmh::setupFrame(FluxboxWindow &win) {
99
100 Atom ret_type;
101 int fmt;
102 unsigned long nitems, bytes_after;
103 long *data = 0;
104/*
105 if (XGetWindowProperty(disp, win.clientWindow(),
106 m_net_wm_state, 0, 1, False, XA_CARDINAL,
107 &ret_type, &fmt, &nitems, &bytes_after,
108 (unsigned char **) &data) == Success && data) {
109 flags = *data;
110 setState(win, flags);
111 XFree(data);
112 }
113*/
114 if (win.winClient().property(m_net_wm_desktop, 0, 1, False, XA_CARDINAL,
115 &ret_type, &fmt, &nitems, &bytes_after,
116 (unsigned char **) &data) && data) {
117 unsigned int desktop = static_cast<unsigned int>(*data);
118 if (desktop == 0xFFFFFFFF && !win.isStuck())
119 win.stick();
120 else
121 win.screen().sendToWorkspace(desktop, &win, false);
122
123 XFree(data);
124 }
125
126 updateStrut(win);
127
128}
129
130void Ewmh::updateClientList(BScreen &screen) {
131 size_t num=0;
132
133 BScreen::Workspaces::const_iterator workspace_it =
134 screen.getWorkspacesList().begin();
135 BScreen::Workspaces::const_iterator workspace_it_end =
136 screen.getWorkspacesList().end();
137 for (; workspace_it != workspace_it_end; ++workspace_it) {
138 Workspace::Windows::iterator win_it =
139 (*workspace_it)->windowList().begin();
140 Workspace::Windows::iterator win_it_end =
141 (*workspace_it)->windowList().end();
142 for (; win_it != win_it_end; ++win_it) {
143 num += (*win_it)->numClients();
144 }
145
146 }
147 // and count icons
148 BScreen::Icons::const_iterator icon_it = screen.getIconList().begin();
149 BScreen::Icons::const_iterator icon_it_end = screen.getIconList().end();
150 for (; icon_it != icon_it_end; ++icon_it) {
151 num += (*icon_it)->numClients();
152 }
153
154 Window *wl = new (nothrow) Window[num];
155 if (wl == 0) {
156 cerr<<"Fatal: Out of memory, can't allocate for Ewmh client list"<<endl;
157 return;
158 }
159
160 //start the iterator from begining
161 workspace_it = screen.getWorkspacesList().begin();
162 int win=0;
163 for (; workspace_it != workspace_it_end; ++workspace_it) {
164
165 // Fill in array of window ID's
166 Workspace::Windows::const_iterator it =
167 (*workspace_it)->windowList().begin();
168 Workspace::Windows::const_iterator it_end =
169 (*workspace_it)->windowList().end();
170 for (; it != it_end; ++it) {
171 if ((*it)->numClients() == 1)
172 wl[win++] = (*it)->clientWindow();
173 else {
174 // add every client in fluxboxwindow to list window list
175 std::list<WinClient *>::iterator client_it =
176 (*it)->clientList().begin();
177 std::list<WinClient *>::iterator client_it_end =
178 (*it)->clientList().end();
179 for (; client_it != client_it_end; ++client_it)
180 wl[win++] = (*client_it)->window();
181 }
182 }
183 }
184
185 // plus iconified windows
186 icon_it = screen.getIconList().begin();
187 for (; icon_it != icon_it_end; ++icon_it) {
188 FluxboxWindow::ClientList::iterator client_it = (*icon_it)->clientList().begin();
189 FluxboxWindow::ClientList::iterator client_it_end = (*icon_it)->clientList().end();
190 for (; client_it != client_it_end; ++client_it)
191 wl[win++] = (*client_it)->window();
192 }
193
194 //number of windows to show in client list
195 num = win;
196 screen.rootWindow().changeProperty(m_net_client_list,
197 XA_CARDINAL, 32,
198 PropModeReplace, (unsigned char *)wl, num);
199
200 delete [] wl;
201}
202
203void Ewmh::updateWorkspaceNames(BScreen &screen) {
204 XTextProperty text;
205 const size_t number_of_desks = screen.getWorkspaceNames().size();
206
207 char *names[number_of_desks];
208
209 for (size_t i = 0; i < number_of_desks; i++) {
210 names[i] = new char[screen.getWorkspaceNames()[i].size()];
211 strcpy(names[i], screen.getWorkspaceNames()[i].c_str());
212 }
213
214 if (XStringListToTextProperty(names, number_of_desks, &text)) {
215 XSetTextProperty(FbTk::App::instance()->display(), screen.rootWindow().window(),
216 &text, m_net_desktop_names);
217 XFree(text.value);
218 }
219
220 for (size_t i = 0; i < number_of_desks; i++)
221 delete [] names[i];
222}
223
224void Ewmh::updateCurrentWorkspace(BScreen &screen) {
225 size_t workspace = screen.currentWorkspaceID();
226 screen.rootWindow().changeProperty(m_net_current_desktop, XA_CARDINAL, 32, PropModeReplace,
227 (unsigned char *)&workspace, 1);
228
229}
230
231void Ewmh::updateWorkspaceCount(BScreen &screen) {
232 size_t numworkspaces = screen.getCount();
233 screen.rootWindow().changeProperty(m_net_number_of_desktops, XA_CARDINAL, 32, PropModeReplace,
234 (unsigned char *)&numworkspaces, 1);
235}
236
237void Ewmh::updateState(FluxboxWindow &win) {
238 //!! TODO
239}
240
241void Ewmh::updateLayer(FluxboxWindow &win) {
242 //!! TODO _NET_WM_WINDOW_TYPE
243}
244
245void Ewmh::updateHints(FluxboxWindow &win) {
246}
247
248void Ewmh::updateWorkspace(FluxboxWindow &win) {
249 int workspace = win.workspaceNumber();
250 if (win.isStuck())
251 workspace = 0xFFFFFFFF; // appear on all desktops/workspaces
252
253 FluxboxWindow::ClientList::iterator it = win.clientList().begin();
254 FluxboxWindow::ClientList::iterator it_end = win.clientList().end();
255 for (; it != it_end; ++it) {
256 (*it)->changeProperty(m_net_wm_desktop, XA_CARDINAL, 32, PropModeReplace,
257 (unsigned char *)&workspace, 1);
258 }
259
260}
261
262// return true if we did handle the atom here
263bool Ewmh::checkClientMessage(const XClientMessageEvent &ce, BScreen * screen, FluxboxWindow * const win) {
264
265 if (ce.message_type == m_net_wm_desktop) {
266 if (screen == 0)
267 return true;
268 // ce.data.l[0] = workspace number
269 // valid window and workspace number?
270 if (win == 0 ||
271 static_cast<unsigned int>(ce.data.l[0]) >= screen->getCount())
272 return true;
273
274 screen->sendToWorkspace(ce.data.l[0], win, false);
275 return true;
276 } else if (ce.message_type == m_net_wm_state) {
277 if (win == 0)
278 return true;
279 // ce.data.l[0] = the action (remove, add or toggle)
280 // ce.data.l[1] = the first property to alter
281 // ce.data.l[2] = second property to alter (can be zero)
282 if (ce.data.l[0] == STATE_REMOVE) {
283 setState(*win, ce.data.l[1], false);
284 setState(*win, ce.data.l[2], false);
285 } else if (ce.data.l[0] == STATE_ADD) {
286 setState(*win, ce.data.l[1], true);
287 setState(*win, ce.data.l[2], true);
288 } else if (ce.data.l[0] == STATE_TOGGLE) {
289 toggleState(*win, ce.data.l[1]);
290 toggleState(*win, ce.data.l[2]);
291 }
292
293 return true;
294 } else if (ce.message_type == m_net_number_of_desktops) {
295 if (screen == 0)
296 return true;
297 // ce.data.l[0] = number of workspaces
298
299 // no need to alter number of desktops if they are the same
300 // or if requested number of workspace is less than zero
301 if (screen->getCount() == static_cast<unsigned int>(ce.data.l[0]) ||
302 ce.data.l[0] < 0)
303 return true;
304
305 if (screen->getCount() > static_cast<unsigned int>(ce.data.l[0])) {
306 // remove last workspace until we have
307 // the same number of workspaces
308 while (screen->getCount() != static_cast<unsigned int>(ce.data.l[0])) {
309 screen->removeLastWorkspace();
310 if (screen->getCount() == 1) // must have at least one workspace
311 break;
312 }
313 } else { // add workspaces to screen until workspace count match the requested size
314 while (screen->getCount() != static_cast<unsigned int>(ce.data.l[0])) {
315 screen->addWorkspace();
316 }
317 }
318
319 return true;
320 } else if (ce.message_type == m_net_current_desktop) {
321 if (screen == 0)
322 return true;
323 // ce.data.l[0] = workspace number
324
325 // prevent out of range value
326 if (static_cast<unsigned int>(ce.data.l[0]) >= screen->getCount())
327 return true;
328 screen->changeWorkspaceID(ce.data.l[0]);
329 return true;
330 } else if (ce.message_type == m_net_active_window) {
331
332 // make sure we have a valid window
333 if (win == 0)
334 return true;
335 // ce.window = window to focus
336
337 win->setInputFocus();
338 return true;
339 } else if (ce.message_type == m_net_close_window) {
340 if (win == 0)
341 return true;
342 // ce.window = window to close (which in this case is the win argument)
343 win->close();
344 return true;
345 } else if (ce.message_type == m_net_moveresize_window) {
346 if (win == 0)
347 return true;
348 // ce.data.l[0] = gravity and flags
349 // ce.data.l[1] = x
350 // ce.data.l[2] = y
351 // ce.data.l[3] = width
352 // ce.data.l[4] = height
353 // TODO: gravity and flags
354 win->moveResize(ce.data.l[1], ce.data.l[2],
355 ce.data.l[3], ce.data.l[4]);
356 return true;
357 }
358
359 // we didn't handle the ce.message_type here
360 return false;
361}
362
363
364bool Ewmh::propertyNotify(FluxboxWindow &win, Atom the_property) {
365 if (the_property == m_net_wm_strut) {
366 updateStrut(win);
367 return true;
368 }
369
370 return false;
371}
372
373void Ewmh::createAtoms() {
374 Display *disp = FbTk::App::instance()->display();
375 m_net_supported = XInternAtom(disp, "_NET_SUPPORTED", False);
376 m_net_client_list = XInternAtom(disp, "_NET_CLIENT_LIST", False);
377 m_net_client_list_stacking = XInternAtom(disp, "_NET_CLIENT_LIST_STACKING", False);
378 m_net_number_of_desktops = XInternAtom(disp, "_NET_NUMBER_OF_DESKTOPS", False);
379 m_net_desktop_geometry = XInternAtom(disp, "_NET_DESKTOP_GEOMETRY", False);
380 m_net_desktop_viewport = XInternAtom(disp, "_NET_DESKTOP_VIEWPORT", False);
381 m_net_current_desktop = XInternAtom(disp, "_NET_CURRENT_DESKTOP", False);
382 m_net_desktop_names = XInternAtom(disp, "_NET_DESKTOP_NAMES", False);
383 m_net_active_window = XInternAtom(disp, "_NET_ACTIVE_WINDOW", False);
384 m_net_workarea = XInternAtom(disp, "_NET_WORKAREA", False);
385 m_net_supporting_wm_check = XInternAtom(disp, "_NET_SUPPORTING_WM_CHECK", False);
386 m_net_virtual_roots = XInternAtom(disp, "_NET_VIRTUAL_ROOTS", False);
387
388 m_net_close_window = XInternAtom(disp, "_NET_CLOSE_WINDOW", False);
389 m_net_moveresize_window = XInternAtom(disp, "_NET_MOVERESIZE_WINDOW", False);
390
391 // TODO: implement this one
392 m_net_wm_moveresize = XInternAtom(disp, "_NET_WM_MOVERESIZE", False);
393
394 m_net_properties = XInternAtom(disp, "_NET_PROPERTIES", False);
395 m_net_wm_name = XInternAtom(disp, "_NET_WM_NAME", False);
396 m_net_wm_desktop = XInternAtom(disp, "_NET_WM_DESKTOP", False);
397 m_net_wm_window_type = XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False);
398
399 // state atom and the supported state atoms
400 m_net_wm_state = XInternAtom(disp, "_NET_WM_STATE", False);
401 m_net_wm_state_sticky = XInternAtom(disp, "_NET_WM_STATE_STICKY", False);
402 m_net_wm_state_shaded = XInternAtom(disp, "_NET_WM_STATE_SHADED", False);
403
404 m_net_wm_strut = XInternAtom(disp, "_NET_WM_STRUT", False);
405 m_net_wm_icon_geometry = XInternAtom(disp, "_NET_WM_ICON_GEOMETRY", False);
406 m_net_wm_icon = XInternAtom(disp, "_NET_WM_ICON", False);
407 m_net_wm_pid = XInternAtom(disp, "_NET_WM_PID", False);
408 m_net_wm_handled_icons = XInternAtom(disp, "_NET_WM_HANDLED_ICONS", False);
409
410 m_net_wm_ping = XInternAtom(disp, "_NET_WM_PING", False);
411}
412
413// set window state
414void Ewmh::setState(FluxboxWindow &win, Atom state, bool value) const {
415
416 if (state == m_net_wm_state_sticky) { // STICKY
417 if (value && !win.isStuck() ||
418 (!value && win.isStuck()))
419 win.stick();
420 } else if (state == m_net_wm_state_shaded) { // SHADED
421 if ((value && !win.isShaded()) ||
422 (!value && win.isShaded()))
423 win.shade();
424 }
425
426}
427
428// toggle window state
429void Ewmh::toggleState(FluxboxWindow &win, Atom state) const {
430 if (state == m_net_wm_state_sticky) {
431 win.stick();
432 } else if (state == m_net_wm_state_shaded)
433 win.shade();
434}
435
436
437void Ewmh::updateStrut(FluxboxWindow &win) {
438 Atom ret_type = 0;
439 int fmt = 0;
440 unsigned long nitems = 0, bytes_after = 0;
441 long *data = 0;
442 if (win.winClient().property(m_net_wm_strut, 0, 4, False, XA_CARDINAL,
443 &ret_type, &fmt, &nitems, &bytes_after,
444 (unsigned char **) &data) && data) {
445#ifdef DEBUG
446 cerr<<__FILE__<<"("<<__FUNCTION__<<"): Strut: "<<data[0]<<", "<<data[1]<<", "<<
447 data[2]<<", "<<data[3]<<endl;
448#endif // DEBUG
449 win.setStrut(win.screen().requestStrut(data[0], data[1], data[2], data[3]));
450 win.screen().updateAvailableWorkspaceArea();
451 }
452
453}