diff options
Diffstat (limited to 'src/Ewmh.cc')
-rw-r--r-- | src/Ewmh.cc | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/src/Ewmh.cc b/src/Ewmh.cc new file mode 100644 index 0000000..87e55bf --- /dev/null +++ b/src/Ewmh.cc | |||
@@ -0,0 +1,322 @@ | |||
1 | // Ewmh.cc for FbPager | ||
2 | // Copyright (c) 2004 Henrik Kinnunen (fluxgen at users.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 | #include "Ewmh.hh" | ||
23 | |||
24 | #include "Pager.hh" | ||
25 | #include "WindowHint.hh" | ||
26 | |||
27 | #include "FbTk/App.hh" | ||
28 | #include "FbTk/FbWindow.hh" | ||
29 | #include "FbRootWindow.hh" | ||
30 | |||
31 | #include <X11/Xatom.h> | ||
32 | |||
33 | #include <iostream> | ||
34 | #include <vector> | ||
35 | #include <sys/types.h> | ||
36 | #include <unistd.h> | ||
37 | #include <memory> | ||
38 | |||
39 | using namespace std; | ||
40 | |||
41 | namespace FbPager { | ||
42 | |||
43 | class Ewmh_priv { | ||
44 | public: | ||
45 | Ewmh_priv() { | ||
46 | Display *disp = FbTk::App::instance()->display(); | ||
47 | state_skip_pager = XInternAtom(disp, "_NET_WM_STATE_SKIP_PAGER", False); | ||
48 | state_skip_taskbar = XInternAtom(disp, "_NET_WM_STATE_SKIP_TASKBAR", False); | ||
49 | state_sticky = XInternAtom(disp, "_NET_WM_STATE_STICKY", False); | ||
50 | state_hidden = XInternAtom(disp, "_NET_WM_STATE_HIDDEN", False); | ||
51 | state_shaded = XInternAtom(disp, "_NET_WM_STATE_SHADED", False); | ||
52 | state_above = XInternAtom(disp, "_NET_WM_STATE_ABOVE", False); | ||
53 | state_below = XInternAtom(disp, "_NET_WM_STATE_BELOW", False); | ||
54 | wm_desktop = XInternAtom(disp, "_NET_WM_DESKTOP", False); | ||
55 | wm_state = XInternAtom(disp, "_NET_WM_STATE", False); | ||
56 | wm_pid = XInternAtom(disp, "_NET_WM_PID", False); | ||
57 | wm_type = XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False); | ||
58 | type_dock = XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DOCK", False); | ||
59 | number_of_desktops = XInternAtom(disp, "_NET_NUMBER_OF_DESKTOPS", False); | ||
60 | current_desktop = XInternAtom(disp, "_NET_CURRENT_DESKTOP", False); | ||
61 | clientlist = XInternAtom(disp, "_NET_CLIENT_LIST", False); | ||
62 | moveresize_window = XInternAtom(disp, "_NET_MOVERESIZE_WINDOW", False); | ||
63 | active_window = XInternAtom(disp, "_NET_ACTIVE_WINDOW", False); | ||
64 | close_window = XInternAtom(disp, "_NET_CLOSE_WINDOW", False); | ||
65 | desktop_layout = XInternAtom(disp, "_NET_DESKTOP_LAYOUT", False); | ||
66 | } | ||
67 | Atom state_skip_pager, state_skip_taskbar, state_sticky, | ||
68 | state_hidden, state_shaded, state_above, state_below; | ||
69 | Atom wm_desktop, wm_state, wm_pid, wm_type; | ||
70 | Atom type_dock; | ||
71 | Atom number_of_desktops, current_desktop; | ||
72 | Atom clientlist; | ||
73 | Atom moveresize_window; | ||
74 | Atom active_window; | ||
75 | Atom close_window; | ||
76 | Atom above, below; | ||
77 | Atom desktop_layout; | ||
78 | }; | ||
79 | |||
80 | Ewmh::Ewmh(): | ||
81 | m_support(true), | ||
82 | m_data(new Ewmh_priv()) { | ||
83 | |||
84 | //!! TODO | ||
85 | // check for ewmh support | ||
86 | |||
87 | } | ||
88 | |||
89 | Ewmh::~Ewmh() { | ||
90 | } | ||
91 | |||
92 | |||
93 | void Ewmh::setFocus(FbTk::FbWindow &win) { | ||
94 | |||
95 | } | ||
96 | |||
97 | void Ewmh::setDesktopLayout(FbTk::FbWindow &root, | ||
98 | Orientation orientation, | ||
99 | Corner starting_corner, | ||
100 | unsigned int columns, unsigned int rows) { | ||
101 | unsigned int data[4] = { orientation, columns, rows, starting_corner }; | ||
102 | root.changeProperty(m_data->desktop_layout, | ||
103 | XA_CARDINAL, | ||
104 | 32, | ||
105 | PropModeReplace, | ||
106 | (unsigned char*)data, 4 ); | ||
107 | } | ||
108 | |||
109 | void Ewmh::moveResize(FbTk::FbWindow &win) { | ||
110 | |||
111 | // We can't do this yet, there is a bug in fluxbox 0.9.8 | ||
112 | // and this makes it crash (it's fixed in cvs though) | ||
113 | /* | ||
114 | Display *disp = FbTk::App::instance()->display(); | ||
115 | XEvent event; | ||
116 | event.xclient.display = disp; | ||
117 | event.xclient.type = ClientMessage; | ||
118 | event.xclient.window = RootWindow(disp, win.screenNumber()); | ||
119 | event.xclient.message_type = m_data->moveresize_window; | ||
120 | event.xclient.format = 32; | ||
121 | event.xclient.data.l[0] = 0; | ||
122 | event.xclient.data.l[1] = win.x(); | ||
123 | event.xclient.data.l[2] = win.y(); | ||
124 | event.xclient.data.l[3] = win.width(); | ||
125 | event.xclient.data.l[4] = win.height(); | ||
126 | |||
127 | XSendEvent(disp, event.xclient.window, False, SubstructureNotifyMask, &event); | ||
128 | */ | ||
129 | } | ||
130 | |||
131 | void Ewmh::sendToWorkspace(FbTk::FbWindow &win, int workspace) { | ||
132 | |||
133 | } | ||
134 | |||
135 | void Ewmh::closeWindow(FbTk::FbWindow &win) { | ||
136 | Display *disp = FbTk::App::instance()->display(); | ||
137 | XEvent event; | ||
138 | event.xclient.display = disp; | ||
139 | event.xclient.type = ClientMessage; | ||
140 | event.xclient.window = win.window(); | ||
141 | event.xclient.message_type = m_data->close_window; | ||
142 | event.xclient.format = 32; | ||
143 | event.xclient.data.l[0] = 0; | ||
144 | XSendEvent(disp, RootWindow(disp, DefaultScreen(disp)), False, SubstructureNotifyMask, &event); | ||
145 | } | ||
146 | |||
147 | bool Ewmh::clientMessage(Pager &pager, XClientMessageEvent &event) { | ||
148 | if (!m_support) | ||
149 | return false; | ||
150 | |||
151 | if (event.message_type == m_data->current_desktop) { | ||
152 | pager.setCurrentWorkspace(event.data.l[0]); | ||
153 | return true; | ||
154 | } else if (event.message_type == m_data->number_of_desktops) { | ||
155 | pager.updateWorkspaceCount(event.data.l[0]); | ||
156 | return true; | ||
157 | } else if (event.message_type == m_data->wm_desktop) { | ||
158 | pager.moveToWorkspace(event.window, event.data.l[0]); | ||
159 | return true; | ||
160 | } else if (event.message_type == m_data->clientlist) { | ||
161 | return true; | ||
162 | } else if (event.message_type == m_data->active_window) { | ||
163 | pager.setFocusedWindow(event.window); | ||
164 | return true; | ||
165 | } | ||
166 | |||
167 | return false; | ||
168 | } | ||
169 | |||
170 | void Ewmh::changeWorkspace(int screen_num, int workspace) { | ||
171 | Display *disp = FbTk::App::instance()->display(); | ||
172 | XEvent event; | ||
173 | event.xclient.display = disp; | ||
174 | event.xclient.type = ClientMessage; | ||
175 | event.xclient.window = RootWindow(disp, screen_num); | ||
176 | event.xclient.message_type = m_data->current_desktop; | ||
177 | event.xclient.format = 32; | ||
178 | event.xclient.data.l[0] = workspace; | ||
179 | XSendEvent(disp, event.xclient.window, False, SubstructureNotifyMask, &event); | ||
180 | } | ||
181 | |||
182 | void Ewmh::setHints(FbTk::FbWindow &win, WindowHint &hint) { | ||
183 | |||
184 | int data = getpid(); | ||
185 | win.changeProperty(m_data->wm_pid, | ||
186 | XA_CARDINAL, | ||
187 | 32, | ||
188 | PropModeReplace, | ||
189 | (unsigned char *)&data, 1); | ||
190 | |||
191 | if (hint.flags() & WindowHint::WHINT_STICKY) { | ||
192 | data = 0xFFFFFFFF; | ||
193 | win.changeProperty(m_data->wm_desktop, | ||
194 | XA_CARDINAL, | ||
195 | 32, | ||
196 | PropModeReplace, | ||
197 | (unsigned char *)&data, 1); | ||
198 | } | ||
199 | |||
200 | if (hint.flags() & WindowHint::WHINT_TYPE_DOCK) { | ||
201 | cerr << "Setting type dock." << endl; | ||
202 | Atom data = m_data->type_dock; | ||
203 | win.changeProperty(m_data->wm_type, | ||
204 | XA_ATOM, | ||
205 | 32, | ||
206 | PropModeReplace, | ||
207 | (unsigned char *)&data, 1); | ||
208 | } | ||
209 | |||
210 | std::vector<Atom> states; | ||
211 | if (hint.flags() & WindowHint::WHINT_SKIP_TASKBAR) | ||
212 | states.push_back(m_data->state_skip_taskbar); | ||
213 | if (hint.flags() & WindowHint::WHINT_SKIP_PAGER) | ||
214 | states.push_back(m_data->state_skip_pager); | ||
215 | if (hint.flags() & WindowHint::WHINT_STICKY) | ||
216 | states.push_back(m_data->state_sticky); | ||
217 | if (hint.flags() & WindowHint::WHINT_HIDDEN) | ||
218 | states.push_back(m_data->state_hidden); | ||
219 | if (hint.flags() & WindowHint::WHINT_LAYER_TOP){ | ||
220 | states.push_back(m_data->state_above); | ||
221 | cerr << "Setting state above." << endl; | ||
222 | } | ||
223 | if (hint.flags() & WindowHint::WHINT_LAYER_BOTTOM) { | ||
224 | cerr<< "Setting state bottom." << endl; | ||
225 | states.push_back(m_data->state_below); | ||
226 | } | ||
227 | |||
228 | Atom *state_atoms = new Atom[states.size()]; | ||
229 | for (size_t i=0; i < states.size(); ++i) | ||
230 | state_atoms[i] = states[i]; | ||
231 | |||
232 | win.changeProperty(m_data->wm_state, | ||
233 | XA_ATOM, | ||
234 | 32, | ||
235 | PropModeReplace, | ||
236 | (unsigned char *)state_atoms, states.size()); | ||
237 | delete [] state_atoms; | ||
238 | } | ||
239 | |||
240 | |||
241 | struct PropT { | ||
242 | PropT(unsigned char *data, unsigned int num):data(data), num(num) { } | ||
243 | ~PropT() { | ||
244 | if (data != 0) | ||
245 | XFree(data); | ||
246 | } | ||
247 | unsigned char *data; | ||
248 | unsigned int num; | ||
249 | }; | ||
250 | |||
251 | typedef std::auto_ptr<PropT> PropTPtr; | ||
252 | |||
253 | PropT *property(const FbTk::FbWindow &win, Atom atom, | ||
254 | Atom type, unsigned int num) { | ||
255 | Atom ret_type; | ||
256 | int fmt; | ||
257 | unsigned long nitems, bytes_after; | ||
258 | unsigned char *data = 0; | ||
259 | win.property(atom, | ||
260 | 0, num, | ||
261 | False, | ||
262 | type, | ||
263 | &ret_type, &fmt, | ||
264 | &nitems, | ||
265 | &bytes_after, | ||
266 | &data); | ||
267 | return new PropT(data, nitems); | ||
268 | |||
269 | } | ||
270 | |||
271 | void Ewmh::getHints(const FbTk::FbWindow &win, WindowHint &hint) const { | ||
272 | PropTPtr p(property(win, | ||
273 | m_data->wm_state, | ||
274 | XA_ATOM, 0x7FFFFFFF)); | ||
275 | |||
276 | if (p.get() != 0 && p->data != 0) { | ||
277 | |||
278 | Atom *states = (Atom *)(p->data); | ||
279 | for (int i=0; i<p->num; ++i) { | ||
280 | if (states[i] == m_data->state_skip_pager) | ||
281 | hint.add(WindowHint::WHINT_SKIP_PAGER); | ||
282 | else if (states[i] == m_data->state_skip_taskbar) | ||
283 | hint.add(WindowHint::WHINT_SKIP_TASKBAR); | ||
284 | else if (states[i] == m_data->state_sticky) | ||
285 | hint.add(WindowHint::WHINT_STICKY); | ||
286 | else if (states[i] == m_data->state_shaded) | ||
287 | hint.add(WindowHint::WHINT_SHADED); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | p.reset(property(win, m_data->wm_type, | ||
292 | XA_ATOM, 0x7FFFFFFF)); | ||
293 | if (p.get() != 0 && p->data != 0) { | ||
294 | // we only care about the first type. | ||
295 | Atom *atoms = (Atom *)p->data; | ||
296 | if (atoms[0] == m_data->type_dock) | ||
297 | hint.add(WindowHint::WHINT_TYPE_DOCK); | ||
298 | } | ||
299 | |||
300 | p.reset(property(win, m_data->wm_desktop, | ||
301 | XA_CARDINAL, 1)); | ||
302 | if (p.get() != 0 && p->data != 0) { | ||
303 | int workspace = static_cast<int>(*(p->data)); | ||
304 | hint.setWorkspace(workspace); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | int Ewmh::numberOfWorkspaces(int screen_num) const { | ||
309 | |||
310 | PropTPtr p(property(FbRootWindow(screen_num), | ||
311 | m_data->number_of_desktops, | ||
312 | XA_CARDINAL, 1)); | ||
313 | if (p.get() == 0 || p->data == 0) | ||
314 | return 0; | ||
315 | else { | ||
316 | int num = static_cast<int>(*(p->data)); | ||
317 | return num; | ||
318 | } | ||
319 | |||
320 | } | ||
321 | |||
322 | } // end namespace FbPager | ||