/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/rdesktop/ewmhints.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/ewmhints.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1177 - (show annotations)
Tue Mar 21 14:42:25 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 11320 byte(s)
Support for window groups and modal windows.

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3
4 Support functions for Extended Window Manager Hints,
5 http://www.freedesktop.org/wiki/Standards_2fwm_2dspec
6
7 Copyright (C) Peter Astrand <astrand@cendio.se> 2005
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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include <X11/Xlib.h>
25 #include <X11/Xatom.h>
26 #include <X11/Xutil.h>
27 #include "rdesktop.h"
28
29 #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
30 #define _NET_WM_STATE_ADD 1 /* add/set property */
31 #define _NET_WM_STATE_TOGGLE 2 /* toggle property */
32
33 extern Display *g_display;
34
35 static Atom g_net_wm_state_maximized_vert_atom, g_net_wm_state_maximized_horz_atom,
36 g_net_wm_state_hidden_atom, g_net_wm_name_atom, g_utf8_string_atom,
37 g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom, g_net_wm_state_modal_atom;
38
39 Atom g_net_wm_state_atom, g_net_wm_desktop_atom;
40
41 /*
42 Get window property value (32 bit format)
43 Returns zero on success, -1 on error
44 */
45 static int
46 get_property_value(Window wnd, char *propname, long max_length,
47 unsigned long *nitems_return, unsigned char **prop_return, int nowarn)
48 {
49 int result;
50 Atom property;
51 Atom actual_type_return;
52 int actual_format_return;
53 unsigned long bytes_after_return;
54
55 property = XInternAtom(g_display, propname, True);
56 if (property == None)
57 {
58 fprintf(stderr, "Atom %s does not exist\n", propname);
59 return (-1);
60 }
61
62 result = XGetWindowProperty(g_display, wnd, property, 0, /* long_offset */
63 max_length, /* long_length */
64 False, /* delete */
65 AnyPropertyType, /* req_type */
66 &actual_type_return,
67 &actual_format_return,
68 nitems_return, &bytes_after_return, prop_return);
69
70 if (result != Success)
71 {
72 fprintf(stderr, "XGetWindowProperty failed\n");
73 return (-1);
74 }
75
76 if (actual_type_return == None || actual_format_return == 0)
77 {
78 if (!nowarn)
79 fprintf(stderr, "Window is missing property %s\n", propname);
80 return (-1);
81 }
82
83 if (bytes_after_return)
84 {
85 fprintf(stderr, "%s is too big for me\n", propname);
86 return (-1);
87 }
88
89 if (actual_format_return != 32)
90 {
91 fprintf(stderr, "%s has bad format\n", propname);
92 return (-1);
93 }
94
95 return (0);
96 }
97
98 /*
99 Get current desktop number
100 Returns -1 on error
101 */
102 static int
103 get_current_desktop(void)
104 {
105 unsigned long nitems_return;
106 unsigned char *prop_return;
107 int current_desktop;
108
109 if (get_property_value
110 (DefaultRootWindow(g_display), "_NET_CURRENT_DESKTOP", 1, &nitems_return,
111 &prop_return, 0) < 0)
112 return (-1);
113
114 if (nitems_return != 1)
115 {
116 fprintf(stderr, "_NET_CURRENT_DESKTOP has bad length\n");
117 return (-1);
118 }
119
120 current_desktop = *prop_return;
121 XFree(prop_return);
122 return current_desktop;
123 }
124
125 /*
126 Get workarea geometry
127 Returns zero on success, -1 on error
128 */
129
130 int
131 get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height)
132 {
133 int current_desktop;
134 unsigned long nitems_return;
135 unsigned char *prop_return;
136 uint32 *return_words;
137 const uint32 net_workarea_x_offset = 0;
138 const uint32 net_workarea_y_offset = 1;
139 const uint32 net_workarea_width_offset = 2;
140 const uint32 net_workarea_height_offset = 3;
141 const uint32 max_prop_length = 32 * 4; /* Max 32 desktops */
142
143 if (get_property_value
144 (DefaultRootWindow(g_display), "_NET_WORKAREA", max_prop_length, &nitems_return,
145 &prop_return, 0) < 0)
146 return (-1);
147
148 if (nitems_return % 4)
149 {
150 fprintf(stderr, "_NET_WORKAREA has odd length\n");
151 return (-1);
152 }
153
154 current_desktop = get_current_desktop();
155
156 if (current_desktop < 0)
157 return -1;
158
159 return_words = (uint32 *) prop_return;
160
161 *x = return_words[current_desktop * 4 + net_workarea_x_offset];
162 *y = return_words[current_desktop * 4 + net_workarea_y_offset];
163 *width = return_words[current_desktop * 4 + net_workarea_width_offset];
164 *height = return_words[current_desktop * 4 + net_workarea_height_offset];
165
166 XFree(prop_return);
167
168 return (0);
169
170 }
171
172
173
174 void
175 ewmh_init()
176 {
177 /* FIXME: Use XInternAtoms */
178 g_net_wm_state_maximized_vert_atom =
179 XInternAtom(g_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
180 g_net_wm_state_maximized_horz_atom =
181 XInternAtom(g_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
182 g_net_wm_state_hidden_atom = XInternAtom(g_display, "_NET_WM_STATE_HIDDEN", False);
183 g_net_wm_state_skip_taskbar_atom =
184 XInternAtom(g_display, "_NET_WM_STATE_SKIP_TASKBAR", False);
185 g_net_wm_state_skip_pager_atom = XInternAtom(g_display, "_NET_WM_STATE_SKIP_PAGER", False);
186 g_net_wm_state_modal_atom = XInternAtom(g_display, "_NET_WM_STATE_MODAL", False);
187 g_net_wm_state_atom = XInternAtom(g_display, "_NET_WM_STATE", False);
188 g_net_wm_desktop_atom = XInternAtom(g_display, "_NET_WM_DESKTOP", False);
189 g_net_wm_name_atom = XInternAtom(g_display, "_NET_WM_NAME", False);
190 g_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);
191 }
192
193
194 /*
195 Get the window state: normal/minimized/maximized.
196 */
197 #ifndef MAKE_PROTO
198 int
199 ewmh_get_window_state(Window w)
200 {
201 unsigned long nitems_return;
202 unsigned char *prop_return;
203 uint32 *return_words;
204 unsigned long item;
205 BOOL maximized_vert, maximized_horz, hidden;
206
207 maximized_vert = maximized_horz = hidden = False;
208
209 if (get_property_value(w, "_NET_WM_STATE", 64, &nitems_return, &prop_return, 0) < 0)
210 return SEAMLESSRDP_NORMAL;
211
212 return_words = (uint32 *) prop_return;
213
214 for (item = 0; item < nitems_return; item++)
215 {
216 if (return_words[item] == g_net_wm_state_maximized_vert_atom)
217 maximized_vert = True;
218 if (return_words[item] == g_net_wm_state_maximized_horz_atom)
219 maximized_horz = True;
220 if (return_words[item] == g_net_wm_state_hidden_atom)
221 hidden = True;
222 }
223
224 XFree(prop_return);
225
226 if (maximized_vert && maximized_horz)
227 return SEAMLESSRDP_MAXIMIZED;
228 else if (hidden)
229 return SEAMLESSRDP_MINIMIZED;
230 else
231 return SEAMLESSRDP_NORMAL;
232 }
233
234 static int
235 ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
236 {
237 Status status;
238 XEvent xevent;
239
240 unsigned long nitems;
241 unsigned char *props;
242 uint32 *state;
243
244 /* The spec states that the window manager must respect any
245 _NET_WM_STATE attributes on a withdrawn window. In order words, we
246 modify the attributes directly for withdrawn windows and ask the WM
247 to do it for active windows. */
248 if ((get_property_value(wnd, "WM_STATE", 64, &nitems, &props, 1) < 0)
249 || ((state = (uint32 *) props)[0] == WithdrawnState))
250 {
251 if (add)
252 {
253 Atom atoms[2];
254
255 atoms[0] = atom1;
256 nitems = 1;
257 if (atom2)
258 {
259 atoms[1] = atom2;
260 nitems = 2;
261 }
262
263 XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
264 32, PropModeAppend, (unsigned char *) atoms, nitems);
265 }
266 else
267 {
268 Atom *atoms;
269 int i;
270
271 if (get_property_value(wnd, "_NET_WM_STATE", 64, &nitems, &props, 1) < 0)
272 return 0;
273
274 atoms = (Atom *) props;
275
276 for (i = 0; i < nitems; i++)
277 {
278 if ((atoms[i] == atom1) || (atom2 && (atoms[i] == atom2)))
279 {
280 if (i != (nitems - 1))
281 memmove(&atoms[i], &atoms[i + 1],
282 sizeof(Atom) * (nitems - i - 1));
283 nitems--;
284 i--;
285 }
286 }
287
288 XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
289 32, PropModeReplace, (unsigned char *) atoms, nitems);
290 }
291
292 return 0;
293 }
294
295 xevent.type = ClientMessage;
296 xevent.xclient.window = wnd;
297 xevent.xclient.message_type = g_net_wm_state_atom;
298 xevent.xclient.format = 32;
299 if (add)
300 xevent.xclient.data.l[0] = _NET_WM_STATE_ADD;
301 else
302 xevent.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
303 xevent.xclient.data.l[1] = atom1;
304 xevent.xclient.data.l[2] = atom2;
305 xevent.xclient.data.l[3] = 0;
306 xevent.xclient.data.l[4] = 0;
307 status = XSendEvent(g_display, DefaultRootWindow(g_display), False,
308 SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
309 if (!status)
310 return -1;
311
312 return 0;
313 }
314
315 /*
316 Set the window state: normal/minimized/maximized.
317 Returns -1 on failure.
318 */
319 int
320 ewmh_change_state(Window wnd, int state)
321 {
322 /*
323 * Deal with the max atoms
324 */
325 if (state == SEAMLESSRDP_MAXIMIZED)
326 {
327 if (ewmh_modify_state
328 (wnd, 1, g_net_wm_state_maximized_vert_atom,
329 g_net_wm_state_maximized_horz_atom) < 0)
330 return -1;
331 }
332 else
333 {
334 if (ewmh_modify_state
335 (wnd, 0, g_net_wm_state_maximized_vert_atom,
336 g_net_wm_state_maximized_horz_atom) < 0)
337 return -1;
338 }
339
340 return 0;
341 }
342
343
344 int
345 ewmh_get_window_desktop(Window wnd)
346 {
347 unsigned long nitems_return;
348 unsigned char *prop_return;
349 int desktop;
350
351 if (get_property_value(wnd, "_NET_WM_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0)
352 return (-1);
353
354 if (nitems_return != 1)
355 {
356 fprintf(stderr, "_NET_WM_DESKTOP has bad length\n");
357 return (-1);
358 }
359
360 desktop = *prop_return;
361 XFree(prop_return);
362 return desktop;
363 }
364
365
366 int
367 ewmh_move_to_desktop(Window wnd, unsigned int desktop)
368 {
369 Status status;
370 XEvent xevent;
371
372 xevent.type = ClientMessage;
373 xevent.xclient.window = wnd;
374 xevent.xclient.message_type = g_net_wm_desktop_atom;
375 xevent.xclient.format = 32;
376 xevent.xclient.data.l[0] = desktop;
377 xevent.xclient.data.l[1] = 0;
378 xevent.xclient.data.l[2] = 0;
379 xevent.xclient.data.l[3] = 0;
380 xevent.xclient.data.l[4] = 0;
381 status = XSendEvent(g_display, DefaultRootWindow(g_display), False,
382 SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
383 if (!status)
384 return -1;
385
386 return 0;
387 }
388
389 void
390 ewmh_set_wm_name(Window wnd, const char *title)
391 {
392 int len;
393
394 len = strlen(title);
395 XChangeProperty(g_display, wnd, g_net_wm_name_atom, g_utf8_string_atom,
396 8, PropModeReplace, (unsigned char *) title, len);
397 }
398
399
400 int
401 ewmh_set_window_popup(Window wnd)
402 {
403 if (ewmh_modify_state
404 (wnd, 1, g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom) < 0)
405 return -1;
406 return 0;
407 }
408
409 int
410 ewmh_set_window_modal(Window wnd)
411 {
412 if (ewmh_modify_state(wnd, 1, g_net_wm_state_modal_atom, 0) < 0)
413 return -1;
414 return 0;
415 }
416
417 #endif /* MAKE_PROTO */
418
419
420 #if 0
421
422 /* FIXME: _NET_MOVERESIZE_WINDOW is for pagers, not for
423 applications. We should implement _NET_WM_MOVERESIZE instead */
424
425 int
426 ewmh_net_moveresize_window(Window wnd, int x, int y, int width, int height)
427 {
428 Status status;
429 XEvent xevent;
430 Atom moveresize;
431
432 moveresize = XInternAtom(g_display, "_NET_MOVERESIZE_WINDOW", False);
433 if (!moveresize)
434 {
435 return -1;
436 }
437
438 xevent.type = ClientMessage;
439 xevent.xclient.window = wnd;
440 xevent.xclient.message_type = moveresize;
441 xevent.xclient.format = 32;
442 xevent.xclient.data.l[0] = StaticGravity | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11);
443 xevent.xclient.data.l[1] = x;
444 xevent.xclient.data.l[2] = y;
445 xevent.xclient.data.l[3] = width;
446 xevent.xclient.data.l[4] = height;
447
448 status = XSendEvent(g_display, DefaultRootWindow(g_display), False,
449 SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
450 if (!status)
451 return -1;
452 return 0;
453 }
454
455 #endif

  ViewVC Help
Powered by ViewVC 1.1.26