diff options
Diffstat (limited to 'src/Ewmh.cc')
-rw-r--r-- | src/Ewmh.cc | 453 |
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> | ||
34 | using namespace std; | ||
35 | |||
36 | Ewmh::Ewmh() { | ||
37 | createAtoms(); | ||
38 | enableUpdate(); | ||
39 | } | ||
40 | |||
41 | Ewmh::~Ewmh() { | ||
42 | while (!m_windows.empty()) { | ||
43 | XDestroyWindow(FbTk::App::instance()->display(), m_windows.back()); | ||
44 | m_windows.pop_back(); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | void 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 | |||
98 | void 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 | |||
130 | void 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 | |||
203 | void 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 | |||
224 | void 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 | |||
231 | void 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 | |||
237 | void Ewmh::updateState(FluxboxWindow &win) { | ||
238 | //!! TODO | ||
239 | } | ||
240 | |||
241 | void Ewmh::updateLayer(FluxboxWindow &win) { | ||
242 | //!! TODO _NET_WM_WINDOW_TYPE | ||
243 | } | ||
244 | |||
245 | void Ewmh::updateHints(FluxboxWindow &win) { | ||
246 | } | ||
247 | |||
248 | void 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 | ||
263 | bool 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 | |||
364 | bool 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 | |||
373 | void 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 | ||
414 | void 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 | ||
429 | void 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 | |||
437 | void 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 | } | ||