/[rdesktop]/sourceforge.net/trunk/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/trunk/rdesktop/ewmhints.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1225 - (show annotations)
Sun Apr 9 20:22:11 2006 UTC (18 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 11420 byte(s)
ewmh_modify_state: Prevent using uninitialized state; simplify code.

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 int result;
241 unsigned long nitems;
242 unsigned char *props;
243 uint32 state = WithdrawnState;
244
245 /* The spec states that the window manager must respect any
246 _NET_WM_STATE attributes on a withdrawn window. In order words, we
247 modify the attributes directly for withdrawn windows and ask the WM
248 to do it for active windows. */
249 result = get_property_value(wnd, "WM_STATE", 64, &nitems, &props, 1);
250 if ((result >= 0) && nitems)
251 {
252 state = *(uint32 *) props;
253 XFree(props);
254 }
255
256 if (state == WithdrawnState)
257 {
258 if (add)
259 {
260 Atom atoms[2];
261
262 atoms[0] = atom1;
263 nitems = 1;
264 if (atom2)
265 {
266 atoms[1] = atom2;
267 nitems = 2;
268 }
269
270 XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
271 32, PropModeAppend, (unsigned char *) atoms, nitems);
272 }
273 else
274 {
275 Atom *atoms;
276 int i;
277
278 if (get_property_value(wnd, "_NET_WM_STATE", 64, &nitems, &props, 1) < 0)
279 return 0;
280
281 atoms = (Atom *) props;
282
283 for (i = 0; i < nitems; i++)
284 {
285 if ((atoms[i] == atom1) || (atom2 && (atoms[i] == atom2)))
286 {
287 if (i != (nitems - 1))
288 memmove(&atoms[i], &atoms[i + 1],
289 sizeof(Atom) * (nitems - i - 1));
290 nitems--;
291 i--;
292 }
293 }
294
295 XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
296 32, PropModeReplace, (unsigned char *) atoms, nitems);
297
298 XFree(props);
299 }
300
301 return 0;
302 }
303
304 xevent.type = ClientMessage;
305 xevent.xclient.window = wnd;
306 xevent.xclient.message_type = g_net_wm_state_atom;
307 xevent.xclient.format = 32;
308 if (add)
309 xevent.xclient.data.l[0] = _NET_WM_STATE_ADD;
310 else
311 xevent.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
312 xevent.xclient.data.l[1] = atom1;
313 xevent.xclient.data.l[2] = atom2;
314 xevent.xclient.data.l[3] = 0;
315 xevent.xclient.data.l[4] = 0;
316 status = XSendEvent(g_display, DefaultRootWindow(g_display), False,
317 SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
318 if (!status)
319 return -1;
320
321 return 0;
322 }
323
324 /*
325 Set the window state: normal/minimized/maximized.
326 Returns -1 on failure.
327 */
328 int
329 ewmh_change_state(Window wnd, int state)
330 {
331 /*
332 * Deal with the max atoms
333 */
334 if (state == SEAMLESSRDP_MAXIMIZED)
335 {
336 if (ewmh_modify_state
337 (wnd, 1, g_net_wm_state_maximized_vert_atom,
338 g_net_wm_state_maximized_horz_atom) < 0)
339 return -1;
340 }
341 else
342 {
343 if (ewmh_modify_state
344 (wnd, 0, g_net_wm_state_maximized_vert_atom,
345 g_net_wm_state_maximized_horz_atom) < 0)
346 return -1;
347 }
348
349 return 0;
350 }
351
352
353 int
354 ewmh_get_window_desktop(Window wnd)
355 {
356 unsigned long nitems_return;
357 unsigned char *prop_return;
358 int desktop;
359
360 if (get_property_value(wnd, "_NET_WM_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0)
361 return (-1);
362
363 if (nitems_return != 1)
364 {
365 fprintf(stderr, "_NET_WM_DESKTOP has bad length\n");
366 return (-1);
367 }
368
369 desktop = *prop_return;
370 XFree(prop_return);
371 return desktop;
372 }
373
374
375 int
376 ewmh_move_to_desktop(Window wnd, unsigned int desktop)
377 {
378 Status status;
379 XEvent xevent;
380
381 xevent.type = ClientMessage;
382 xevent.xclient.window = wnd;
383 xevent.xclient.message_type = g_net_wm_desktop_atom;
384 xevent.xclient.format = 32;
385 xevent.xclient.data.l[0] = desktop;
386 xevent.xclient.data.l[1] = 0;
387 xevent.xclient.data.l[2] = 0;
388 xevent.xclient.data.l[3] = 0;
389 xevent.xclient.data.l[4] = 0;
390 status = XSendEvent(g_display, DefaultRootWindow(g_display), False,
391 SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
392 if (!status)
393 return -1;
394
395 return 0;
396 }
397
398 void
399 ewmh_set_wm_name(Window wnd, const char *title)
400 {
401 int len;
402
403 len = strlen(title);
404 XChangeProperty(g_display, wnd, g_net_wm_name_atom, g_utf8_string_atom,
405 8, PropModeReplace, (unsigned char *) title, len);
406 }
407
408
409 int
410 ewmh_set_window_popup(Window wnd)
411 {
412 if (ewmh_modify_state
413 (wnd, 1, g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom) < 0)
414 return -1;
415 return 0;
416 }
417
418 int
419 ewmh_set_window_modal(Window wnd)
420 {
421 if (ewmh_modify_state(wnd, 1, g_net_wm_state_modal_atom, 0) < 0)
422 return -1;
423 return 0;
424 }
425
426 #endif /* MAKE_PROTO */
427
428
429 #if 0
430
431 /* FIXME: _NET_MOVERESIZE_WINDOW is for pagers, not for
432 applications. We should implement _NET_WM_MOVERESIZE instead */
433
434 int
435 ewmh_net_moveresize_window(Window wnd, int x, int y, int width, int height)
436 {
437 Status status;
438 XEvent xevent;
439 Atom moveresize;
440
441 moveresize = XInternAtom(g_display, "_NET_MOVERESIZE_WINDOW", False);
442 if (!moveresize)
443 {
444 return -1;
445 }
446
447 xevent.type = ClientMessage;
448 xevent.xclient.window = wnd;
449 xevent.xclient.message_type = moveresize;
450 xevent.xclient.format = 32;
451 xevent.xclient.data.l[0] = StaticGravity | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11);
452 xevent.xclient.data.l[1] = x;
453 xevent.xclient.data.l[2] = y;
454 xevent.xclient.data.l[3] = width;
455 xevent.xclient.data.l[4] = height;
456
457 status = XSendEvent(g_display, DefaultRootWindow(g_display), False,
458 SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
459 if (!status)
460 return -1;
461 return 0;
462 }
463
464 #endif

  ViewVC Help
Powered by ViewVC 1.1.26