/[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

Annotation of /sourceforge.net/trunk/rdesktop/ewmhints.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1476 - (hide annotations)
Fri Jul 11 03:55:52 2008 UTC (15 years, 10 months ago) by jsorg71
File MIME type: text/plain
File size: 14035 byte(s)
ran indent and removed some spaces at EOL

1 astrand 963 /* -*- c-basic-offset: 8 -*-
2 astrand 263 rdesktop: A Remote Desktop Protocol client.
3    
4     Support functions for Extended Window Manager Hints,
5 astrand 1013 http://www.freedesktop.org/wiki/Standards_2fwm_2dspec
6 astrand 263
7 ossman_ 1413 Copyright 2005 Peter Astrand <astrand@cendio.se> for Cendio AB
8     Copyright 2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 jsorg71 1476
10 astrand 263 This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14 jsorg71 1476
15 astrand 263 This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18     GNU General Public License for more details.
19 jsorg71 1476
20 astrand 263 You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23     */
24    
25 astrand 266 #include <X11/Xlib.h>
26 astrand 1199 #include <X11/Xatom.h>
27     #include <X11/Xutil.h>
28 astrand 263 #include "rdesktop.h"
29    
30 astrand 1199 #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
31     #define _NET_WM_STATE_ADD 1 /* add/set property */
32     #define _NET_WM_STATE_TOGGLE 2 /* toggle property */
33    
34 jsorg71 450 extern Display *g_display;
35 astrand 263
36 astrand 1199 static Atom g_net_wm_state_maximized_vert_atom, g_net_wm_state_maximized_horz_atom,
37     g_net_wm_state_hidden_atom, g_net_wm_name_atom, g_utf8_string_atom,
38 ossman_ 1413 g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom,
39 astrand 1443 g_net_wm_state_modal_atom, g_net_wm_icon_atom, g_net_wm_state_above_atom;
40 astrand 1199
41     Atom g_net_wm_state_atom, g_net_wm_desktop_atom;
42    
43 astrand 263 /*
44     Get window property value (32 bit format)
45     Returns zero on success, -1 on error
46     */
47     static int
48 astrand 1199 get_property_value(Window wnd, char *propname, long max_length,
49     unsigned long *nitems_return, unsigned char **prop_return, int nowarn)
50 astrand 263 {
51     int result;
52     Atom property;
53     Atom actual_type_return;
54     int actual_format_return;
55     unsigned long bytes_after_return;
56    
57 jsorg71 450 property = XInternAtom(g_display, propname, True);
58 astrand 263 if (property == None)
59     {
60     fprintf(stderr, "Atom %s does not exist\n", propname);
61     return (-1);
62     }
63    
64 astrand 1199 result = XGetWindowProperty(g_display, wnd, property, 0, /* long_offset */
65 astrand 263 max_length, /* long_length */
66     False, /* delete */
67     AnyPropertyType, /* req_type */
68     &actual_type_return,
69     &actual_format_return,
70     nitems_return, &bytes_after_return, prop_return);
71    
72     if (result != Success)
73     {
74     fprintf(stderr, "XGetWindowProperty failed\n");
75     return (-1);
76     }
77    
78     if (actual_type_return == None || actual_format_return == 0)
79     {
80 astrand 1199 if (!nowarn)
81     fprintf(stderr, "Window is missing property %s\n", propname);
82 astrand 263 return (-1);
83     }
84    
85     if (bytes_after_return)
86     {
87     fprintf(stderr, "%s is too big for me\n", propname);
88     return (-1);
89     }
90    
91     if (actual_format_return != 32)
92     {
93     fprintf(stderr, "%s has bad format\n", propname);
94     return (-1);
95     }
96    
97     return (0);
98     }
99    
100     /*
101     Get current desktop number
102     Returns -1 on error
103     */
104     static int
105 matthewc 300 get_current_desktop(void)
106 astrand 263 {
107     unsigned long nitems_return;
108 astrand 464 unsigned char *prop_return;
109 astrand 263 int current_desktop;
110    
111 astrand 1199 if (get_property_value
112     (DefaultRootWindow(g_display), "_NET_CURRENT_DESKTOP", 1, &nitems_return,
113     &prop_return, 0) < 0)
114 astrand 263 return (-1);
115    
116     if (nitems_return != 1)
117     {
118     fprintf(stderr, "_NET_CURRENT_DESKTOP has bad length\n");
119     return (-1);
120     }
121    
122     current_desktop = *prop_return;
123     XFree(prop_return);
124     return current_desktop;
125     }
126    
127     /*
128     Get workarea geometry
129     Returns zero on success, -1 on error
130     */
131    
132     int
133     get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height)
134     {
135     int current_desktop;
136     unsigned long nitems_return;
137 astrand 464 unsigned char *prop_return;
138     uint32 *return_words;
139 astrand 263 const uint32 net_workarea_x_offset = 0;
140     const uint32 net_workarea_y_offset = 1;
141     const uint32 net_workarea_width_offset = 2;
142     const uint32 net_workarea_height_offset = 3;
143     const uint32 max_prop_length = 32 * 4; /* Max 32 desktops */
144    
145 astrand 1199 if (get_property_value
146     (DefaultRootWindow(g_display), "_NET_WORKAREA", max_prop_length, &nitems_return,
147     &prop_return, 0) < 0)
148 astrand 263 return (-1);
149    
150     if (nitems_return % 4)
151     {
152     fprintf(stderr, "_NET_WORKAREA has odd length\n");
153     return (-1);
154     }
155    
156     current_desktop = get_current_desktop();
157    
158     if (current_desktop < 0)
159     return -1;
160    
161 astrand 468 return_words = (uint32 *) prop_return;
162 astrand 263
163 astrand 464 *x = return_words[current_desktop * 4 + net_workarea_x_offset];
164     *y = return_words[current_desktop * 4 + net_workarea_y_offset];
165     *width = return_words[current_desktop * 4 + net_workarea_width_offset];
166     *height = return_words[current_desktop * 4 + net_workarea_height_offset];
167    
168 astrand 263 XFree(prop_return);
169    
170     return (0);
171    
172     }
173 astrand 1013
174    
175 astrand 1199
176     void
177     ewmh_init()
178     {
179     /* FIXME: Use XInternAtoms */
180     g_net_wm_state_maximized_vert_atom =
181     XInternAtom(g_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
182     g_net_wm_state_maximized_horz_atom =
183     XInternAtom(g_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
184     g_net_wm_state_hidden_atom = XInternAtom(g_display, "_NET_WM_STATE_HIDDEN", False);
185     g_net_wm_state_skip_taskbar_atom =
186     XInternAtom(g_display, "_NET_WM_STATE_SKIP_TASKBAR", False);
187     g_net_wm_state_skip_pager_atom = XInternAtom(g_display, "_NET_WM_STATE_SKIP_PAGER", False);
188     g_net_wm_state_modal_atom = XInternAtom(g_display, "_NET_WM_STATE_MODAL", False);
189 astrand 1443 g_net_wm_state_above_atom = XInternAtom(g_display, "_NET_WM_STATE_ABOVE", False);
190 astrand 1199 g_net_wm_state_atom = XInternAtom(g_display, "_NET_WM_STATE", False);
191     g_net_wm_desktop_atom = XInternAtom(g_display, "_NET_WM_DESKTOP", False);
192     g_net_wm_name_atom = XInternAtom(g_display, "_NET_WM_NAME", False);
193 ossman_ 1413 g_net_wm_icon_atom = XInternAtom(g_display, "_NET_WM_ICON", False);
194 astrand 1199 g_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);
195     }
196    
197    
198     /*
199     Get the window state: normal/minimized/maximized.
200     */
201     #ifndef MAKE_PROTO
202     int
203     ewmh_get_window_state(Window w)
204     {
205     unsigned long nitems_return;
206     unsigned char *prop_return;
207     uint32 *return_words;
208     unsigned long item;
209 jsorg71 1372 RD_BOOL maximized_vert, maximized_horz, hidden;
210 astrand 1199
211     maximized_vert = maximized_horz = hidden = False;
212    
213     if (get_property_value(w, "_NET_WM_STATE", 64, &nitems_return, &prop_return, 0) < 0)
214     return SEAMLESSRDP_NORMAL;
215    
216     return_words = (uint32 *) prop_return;
217    
218     for (item = 0; item < nitems_return; item++)
219     {
220     if (return_words[item] == g_net_wm_state_maximized_vert_atom)
221     maximized_vert = True;
222     if (return_words[item] == g_net_wm_state_maximized_horz_atom)
223     maximized_horz = True;
224     if (return_words[item] == g_net_wm_state_hidden_atom)
225     hidden = True;
226     }
227    
228     XFree(prop_return);
229    
230     if (maximized_vert && maximized_horz)
231     return SEAMLESSRDP_MAXIMIZED;
232     else if (hidden)
233     return SEAMLESSRDP_MINIMIZED;
234     else
235     return SEAMLESSRDP_NORMAL;
236     }
237    
238     static int
239     ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
240     {
241     Status status;
242     XEvent xevent;
243    
244     int result;
245     unsigned long nitems;
246     unsigned char *props;
247 astrand 1225 uint32 state = WithdrawnState;
248 astrand 1199
249     /* The spec states that the window manager must respect any
250     _NET_WM_STATE attributes on a withdrawn window. In order words, we
251     modify the attributes directly for withdrawn windows and ask the WM
252     to do it for active windows. */
253     result = get_property_value(wnd, "WM_STATE", 64, &nitems, &props, 1);
254     if ((result >= 0) && nitems)
255     {
256     state = *(uint32 *) props;
257     XFree(props);
258     }
259    
260 astrand 1225 if (state == WithdrawnState)
261 astrand 1199 {
262     if (add)
263     {
264     Atom atoms[2];
265    
266     atoms[0] = atom1;
267     nitems = 1;
268     if (atom2)
269     {
270     atoms[1] = atom2;
271     nitems = 2;
272     }
273    
274     XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
275     32, PropModeAppend, (unsigned char *) atoms, nitems);
276     }
277     else
278     {
279     Atom *atoms;
280     int i;
281    
282     if (get_property_value(wnd, "_NET_WM_STATE", 64, &nitems, &props, 1) < 0)
283     return 0;
284    
285     atoms = (Atom *) props;
286    
287     for (i = 0; i < nitems; i++)
288     {
289     if ((atoms[i] == atom1) || (atom2 && (atoms[i] == atom2)))
290     {
291     if (i != (nitems - 1))
292     memmove(&atoms[i], &atoms[i + 1],
293     sizeof(Atom) * (nitems - i - 1));
294     nitems--;
295     i--;
296     }
297     }
298    
299     XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
300     32, PropModeReplace, (unsigned char *) atoms, nitems);
301    
302     XFree(props);
303     }
304    
305     return 0;
306     }
307    
308     xevent.type = ClientMessage;
309     xevent.xclient.window = wnd;
310     xevent.xclient.message_type = g_net_wm_state_atom;
311     xevent.xclient.format = 32;
312     if (add)
313     xevent.xclient.data.l[0] = _NET_WM_STATE_ADD;
314     else
315     xevent.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
316     xevent.xclient.data.l[1] = atom1;
317     xevent.xclient.data.l[2] = atom2;
318     xevent.xclient.data.l[3] = 0;
319     xevent.xclient.data.l[4] = 0;
320     status = XSendEvent(g_display, DefaultRootWindow(g_display), False,
321     SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
322     if (!status)
323     return -1;
324    
325     return 0;
326     }
327    
328     /*
329     Set the window state: normal/minimized/maximized.
330     Returns -1 on failure.
331     */
332     int
333     ewmh_change_state(Window wnd, int state)
334     {
335     /*
336     * Deal with the max atoms
337     */
338     if (state == SEAMLESSRDP_MAXIMIZED)
339     {
340     if (ewmh_modify_state
341     (wnd, 1, g_net_wm_state_maximized_vert_atom,
342     g_net_wm_state_maximized_horz_atom) < 0)
343     return -1;
344     }
345     else
346     {
347     if (ewmh_modify_state
348     (wnd, 0, g_net_wm_state_maximized_vert_atom,
349     g_net_wm_state_maximized_horz_atom) < 0)
350     return -1;
351     }
352    
353     return 0;
354     }
355    
356    
357     int
358     ewmh_get_window_desktop(Window wnd)
359     {
360     unsigned long nitems_return;
361     unsigned char *prop_return;
362     int desktop;
363    
364     if (get_property_value(wnd, "_NET_WM_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0)
365     return (-1);
366    
367     if (nitems_return != 1)
368     {
369     fprintf(stderr, "_NET_WM_DESKTOP has bad length\n");
370     return (-1);
371     }
372    
373     desktop = *prop_return;
374     XFree(prop_return);
375     return desktop;
376     }
377    
378    
379     int
380     ewmh_move_to_desktop(Window wnd, unsigned int desktop)
381     {
382     Status status;
383     XEvent xevent;
384    
385     xevent.type = ClientMessage;
386     xevent.xclient.window = wnd;
387     xevent.xclient.message_type = g_net_wm_desktop_atom;
388     xevent.xclient.format = 32;
389     xevent.xclient.data.l[0] = desktop;
390     xevent.xclient.data.l[1] = 0;
391     xevent.xclient.data.l[2] = 0;
392     xevent.xclient.data.l[3] = 0;
393     xevent.xclient.data.l[4] = 0;
394     status = XSendEvent(g_display, DefaultRootWindow(g_display), False,
395     SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
396     if (!status)
397     return -1;
398    
399     return 0;
400     }
401    
402     void
403     ewmh_set_wm_name(Window wnd, const char *title)
404     {
405     int len;
406    
407     len = strlen(title);
408     XChangeProperty(g_display, wnd, g_net_wm_name_atom, g_utf8_string_atom,
409     8, PropModeReplace, (unsigned char *) title, len);
410     }
411    
412    
413     int
414     ewmh_set_window_popup(Window wnd)
415     {
416     if (ewmh_modify_state
417     (wnd, 1, g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom) < 0)
418     return -1;
419     return 0;
420     }
421    
422     int
423     ewmh_set_window_modal(Window wnd)
424     {
425     if (ewmh_modify_state(wnd, 1, g_net_wm_state_modal_atom, 0) < 0)
426     return -1;
427     return 0;
428     }
429    
430 ossman_ 1413 void
431     ewmh_set_icon(Window wnd, int width, int height, const char *rgba_data)
432     {
433     unsigned long nitems, i;
434     unsigned char *props;
435     uint32 *cur_set, *new_set;
436     uint32 *icon;
437    
438     cur_set = NULL;
439     new_set = NULL;
440    
441     if (get_property_value(wnd, "_NET_WM_ICON", 10000, &nitems, &props, 1) >= 0)
442     {
443     cur_set = (uint32 *) props;
444    
445     for (i = 0; i < nitems;)
446     {
447     if (cur_set[i] == width && cur_set[i + 1] == height)
448     break;
449    
450     i += 2 + cur_set[i] * cur_set[i + 1];
451     }
452    
453     if (i != nitems)
454     icon = cur_set + i;
455     else
456     {
457     new_set = xmalloc((nitems + width * height + 2) * 4);
458     memcpy(new_set, cur_set, nitems * 4);
459     icon = new_set + nitems;
460     nitems += width * height + 2;
461     }
462     }
463     else
464     {
465     new_set = xmalloc((width * height + 2) * 4);
466     icon = new_set;
467     nitems = width * height + 2;
468     }
469    
470     icon[0] = width;
471     icon[1] = height;
472    
473     /* Convert RGBA -> ARGB */
474     for (i = 0; i < width * height; i++)
475     {
476     icon[i + 2] =
477     rgba_data[i * 4 + 3] << 24 |
478     ((rgba_data[i * 4 + 0] << 16) & 0x00FF0000) |
479     ((rgba_data[i * 4 + 1] << 8) & 0x0000FF00) |
480     ((rgba_data[i * 4 + 2] << 0) & 0x000000FF);
481     }
482    
483     XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
484     PropModeReplace, (unsigned char *) (new_set ? new_set : cur_set), nitems);
485    
486     if (cur_set)
487     XFree(cur_set);
488     if (new_set)
489     xfree(new_set);
490     }
491    
492     void
493     ewmh_del_icon(Window wnd, int width, int height)
494     {
495     unsigned long nitems, i, icon_size;
496     unsigned char *props;
497     uint32 *cur_set, *new_set;
498    
499     cur_set = NULL;
500     new_set = NULL;
501    
502     if (get_property_value(wnd, "_NET_WM_ICON", 10000, &nitems, &props, 1) < 0)
503     return;
504    
505     cur_set = (uint32 *) props;
506    
507     for (i = 0; i < nitems;)
508     {
509     if (cur_set[i] == width && cur_set[i + 1] == height)
510     break;
511    
512     i += 2 + cur_set[i] * cur_set[i + 1];
513     }
514    
515     if (i == nitems)
516     goto out;
517    
518     icon_size = width * height + 2;
519     new_set = xmalloc((nitems - icon_size) * 4);
520    
521     if (i != 0)
522     memcpy(new_set, cur_set, i * 4);
523     if (i != nitems - icon_size)
524     memcpy(new_set + i * 4, cur_set + i * 4 + icon_size, nitems - icon_size);
525    
526     nitems -= icon_size;
527    
528     XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32,
529     PropModeReplace, (unsigned char *) new_set, nitems);
530    
531     xfree(new_set);
532    
533     out:
534     XFree(cur_set);
535     }
536    
537 astrand 1443 int
538     ewmh_set_window_above(Window wnd)
539     {
540     if (ewmh_modify_state(wnd, 1, g_net_wm_state_above_atom, 0) < 0)
541     return -1;
542     return 0;
543     }
544    
545 astrand 1199 #endif /* MAKE_PROTO */
546    
547    
548 astrand 1013 #if 0
549    
550     /* FIXME: _NET_MOVERESIZE_WINDOW is for pagers, not for
551     applications. We should implement _NET_WM_MOVERESIZE instead */
552    
553     int
554     ewmh_net_moveresize_window(Window wnd, int x, int y, int width, int height)
555     {
556     Status status;
557     XEvent xevent;
558     Atom moveresize;
559    
560     moveresize = XInternAtom(g_display, "_NET_MOVERESIZE_WINDOW", False);
561     if (!moveresize)
562     {
563     return -1;
564     }
565    
566     xevent.type = ClientMessage;
567     xevent.xclient.window = wnd;
568     xevent.xclient.message_type = moveresize;
569     xevent.xclient.format = 32;
570     xevent.xclient.data.l[0] = StaticGravity | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11);
571     xevent.xclient.data.l[1] = x;
572     xevent.xclient.data.l[2] = y;
573     xevent.xclient.data.l[3] = width;
574     xevent.xclient.data.l[4] = height;
575    
576     status = XSendEvent(g_display, DefaultRootWindow(g_display), False,
577     SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
578     if (!status)
579     return -1;
580     return 0;
581     }
582    
583     #endif

  ViewVC Help
Powered by ViewVC 1.1.26