1 /*      $Id$
2 
3         This program is free software; you can redistribute it and/or modify
4         it under the terms of the GNU General Public License as published by
5         the Free Software Foundation; either version 2, or (at your option)
6         any later version.
7 
8         This program is distributed in the hope that it will be useful,
9         but WITHOUT ANY WARRANTY; without even the implied warranty of
10         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11         GNU General Public License for more details.
12 
13         You should have received a copy of the GNU General Public License
14         along with this program; if not, write to the Free Software
15         Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
16         MA 02110-1301, USA.
17 
18 
19         oroborus - (c) 2001 Ken Lynch
20         Metacity - (c) 2001 Havoc Pennington
21         xfwm4    - (c) 2002-2020 Olivier Fourdan
22 
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <X11/X.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <X11/Xmd.h>
33 #ifdef HAVE_XRES
34 #include <X11/extensions/XRes.h>
35 #endif
36 
37 #include <glib.h>
38 #include <gdk/gdk.h>
39 #include <gdk/gdkx.h>
40 #include <gtk/gtk.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <libxfce4util/libxfce4util.h>
46 
47 #include "display.h"
48 #include "screen.h"
49 #include "hints.h"
50 
51 static gboolean
check_type_and_format(int expected_format,Atom expected_type,int n_items,int format,Atom type)52 check_type_and_format (int expected_format, Atom expected_type, int n_items, int format, Atom type)
53 {
54     if ((expected_format == format) && (expected_type == type) && (n_items < 0 || n_items > 0))
55     {
56         return TRUE;
57     }
58     return FALSE;
59 }
60 
61 static gchar *
internal_utf8_strndup(const gchar * src,gssize max_len)62 internal_utf8_strndup (const gchar *src, gssize max_len)
63 {
64     const gchar *s;
65 
66     if (max_len <= 0)
67     {
68         return g_strdup (src);
69     }
70 
71     s = src;
72     while (max_len && *s)
73     {
74         s = g_utf8_next_char (s);
75         max_len--;
76     }
77 
78     return g_strndup (src, s - src);
79 }
80 
81 unsigned long
getWMState(DisplayInfo * display_info,Window w)82 getWMState (DisplayInfo *display_info, Window w)
83 {
84     Atom real_type;
85     int real_format;
86     unsigned long items_read, items_left;
87     unsigned char *data;
88     unsigned long state;
89     int result, status;
90 
91     TRACE ("window 0x%lx", w);
92 
93     data = NULL;
94     state = WithdrawnState;
95 
96     myDisplayErrorTrapPush (display_info);
97     status = XGetWindowProperty (display_info->dpy, w, display_info->atoms[WM_STATE],
98                                  0, 3L, FALSE, display_info->atoms[WM_STATE],
99                                  &real_type, &real_format, &items_read, &items_left,
100                                  (unsigned char **) &data);
101     result = myDisplayErrorTrapPop (display_info);
102 
103     if ((result == Success) &&
104         (status == Success) &&
105         (items_read) &&
106         (data != NULL))
107     {
108         state = *data;
109     }
110     XFree (data);
111 
112     return state;
113 }
114 
115 void
setWMState(DisplayInfo * display_info,Window w,unsigned long state)116 setWMState (DisplayInfo *display_info, Window w, unsigned long state)
117 {
118     CARD32 data[2];
119 
120     TRACE ("window 0x%lx", w);
121 
122     data[0] = state;
123     data[1] = None;
124     myDisplayErrorTrapPush (display_info);
125     XChangeProperty (display_info->dpy, w, display_info->atoms[WM_STATE],
126                      display_info->atoms[WM_STATE], 32, PropModeReplace,
127                      (unsigned char *) data, 2);
128     myDisplayErrorTrapPopIgnored (display_info);
129 }
130 
131 PropMwmHints *
getMotifHints(DisplayInfo * display_info,Window w)132 getMotifHints (DisplayInfo *display_info, Window w)
133 {
134     Atom real_type;
135     int real_format;
136     unsigned long items_read, items_left;
137     unsigned char *data;
138     PropMwmHints *hints;
139     int result, status;
140 
141     TRACE ("window 0x%lx", w);
142 
143     data = NULL;
144     hints = NULL;
145 
146     myDisplayErrorTrapPush (display_info);
147     status = XGetWindowProperty (display_info->dpy, w, display_info->atoms[MOTIF_WM_HINTS], 0L,
148                                  MWM_HINTS_ELEMENTS, FALSE, display_info->atoms[MOTIF_WM_HINTS],
149                                  &real_type, &real_format, &items_read, &items_left,
150                                  (unsigned char **) &data);
151     result = myDisplayErrorTrapPop (display_info);
152 
153     if ((status == Success) &&
154         (result == Success) &&
155         (data != NULL) &&
156         (items_read >= MWM_HINTS_ELEMENTS))
157     {
158         hints = g_new0 (PropMwmHints, 1);
159         memcpy (hints, data, sizeof (PropMwmHints));
160     }
161 
162     XFree (data);
163 
164     return hints;
165 }
166 
167 unsigned int
getWMProtocols(DisplayInfo * display_info,Window w)168 getWMProtocols (DisplayInfo *display_info, Window w)
169 {
170     Atom *protocols, *ap;
171     gint i, n;
172     Atom atype;
173     int aformat;
174     unsigned int flags;
175     unsigned long bytes_remain, nitems;
176     unsigned char *data;
177     int result, status;
178 
179     TRACE ("window 0x%lx", w);
180 
181     flags = 0;
182     protocols = NULL;
183     data = NULL;
184 
185     myDisplayErrorTrapPush (display_info);
186     status = XGetWMProtocols (display_info->dpy, w, &protocols, &n);
187     result = myDisplayErrorTrapPop (display_info);
188 
189     if (status && (result == Success) && (protocols != NULL))
190     {
191         for (i = 0, ap = protocols; i < n; i++, ap++)
192         {
193             if (*ap == display_info->atoms[WM_TAKE_FOCUS])
194             {
195                 flags |= WM_PROTOCOLS_TAKE_FOCUS;
196             }
197             if (*ap == display_info->atoms[WM_DELETE_WINDOW])
198             {
199                 flags |= WM_PROTOCOLS_DELETE_WINDOW;
200             }
201             /* KDE extension */
202             if (*ap == display_info->atoms[NET_WM_CONTEXT_HELP])
203             {
204                 flags |= WM_PROTOCOLS_CONTEXT_HELP;
205             }
206             /* Ping */
207             if (*ap == display_info->atoms[NET_WM_PING])
208             {
209                 flags |= WM_PROTOCOLS_PING;
210             }
211         }
212     }
213     else
214     {
215         myDisplayErrorTrapPush (display_info);
216         status = XGetWindowProperty (display_info->dpy, w,
217                                      display_info->atoms[WM_PROTOCOLS],
218                                      0L, 10L, FALSE,
219                                      display_info->atoms[WM_PROTOCOLS],
220                                      &atype, &aformat, &nitems, &bytes_remain,
221                                      (unsigned char **) &data);
222         result = myDisplayErrorTrapPop (display_info);
223 
224         if ((status == Success) &&
225             (result == Success) &&
226             (data != NULL))
227         {
228             for (i = 0, ap = (Atom *) data; (unsigned long) i < nitems; i++, ap++)
229             {
230                 if (*ap == display_info->atoms[WM_TAKE_FOCUS])
231                 {
232                     flags |= WM_PROTOCOLS_TAKE_FOCUS;
233                 }
234                 if (*ap == display_info->atoms[WM_DELETE_WINDOW])
235                 {
236                     flags |= WM_PROTOCOLS_DELETE_WINDOW;
237                 }
238                 /* KDE extension */
239                 if (*ap == display_info->atoms[NET_WM_CONTEXT_HELP])
240                 {
241                     flags |= WM_PROTOCOLS_CONTEXT_HELP;
242                 }
243             }
244         }
245         XFree (data);
246     }
247     XFree (protocols);
248 
249     return flags;
250 }
251 
252 gboolean
getHint(DisplayInfo * display_info,Window w,int atom_id,long * value)253 getHint (DisplayInfo *display_info, Window w, int atom_id, long *value)
254 {
255     Atom real_type;
256     unsigned long items_read, items_left;
257     unsigned char *data;
258     int real_format;
259     gboolean success;
260     int result, status;
261 
262     g_return_val_if_fail (((atom_id >= 0) && (atom_id < ATOM_COUNT)), FALSE);
263     TRACE ("window 0x%lx atom %i", w, atom_id);
264 
265     success = FALSE;
266     *value = 0;
267     data = NULL;
268 
269     myDisplayErrorTrapPush (display_info);
270     status = XGetWindowProperty (display_info->dpy, w, display_info->atoms[atom_id],
271                                  0L, 1L, FALSE, XA_CARDINAL, &real_type, &real_format,
272                                  &items_read, &items_left, (unsigned char **) &data);
273     result = myDisplayErrorTrapPop (display_info);
274 
275     if ((result == Success) &&
276         (status == Success) &&
277         (data != NULL) &&
278         (items_read > 0))
279     {
280         *value = *((long *) data) & ((1LL << real_format) - 1);
281         XFree (data);
282         success = TRUE;
283     }
284 
285     return success;
286 }
287 
288 void
setHint(DisplayInfo * display_info,Window w,int atom_id,long value)289 setHint (DisplayInfo *display_info, Window w, int atom_id, long value)
290 {
291     g_return_if_fail ((atom_id >= 0) && (atom_id < ATOM_COUNT));
292     TRACE ("window 0x%lx atom %i", w, atom_id);
293 
294     myDisplayErrorTrapPush (display_info);
295     XChangeProperty (display_info->dpy, w, display_info->atoms[atom_id], XA_CARDINAL,
296                      32, PropModeReplace, (unsigned char *) &value, 1);
297     myDisplayErrorTrapPopIgnored (display_info);
298 }
299 
300 void
getDesktopLayout(DisplayInfo * display_info,Window root,int ws_count,NetWmDesktopLayout * layout)301 getDesktopLayout (DisplayInfo *display_info, Window root, int ws_count, NetWmDesktopLayout * layout)
302 {
303     Atom real_type;
304     unsigned long items_read, items_left;
305     unsigned long orientation, cols, rows, start;
306     unsigned long *ptr;
307     unsigned char *data;
308     int real_format;
309     gboolean success;
310     int result, status;
311 
312     ptr = NULL;
313     data = NULL;
314     success = FALSE;
315 
316     myDisplayErrorTrapPush (display_info);
317     status = XGetWindowProperty (display_info->dpy, root,
318                                  display_info->atoms[NET_DESKTOP_LAYOUT],
319                                  0L, 4L, FALSE, XA_CARDINAL,
320                                  &real_type, &real_format, &items_read, &items_left,
321                                  (unsigned char **) &data);
322     result = myDisplayErrorTrapPop (display_info);
323 
324     if ((result == Success) &&
325         (status == Success) &&
326         (data != NULL) &&
327         (items_read >= 3))
328     {
329         do
330         {
331             ptr = (unsigned long *) data;
332             orientation = (unsigned long) *ptr++;
333             cols = (unsigned long) *ptr++;
334             rows = (unsigned long) *ptr++;
335             start = (items_read >= 4) ? (unsigned long) *ptr++ : NET_WM_TOPLEFT;
336 
337             if (orientation > NET_WM_ORIENTATION_VERT)
338             {
339                 break;
340             }
341 
342             if (start > NET_WM_BOTTOMLEFT)
343             {
344                 break;
345             }
346 
347             if ((rows == 0) && (cols == 0))
348             {
349                 break;
350             }
351 
352             if (rows == 0)
353             {
354                 rows = (ws_count - 1) / cols + 1;
355             }
356 
357             if (cols == 0)
358             {
359                 cols = (ws_count - 1) / rows + 1;
360             }
361 
362             layout->orientation = (unsigned long) orientation;
363             layout->cols = cols;
364             layout->rows = rows;
365             layout->start = start;
366             success = TRUE;
367         } while (0);
368     }
369     XFree (data);
370 
371     if (!success)
372     {
373         /* Assume HORZ, TOPLEFT, one row by default */
374         layout->orientation = NET_WM_ORIENTATION_HORZ;
375         layout->cols = ws_count;
376         layout->rows = 1;
377         layout->start = NET_WM_TOPLEFT;
378     }
379 }
380 
381 void
setNetSupportedHint(DisplayInfo * display_info,Window root,Window check_win)382 setNetSupportedHint (DisplayInfo *display_info, Window root, Window check_win)
383 {
384     Atom atoms[ATOM_COUNT];
385     unsigned long data[1];
386     int i;
387 
388     i = 0;
389     atoms[i++] = display_info->atoms[NET_ACTIVE_WINDOW];
390     atoms[i++] = display_info->atoms[NET_CLIENT_LIST];
391     atoms[i++] = display_info->atoms[NET_CLIENT_LIST_STACKING];
392     atoms[i++] = display_info->atoms[NET_CLOSE_WINDOW];
393     atoms[i++] = display_info->atoms[NET_CURRENT_DESKTOP];
394     atoms[i++] = display_info->atoms[NET_DESKTOP_GEOMETRY];
395     atoms[i++] = display_info->atoms[NET_DESKTOP_LAYOUT];
396     atoms[i++] = display_info->atoms[NET_DESKTOP_NAMES];
397     atoms[i++] = display_info->atoms[NET_DESKTOP_VIEWPORT];
398     atoms[i++] = display_info->atoms[NET_FRAME_EXTENTS];
399     atoms[i++] = display_info->atoms[NET_MOVERESIZE_WINDOW];
400     atoms[i++] = display_info->atoms[NET_NUMBER_OF_DESKTOPS];
401     atoms[i++] = display_info->atoms[NET_REQUEST_FRAME_EXTENTS];
402     atoms[i++] = display_info->atoms[NET_SHOWING_DESKTOP];
403     atoms[i++] = display_info->atoms[NET_SUPPORTED];
404     atoms[i++] = display_info->atoms[NET_SUPPORTING_WM_CHECK];
405     atoms[i++] = display_info->atoms[NET_SYSTEM_TRAY_OPCODE];
406     atoms[i++] = display_info->atoms[NET_WM_ACTION_ABOVE];
407     atoms[i++] = display_info->atoms[NET_WM_ACTION_BELOW];
408     atoms[i++] = display_info->atoms[NET_WM_ACTION_CHANGE_DESKTOP];
409     atoms[i++] = display_info->atoms[NET_WM_ACTION_CLOSE];
410     atoms[i++] = display_info->atoms[NET_WM_ACTION_FULLSCREEN];
411     atoms[i++] = display_info->atoms[NET_WM_ACTION_MAXIMIZE_HORZ];
412     atoms[i++] = display_info->atoms[NET_WM_ACTION_MAXIMIZE_VERT];
413     atoms[i++] = display_info->atoms[NET_WM_ACTION_MINIMIZE];
414     atoms[i++] = display_info->atoms[NET_WM_ACTION_MOVE];
415     atoms[i++] = display_info->atoms[NET_WM_ACTION_RESIZE];
416     atoms[i++] = display_info->atoms[NET_WM_ACTION_SHADE];
417     atoms[i++] = display_info->atoms[NET_WM_ACTION_STICK];
418     atoms[i++] = display_info->atoms[NET_WM_ALLOWED_ACTIONS];
419     atoms[i++] = display_info->atoms[NET_WM_BYPASS_COMPOSITOR];
420     atoms[i++] = display_info->atoms[NET_WM_CONTEXT_HELP];
421     atoms[i++] = display_info->atoms[NET_WM_DESKTOP];
422     atoms[i++] = display_info->atoms[NET_WM_FULLSCREEN_MONITORS];
423     atoms[i++] = display_info->atoms[NET_WM_ICON];
424     atoms[i++] = display_info->atoms[NET_WM_ICON_GEOMETRY];
425     atoms[i++] = display_info->atoms[NET_WM_ICON_NAME];
426     atoms[i++] = display_info->atoms[NET_WM_MOVERESIZE];
427     atoms[i++] = display_info->atoms[NET_WM_NAME];
428     atoms[i++] = display_info->atoms[NET_WM_OPAQUE_REGION];
429     atoms[i++] = display_info->atoms[NET_WM_PID];
430     atoms[i++] = display_info->atoms[NET_WM_PING];
431     atoms[i++] = display_info->atoms[NET_WM_STATE];
432     atoms[i++] = display_info->atoms[NET_WM_STATE_ABOVE];
433     atoms[i++] = display_info->atoms[NET_WM_STATE_BELOW];
434     atoms[i++] = display_info->atoms[NET_WM_STATE_DEMANDS_ATTENTION];
435     atoms[i++] = display_info->atoms[NET_WM_STATE_FOCUSED];
436     atoms[i++] = display_info->atoms[NET_WM_STATE_FULLSCREEN];
437     atoms[i++] = display_info->atoms[NET_WM_STATE_HIDDEN];
438     atoms[i++] = display_info->atoms[NET_WM_STATE_MAXIMIZED_HORZ];
439     atoms[i++] = display_info->atoms[NET_WM_STATE_MAXIMIZED_VERT];
440     atoms[i++] = display_info->atoms[NET_WM_STATE_MODAL];
441     atoms[i++] = display_info->atoms[NET_WM_STATE_SHADED];
442     atoms[i++] = display_info->atoms[NET_WM_STATE_SKIP_PAGER];
443     atoms[i++] = display_info->atoms[NET_WM_STATE_SKIP_TASKBAR];
444     atoms[i++] = display_info->atoms[NET_WM_STATE_STICKY];
445     atoms[i++] = display_info->atoms[NET_WM_STRUT];
446     atoms[i++] = display_info->atoms[NET_WM_STRUT_PARTIAL];
447     atoms[i++] = display_info->atoms[NET_WM_SYNC_REQUEST];
448     atoms[i++] = display_info->atoms[NET_WM_SYNC_REQUEST_COUNTER];
449     atoms[i++] = display_info->atoms[NET_WM_USER_TIME];
450     atoms[i++] = display_info->atoms[NET_WM_USER_TIME_WINDOW];
451     atoms[i++] = display_info->atoms[NET_WM_WINDOW_OPACITY];
452     atoms[i++] = display_info->atoms[NET_WM_WINDOW_OPACITY_LOCKED];
453     atoms[i++] = display_info->atoms[NET_WM_WINDOW_TYPE];
454     atoms[i++] = display_info->atoms[NET_WM_WINDOW_TYPE_DESKTOP];
455     atoms[i++] = display_info->atoms[NET_WM_WINDOW_TYPE_DIALOG];
456     atoms[i++] = display_info->atoms[NET_WM_WINDOW_TYPE_DOCK];
457     atoms[i++] = display_info->atoms[NET_WM_WINDOW_TYPE_MENU];
458     atoms[i++] = display_info->atoms[NET_WM_WINDOW_TYPE_NORMAL];
459     atoms[i++] = display_info->atoms[NET_WM_WINDOW_TYPE_SPLASH];
460     atoms[i++] = display_info->atoms[NET_WM_WINDOW_TYPE_TOOLBAR];
461     atoms[i++] = display_info->atoms[NET_WM_WINDOW_TYPE_UTILITY];
462     atoms[i++] = display_info->atoms[NET_WORKAREA];
463     /* GTK specific hints */
464     atoms[i++] = display_info->atoms[GTK_FRAME_EXTENTS];
465     atoms[i++] = display_info->atoms[GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED];
466     atoms[i++] = display_info->atoms[GTK_SHOW_WINDOW_MENU];
467 #ifdef HAVE_LIBSTARTUP_NOTIFICATION
468     atoms[i++] = display_info->atoms[NET_STARTUP_ID];
469 #endif
470 #ifdef ENABLE_KDE_SYSTRAY_PROXY
471     atoms[i++] = display_info->atoms[KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR];
472 #endif
473     g_assert (i < ATOM_COUNT);
474     data[0] = check_win;
475     XChangeProperty (display_info->dpy, root, display_info->atoms[NET_SUPPORTED],
476                      XA_ATOM, 32, PropModeReplace, (unsigned char *) atoms, i);
477     XChangeProperty (display_info->dpy, check_win, display_info->atoms[NET_SUPPORTING_WM_CHECK],
478                      XA_WINDOW, 32, PropModeReplace, (unsigned char *) data, 1);
479     XChangeProperty (display_info->dpy, root, display_info->atoms[NET_SUPPORTING_WM_CHECK],
480                      XA_WINDOW, 32, PropModeReplace, (unsigned char *) data, 1);
481 }
482 
483 gboolean
getAtomList(DisplayInfo * display_info,Window w,int atom_id,Atom ** atoms_p,int * n_atoms_p)484 getAtomList (DisplayInfo *display_info, Window w, int atom_id, Atom ** atoms_p, int *n_atoms_p)
485 {
486     Atom type;
487     int format;
488     unsigned long n_atoms;
489     unsigned long bytes_after;
490     unsigned char *data;
491     Atom *atoms;
492     int result, status;
493 
494     *atoms_p = NULL;
495     *n_atoms_p = 0;
496 
497     g_return_val_if_fail (((atom_id >= 0) && (atom_id < ATOM_COUNT)), FALSE);
498     TRACE ("window 0x%lx atom %i", w, atom_id);
499 
500     myDisplayErrorTrapPush (display_info);
501     status = XGetWindowProperty (display_info->dpy, w, display_info->atoms[atom_id],
502                                  0, G_MAXLONG, FALSE, XA_ATOM, &type, &format, &n_atoms,
503                                  &bytes_after, (unsigned char **) &data);
504     result = myDisplayErrorTrapPop (display_info);
505 
506     if ((result != Success) ||
507         (status != Success) ||
508         (data == NULL) ||
509         (type == None))
510     {
511         XFree (data);
512         return FALSE;
513     }
514 
515     atoms = (Atom *) data;
516     if (!check_type_and_format (32, XA_ATOM, -1, format, type))
517     {
518         XFree (atoms);
519         *atoms_p = NULL;
520         *n_atoms_p = 0;
521         return FALSE;
522     }
523 
524     *atoms_p = atoms;
525     *n_atoms_p = n_atoms;
526 
527     return TRUE;
528 }
529 
530 gboolean
getCardinalList(DisplayInfo * display_info,Window w,int atom_id,unsigned long ** cardinals_p,int * n_cardinals_p)531 getCardinalList (DisplayInfo *display_info, Window w, int atom_id, unsigned long **cardinals_p, int *n_cardinals_p)
532 {
533     Atom type;
534     int format;
535     unsigned int i;
536     unsigned long n_cardinals;
537     unsigned long bytes_after;
538     unsigned char *data;
539     unsigned long *cardinals;
540     int result, status;
541 
542     *cardinals_p = NULL;
543     *n_cardinals_p = 0;
544 
545     g_return_val_if_fail (((atom_id >= 0) && (atom_id < ATOM_COUNT)), FALSE);
546     TRACE ("window 0x%lx atom %i", w, atom_id);
547 
548     myDisplayErrorTrapPush (display_info);
549     status = XGetWindowProperty (display_info->dpy, w, display_info->atoms[atom_id],
550                                  0, G_MAXLONG, FALSE, XA_CARDINAL,
551                                  &type, &format, &n_cardinals, &bytes_after,
552                                  (unsigned char **) &data);
553     result = myDisplayErrorTrapPop (display_info);
554 
555     if ((result != Success) ||
556         (status != Success) ||
557         (data == NULL) ||
558         (type == None))
559     {
560         XFree (data);
561         return FALSE;
562     }
563 
564     cardinals = (unsigned long *) data;
565     if (!check_type_and_format (32, XA_CARDINAL, -1, format, type))
566     {
567         XFree (cardinals);
568         return FALSE;
569     }
570 
571     *cardinals_p = cardinals;
572     *n_cardinals_p = n_cardinals;
573     for (i = 0; i < n_cardinals; i++)
574     {
575         (*cardinals_p)[i] = (*cardinals_p)[i] & ((1LL << format) - 1);
576     }
577 
578     return TRUE;
579 }
580 
581 void
setNetWorkarea(DisplayInfo * display_info,Window root,int nb_workspaces,int width,int height,int * m)582 setNetWorkarea (DisplayInfo *display_info, Window root, int nb_workspaces, int width, int height, int * m)
583 {
584     unsigned long *data, *ptr;
585     int i, j;
586 
587     TRACE ("workspaces %i [%i×%i]", nb_workspaces, width, height);
588 
589     j = (nb_workspaces ? nb_workspaces : 1);
590     data = (unsigned long *) g_new0 (unsigned long, j * 4);
591     ptr = data;
592     for (i = 0; i < j; i++)
593     {
594         *ptr++ = (unsigned long) m[STRUTS_LEFT];
595         *ptr++ = (unsigned long) m[STRUTS_TOP];
596         *ptr++ = (unsigned long) (width  - (m[STRUTS_LEFT] + m[STRUTS_RIGHT]));
597         *ptr++ = (unsigned long) (height - (m[STRUTS_TOP]  + m[STRUTS_BOTTOM]));
598     }
599 
600     XChangeProperty (display_info->dpy, root, display_info->atoms[NET_WORKAREA],
601                      XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, j * 4);
602     g_free (data);
603 }
604 
605 void
setNetFrameExtents(DisplayInfo * display_info,Window w,int top,int left,int right,int bottom)606 setNetFrameExtents (DisplayInfo *display_info, Window w, int top, int left, int right, int bottom)
607 {
608     unsigned long data[4] = { 0, 0, 0, 0 };
609 
610     TRACE ("window 0x%lx [left=%i,right=%i,top=%i,bottom=%i]", w, left, right, top, bottom);
611 
612     data[0] = (unsigned long) left;
613     data[1] = (unsigned long) right;
614     data[2] = (unsigned long) top;
615     data[3] = (unsigned long) bottom;
616     myDisplayErrorTrapPush (display_info);
617     XChangeProperty (display_info->dpy, w, display_info->atoms[NET_FRAME_EXTENTS],
618                      XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 4);
619     myDisplayErrorTrapPopIgnored (display_info);
620 }
621 
622 void
setNetFullscreenMonitors(DisplayInfo * display_info,Window w,gint top,gint bottom,gint left,gint right)623 setNetFullscreenMonitors (DisplayInfo *display_info, Window w, gint top, gint bottom, gint left, gint right)
624 {
625     unsigned long data[4] = { 0, 0, 0, 0 };
626 
627     TRACE ("window 0x%lx [top=%i,bottom=%i,left=%i,right=%i]", w, top, bottom, left, right);
628 
629     data[0] = (unsigned long) top;;
630     data[1] = (unsigned long) bottom;
631     data[2] = (unsigned long) left;
632     data[3] = (unsigned long) right;
633     myDisplayErrorTrapPush (display_info);
634     XChangeProperty (display_info->dpy, w, display_info->atoms[NET_WM_FULLSCREEN_MONITORS],
635                      XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 4);
636     myDisplayErrorTrapPopIgnored (display_info);
637 }
638 
639 int
getNetCurrentDesktop(DisplayInfo * display_info,Window root)640 getNetCurrentDesktop (DisplayInfo *display_info, Window root)
641 {
642     long ws;
643 
644     getHint (display_info, root, NET_CURRENT_DESKTOP, &ws);
645     return (int) ws;
646 }
647 
648 void
setNetCurrentDesktop(DisplayInfo * display_info,Window root,int workspace)649 setNetCurrentDesktop (DisplayInfo *display_info, Window root, int workspace)
650 {
651     unsigned long data[2];
652 
653     TRACE ("workspace %i", workspace);
654 
655     data[0] = 0;
656     data[1] = 0;
657     XChangeProperty (display_info->dpy, root, display_info->atoms[NET_DESKTOP_VIEWPORT],
658                      XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 2);
659     data[0] = workspace;
660     XChangeProperty (display_info->dpy, root, display_info->atoms[NET_CURRENT_DESKTOP],
661                      XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 1);
662 }
663 
664 void
setNetDesktopInfo(DisplayInfo * display_info,Window root,int workspace,int width,int height)665 setNetDesktopInfo (DisplayInfo *display_info, Window root, int workspace, int width, int height)
666 {
667     unsigned long data[2];
668 
669     TRACE ("workspace %i [%i×%i]", workspace, width, height);
670 
671     data[0] = width;
672     data[1] = height;
673     XChangeProperty (display_info->dpy, root, display_info->atoms[NET_DESKTOP_GEOMETRY],
674                      XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 2);
675     setNetCurrentDesktop (display_info, root, workspace);
676 }
677 
678 void
setUTF8StringHint(DisplayInfo * display_info,Window w,int atom_id,const gchar * val)679 setUTF8StringHint (DisplayInfo *display_info, Window w, int atom_id, const gchar *val)
680 {
681     g_return_if_fail ((atom_id >= 0) && (atom_id < ATOM_COUNT));
682 
683     TRACE ("window 0x%lx atom %i", w, atom_id);
684     myDisplayErrorTrapPush (display_info);
685     XChangeProperty (display_info->dpy, w, display_info->atoms[atom_id],
686                      display_info->atoms[UTF8_STRING], 8, PropModeReplace,
687                      (unsigned char *) val, strlen (val));
688     myDisplayErrorTrapPopIgnored (display_info);
689 }
690 
691 void
getTransientFor(DisplayInfo * display_info,Window root,Window w,Window * transient_for)692 getTransientFor (DisplayInfo *display_info, Window root, Window w, Window * transient_for)
693 {
694     int result, status;
695 
696     TRACE ("window 0x%lx", w);
697 
698     myDisplayErrorTrapPush (display_info);
699     status = XGetTransientForHint (display_info->dpy, w, transient_for);
700     result = myDisplayErrorTrapPop (display_info);
701 
702     if ((result == Success) && status)
703     {
704         if (*transient_for == None)
705         {
706             /* Treat transient for "none" same as transient for root */
707             *transient_for = root;
708         }
709         else if (*transient_for == w)
710         {
711             /* Very unlikely to happen, but who knows, maybe a braindead app */
712             *transient_for = None;
713         }
714     }
715     else
716     {
717         *transient_for = None;
718     }
719 
720     TRACE ("window (0x%lx) is transient for (0x%lx)", w, *transient_for);
721 }
722 
723 static char *
textPropertyToUTF8(DisplayInfo * display_info,const XTextProperty * prop)724 textPropertyToUTF8 (DisplayInfo *display_info, const XTextProperty * prop)
725 {
726     char **list;
727     int count;
728     char *retval;
729 
730     list = NULL;
731     count = gdk_text_property_to_utf8_list_for_display (display_info->gdisplay,
732                                                         gdk_x11_xatom_to_atom (prop->encoding),
733                                                         prop->format, prop->value, prop->nitems, &list);
734     if (count == 0)
735     {
736         TRACE ("gdk_text_property_to_utf8_list returned 0");
737         return NULL;
738     }
739     retval = list[0];
740     list[0] = g_strdup ("");
741     g_strfreev (list);
742 
743     return retval;
744 }
745 
746 static char *
getTextProperty(DisplayInfo * display_info,Window w,Atom a)747 getTextProperty (DisplayInfo *display_info, Window w, Atom a)
748 {
749     XTextProperty text;
750     char *retval;
751     int result, status;
752 
753     TRACE ("window 0x%lx", w);
754 
755     text.nitems = 0;
756     text.value = NULL;
757 
758     myDisplayErrorTrapPush (display_info);
759     status = XGetTextProperty (display_info->dpy, w, &text, a);
760     result = myDisplayErrorTrapPop (display_info);
761 
762     if ((result == Success) && status)
763     {
764         retval = textPropertyToUTF8 (display_info, &text);
765         if (retval)
766         {
767             xfce_utf8_remove_controls((gchar *) retval, MAX_STR_LENGTH, NULL);
768         }
769     }
770     else
771     {
772         retval = NULL;
773         TRACE ("XGetTextProperty() failed");
774     }
775     XFree (text.value);
776 
777     return retval;
778 }
779 
780 static gboolean
getUTF8StringData(DisplayInfo * display_info,Window w,int atom_id,gchar ** str_p,guint * length)781 getUTF8StringData (DisplayInfo *display_info, Window w, int atom_id, gchar **str_p, guint *length)
782 {
783     Atom type;
784     int format;
785     unsigned long bytes_after;
786     unsigned char *str;
787     unsigned long n_items;
788     int result, status;
789 
790     g_return_val_if_fail (((atom_id >= 0) && (atom_id < ATOM_COUNT)), FALSE);
791     TRACE ("window 0x%lx atom %i", w, atom_id);
792 
793     *str_p = NULL;
794     str = NULL;
795 
796     myDisplayErrorTrapPush (display_info);
797     status = XGetWindowProperty (display_info->dpy, w, display_info->atoms[atom_id],
798                                  0, G_MAXLONG, FALSE, display_info->atoms[UTF8_STRING],
799                                  &type, &format, &n_items, &bytes_after,
800                                  (unsigned char **) &str);
801     result = myDisplayErrorTrapPop (display_info);
802 
803     if ((result != Success) ||
804         (status != Success) ||
805         (str == NULL) ||
806         (type == None))
807     {
808         TRACE ("no UTF8_STRING property found");
809         XFree (str);
810         return FALSE;
811     }
812 
813     if (!check_type_and_format (8, display_info->atoms[UTF8_STRING], -1, format, type))
814     {
815         TRACE ("UTF8_STRING value invalid");
816         XFree (str);
817         return FALSE;
818     }
819 
820     *str_p = (char *) str;
821     *length = n_items;
822 
823     return TRUE;
824 }
825 
826 gboolean
getUTF8String(DisplayInfo * display_info,Window w,int atom_id,gchar ** str_p,guint * length)827 getUTF8String (DisplayInfo *display_info, Window w, int atom_id, gchar **str_p, guint *length)
828 {
829     char *xstr;
830 
831     g_return_val_if_fail (((atom_id >= 0) && (atom_id < ATOM_COUNT)), FALSE);
832     TRACE ("window 0x%lx atom id %i", w, atom_id);
833 
834     if (!getUTF8StringData (display_info, w, atom_id, &xstr, length))
835     {
836         *str_p = NULL;
837         *length = 0;
838 
839         return FALSE;
840     }
841 
842     /* gmalloc the returned string */
843     *str_p = internal_utf8_strndup (xstr, MAX_STR_LENGTH);
844     XFree (xstr);
845 
846     if (!g_utf8_validate (*str_p, -1, NULL))
847     {
848         TRACE ("getUTF8String() returned invalid UTF-8 characters");
849         g_free (*str_p);
850         str_p = NULL;
851         length = 0;
852 
853         return FALSE;
854     }
855 
856     if (*str_p)
857     {
858         xfce_utf8_remove_controls((gchar *) *str_p, -1, NULL);
859     }
860 
861     return TRUE;
862 }
863 
864 gboolean
getUTF8StringList(DisplayInfo * display_info,Window w,int atom_id,gchar *** str_p,guint * n_items)865 getUTF8StringList (DisplayInfo *display_info, Window w, int atom_id, gchar ***str_p, guint *n_items)
866 {
867     char *xstr, *ptr;
868     gchar **retval;
869     guint i, length;
870 
871     g_return_val_if_fail (((atom_id >= 0) && (atom_id < ATOM_COUNT)), FALSE);
872     TRACE ("window 0x%lx atom id %i", w, atom_id);
873 
874     *str_p = NULL;
875     *n_items = 0;
876 
877     if (!getUTF8StringData (display_info, w, atom_id, &xstr, &length) || !length)
878     {
879         return FALSE;
880     }
881 
882     i = 0;
883     while (i < length)
884     {
885         if (!xstr[i])
886         {
887             *n_items = *n_items + 1;
888         }
889         i++;
890     }
891     if (xstr[length - 1])
892     {
893         *n_items = *n_items + 1;
894     }
895 
896     retval = g_new0 (gchar *, *n_items + 1);
897     ptr = xstr;
898 
899     for (i = 0; i < *n_items; i++)
900     {
901         if (g_utf8_validate (ptr, -1, NULL))
902         {
903             retval[i] = internal_utf8_strndup (ptr, MAX_STR_LENGTH);
904             xfce_utf8_remove_controls((gchar *) retval[i], -1, NULL);
905         }
906         else
907         {
908             TRACE ("getUTF8StringList() returned invalid UTF-8 characters in string #%i.", i);
909             retval[i] = g_strdup ("");
910         }
911         ptr += strlen (ptr) + 1;
912     }
913     XFree (xstr);
914     *str_p = retval;
915 
916     return TRUE;
917 }
918 
919 gboolean
getWindowProp(DisplayInfo * display_info,Window window,int atom_id,Window * w)920 getWindowProp (DisplayInfo *display_info, Window window, int atom_id, Window *w)
921 {
922     Atom type;
923     int format;
924     unsigned long nitems;
925     unsigned long bytes_after;
926     unsigned char *prop;
927     int result, status;
928 
929     g_return_val_if_fail (window != None, FALSE);
930     g_return_val_if_fail (((atom_id >= 0) && (atom_id < ATOM_COUNT)), FALSE);
931     TRACE ("window 0x%lx atom id %i", window, atom_id);
932 
933     *w = None;
934     prop = NULL;
935 
936     myDisplayErrorTrapPush (display_info);
937     status = XGetWindowProperty (display_info->dpy, window, display_info->atoms[atom_id],
938                                  0L, 1L, FALSE, XA_WINDOW, &type, &format, &nitems,
939                                  &bytes_after, (unsigned char **) &prop);
940     result = myDisplayErrorTrapPop (display_info);
941 
942     if ((status == Success) && (result == Success))
943     {
944         if (prop)
945         {
946             *w = *((Window *) prop);
947             XFree (prop);
948         }
949         if (!prop || !check_type_and_format (32, XA_WINDOW, -1, format, type))
950         {
951             *w = None;
952             return FALSE;
953         }
954     }
955 
956     return (result == Success);
957 }
958 
959 gboolean
getWindowHostname(DisplayInfo * display_info,Window w,gchar ** machine)960 getWindowHostname (DisplayInfo *display_info, Window w, gchar **machine)
961 {
962     TRACE ("window 0x%lx", w);
963 
964     g_return_val_if_fail (machine != NULL, FALSE);
965     g_return_val_if_fail (w != None, FALSE);
966     g_return_val_if_fail (display_info != NULL, FALSE);
967 
968     *machine = getTextProperty (display_info, w, display_info->atoms[WM_CLIENT_MACHINE]);
969     if (*machine == NULL)
970     {
971         *machine = g_strdup ("");
972         return FALSE;
973     }
974 
975     return TRUE;
976 }
977 
978 gboolean
getWindowName(DisplayInfo * display_info,Window w,gchar ** name)979 getWindowName (DisplayInfo *display_info, Window w, gchar **name)
980 {
981     char *str;
982     guint len;
983 
984     TRACE ("window 0x%lx", w);
985 
986     g_return_val_if_fail (name != NULL, FALSE);
987     *name = NULL;
988     g_return_val_if_fail (w != None, FALSE);
989 
990     if (getUTF8StringData (display_info, w, NET_WM_NAME, &str, &len))
991     {
992         *name = internal_utf8_strndup (str, MAX_STR_LENGTH);
993         xfce_utf8_remove_controls(*name, -1, NULL);
994         XFree (str);
995         return TRUE;
996     }
997 
998     *name = getTextProperty (display_info, w, XA_WM_NAME);
999     if (*name == NULL)
1000     {
1001         *name = g_strdup ("");
1002         return FALSE;
1003     }
1004 
1005     xfce_utf8_remove_controls(*name, -1, NULL);
1006 
1007     return TRUE;
1008 }
1009 
1010 gboolean
getWindowRole(DisplayInfo * display_info,Window window,gchar ** role)1011 getWindowRole (DisplayInfo *display_info, Window window, gchar **role)
1012 {
1013     g_return_val_if_fail (role != NULL, FALSE);
1014     g_return_val_if_fail (window != None, FALSE);
1015     TRACE ("window 0x%lx", window);
1016 
1017     *role = getTextProperty (display_info, window, display_info->atoms[WM_WINDOW_ROLE]);
1018 
1019     return (*role != NULL);
1020 }
1021 
1022 Window
getClientLeader(DisplayInfo * display_info,Window window)1023 getClientLeader (DisplayInfo *display_info, Window window)
1024 {
1025     Window client_leader;
1026 
1027     g_return_val_if_fail (window != None, None);
1028     TRACE ("window 0x%lx", window);
1029 
1030     client_leader = None;
1031     getWindowProp (display_info, window, WM_CLIENT_LEADER, &client_leader);
1032 
1033     return client_leader;
1034 }
1035 
1036 gboolean
getNetWMUserTime(DisplayInfo * display_info,Window window,guint32 * timestamp)1037 getNetWMUserTime (DisplayInfo *display_info, Window window, guint32 *timestamp)
1038 {
1039     Atom actual_type;
1040     int actual_format;
1041     unsigned long nitems;
1042     unsigned long bytes_after;
1043     unsigned char *data = NULL;
1044     int result, status;
1045 
1046     g_return_val_if_fail (window != None, FALSE);
1047     TRACE ("window 0x%lx", window);
1048 
1049     myDisplayErrorTrapPush (display_info);
1050     status = XGetWindowProperty (display_info->dpy, window,
1051                                  display_info->atoms[NET_WM_USER_TIME],
1052                                  0L, 1L, FALSE, XA_CARDINAL, &actual_type,
1053                                  &actual_format, &nitems, &bytes_after,
1054                                  (unsigned char **) &data);
1055     result = myDisplayErrorTrapPop (display_info);
1056 
1057     if ((status == Success) &&
1058         (result == Success) &&
1059         (data != NULL) &&
1060         (actual_type == XA_CARDINAL) &&
1061         (nitems == 1) &&
1062         (bytes_after == 0))
1063     {
1064         *timestamp = *((guint32 *) data);
1065         XFree (data);
1066         return TRUE;
1067     }
1068 
1069     XFree (data);
1070     *timestamp = (guint32) CurrentTime;
1071 
1072     return FALSE;
1073 }
1074 
1075 Window
getNetWMUserTimeWindow(DisplayInfo * display_info,Window window)1076 getNetWMUserTimeWindow (DisplayInfo *display_info, Window window)
1077 {
1078     Window user_time_win;
1079 
1080     g_return_val_if_fail (window != None, None);
1081     TRACE ("window 0x%lx", window);
1082 
1083     user_time_win = None;
1084     if (getWindowProp (display_info, window, NET_WM_USER_TIME_WINDOW, &user_time_win))
1085     {
1086         return user_time_win;
1087     }
1088     return window;
1089 }
1090 
1091 gboolean
getClientID(DisplayInfo * display_info,Window window,gchar ** client_id)1092 getClientID (DisplayInfo *display_info, Window window, gchar **client_id)
1093 {
1094     Window id;
1095 
1096     g_return_val_if_fail (client_id != NULL, FALSE);
1097     *client_id = NULL;
1098     g_return_val_if_fail (window != None, FALSE);
1099     TRACE ("window 0x%lx", window);
1100 
1101     if (getWindowProp (display_info, window, WM_CLIENT_LEADER, &id) && (id != None))
1102     {
1103         *client_id = getTextProperty (display_info, id, display_info->atoms[SM_CLIENT_ID]);
1104     }
1105 
1106     return (*client_id != NULL);
1107 }
1108 
1109 gboolean
getWindowCommand(DisplayInfo * display_info,Window window,char *** argv,int * argc)1110 getWindowCommand (DisplayInfo *display_info, Window window, char ***argv, int *argc)
1111 {
1112     Window id;
1113 
1114     *argc = 0;
1115     g_return_val_if_fail (window != None, FALSE);
1116     TRACE ("window 0x%lx", window);
1117 
1118     if (XGetCommand (display_info->dpy, window, argv, argc) && (*argc > 0))
1119     {
1120         return TRUE;
1121     }
1122     if (getWindowProp (display_info, window, WM_CLIENT_LEADER, &id) && (id != None))
1123     {
1124         if (XGetCommand (display_info->dpy, id, argv, argc) && (*argc > 0))
1125         {
1126             return TRUE;
1127         }
1128     }
1129     return FALSE;
1130 }
1131 
1132 gboolean
getKDEIcon(DisplayInfo * display_info,Window window,Pixmap * pixmap,Pixmap * mask)1133 getKDEIcon (DisplayInfo *display_info, Window window, Pixmap * pixmap, Pixmap * mask)
1134 {
1135     Atom type;
1136     int format;
1137     unsigned long nitems;
1138     unsigned long bytes_after;
1139     unsigned char *data;
1140     Pixmap *icons;
1141     int result, status;
1142 
1143     TRACE ("window 0x%lx", window);
1144 
1145     *pixmap = None;
1146     *mask = None;
1147     icons = NULL;
1148     data = NULL;
1149 
1150     myDisplayErrorTrapPush (display_info);
1151     status = XGetWindowProperty (display_info->dpy, window,
1152                                  display_info->atoms[KWM_WIN_ICON],
1153                                  0L, G_MAXLONG, FALSE,
1154                                  display_info->atoms[KWM_WIN_ICON],
1155                                  &type, &format, &nitems, &bytes_after,
1156                                  (unsigned char **) &data);
1157     result = myDisplayErrorTrapPop (display_info);
1158 
1159     if ((status != Success) ||
1160         (result != Success) ||
1161         (data == NULL) ||
1162         (type != display_info->atoms[KWM_WIN_ICON]))
1163     {
1164         XFree (data);
1165         return FALSE;
1166     }
1167 
1168     icons = (Pixmap *) data;
1169     *pixmap = icons[0];
1170     *mask = icons[1];
1171 
1172     XFree (icons);
1173 
1174     return TRUE;
1175 }
1176 
1177 gboolean
getRGBIconData(DisplayInfo * display_info,Window window,unsigned long ** data,unsigned long * nitems)1178 getRGBIconData (DisplayInfo *display_info, Window window, unsigned long **data, unsigned long *nitems)
1179 {
1180     Atom type;
1181     int format;
1182     unsigned long bytes_after;
1183     int result, status;
1184 
1185     TRACE ("window 0x%lx", window);
1186 
1187     *data = NULL;
1188     type = None;
1189 
1190     myDisplayErrorTrapPush (display_info);
1191     status = XGetWindowProperty (display_info->dpy, window,
1192                                  display_info->atoms[NET_WM_ICON],
1193                                  0L, G_MAXLONG, FALSE, XA_CARDINAL,
1194                                  &type, &format, nitems, &bytes_after,
1195                                  (unsigned char **) data);
1196     result = myDisplayErrorTrapPop (display_info);
1197 
1198     if ((status != Success) ||
1199         (result != Success) ||
1200         (type != XA_CARDINAL))
1201     {
1202         XFree (*data);
1203         *data = NULL;
1204         return FALSE;
1205     }
1206 
1207     return (data != NULL);
1208 }
1209 
1210 gboolean
getOpacity(DisplayInfo * display_info,Window window,guint32 * opacity)1211 getOpacity (DisplayInfo *display_info, Window window, guint32 *opacity)
1212 {
1213     long val;
1214 
1215     g_return_val_if_fail (window != None, FALSE);
1216     g_return_val_if_fail (opacity != NULL, FALSE);
1217     TRACE ("window 0x%lx", window);
1218 
1219     val = 0;
1220     if (getHint (display_info, window, NET_WM_WINDOW_OPACITY, &val))
1221     {
1222         *opacity = (guint32) val;
1223         return TRUE;
1224     }
1225 
1226     return FALSE;
1227 }
1228 
1229 gboolean
getBypassCompositor(DisplayInfo * display_info,Window window,guint32 * bypass)1230 getBypassCompositor (DisplayInfo *display_info, Window window, guint32 *bypass)
1231 {
1232     long val;
1233 
1234     g_return_val_if_fail (window != None, FALSE);
1235     g_return_val_if_fail (bypass != NULL, FALSE);
1236     TRACE ("window 0x%lx", window);
1237 
1238     val = 0;
1239     if (getHint (display_info, window, NET_WM_BYPASS_COMPOSITOR, &val))
1240     {
1241         *bypass = (guint32) val;
1242         return TRUE;
1243     }
1244 
1245     return FALSE;
1246 }
1247 
1248 gboolean
getOpacityLock(DisplayInfo * display_info,Window window)1249 getOpacityLock (DisplayInfo *display_info, Window window)
1250 {
1251     long val;
1252 
1253     g_return_val_if_fail (window != None, FALSE);
1254     TRACE ("window 0x%lx", window);
1255 
1256     /* only presence/absence matters */
1257     return !!getHint (display_info, window, NET_WM_WINDOW_OPACITY_LOCKED, &val);
1258 }
1259 
1260 gboolean
setXAtomManagerOwner(DisplayInfo * display_info,Atom atom,Window root,Window w)1261 setXAtomManagerOwner (DisplayInfo *display_info, Atom atom, Window root, Window w)
1262 {
1263     XClientMessageEvent ev;
1264     guint32 server_time;
1265     int status;
1266 
1267     g_return_val_if_fail (root != None, FALSE);
1268     TRACE ("window 0x%lx", w);
1269 
1270     server_time = myDisplayGetCurrentTime (display_info);
1271     status = XSetSelectionOwner (display_info->dpy, atom, w, server_time);
1272 
1273     if ((status == BadAtom) || (status == BadWindow))
1274     {
1275         return FALSE;
1276     }
1277 
1278     if (XGetSelectionOwner (display_info->dpy, atom) == w)
1279     {
1280         ev.type = ClientMessage;
1281         ev.message_type = atom;
1282         ev.format = 32;
1283         ev.data.l[0] = (long) server_time;
1284         ev.data.l[1] = (long) atom;
1285         ev.data.l[2] = (long) w;
1286         ev.data.l[3] = (long) 0L;
1287         ev.data.l[4] = (long) 0L;
1288         ev.window = root;
1289 
1290         XSendEvent (display_info->dpy, root, FALSE, StructureNotifyMask, (XEvent *) &ev);
1291 
1292         return TRUE;
1293     }
1294 
1295     return FALSE;
1296 }
1297 
1298 gboolean
setAtomIdManagerOwner(DisplayInfo * display_info,int atom_id,Window root,Window w)1299 setAtomIdManagerOwner (DisplayInfo *display_info, int atom_id, Window root, Window w)
1300 {
1301     g_return_val_if_fail (((atom_id >= 0) && (atom_id < ATOM_COUNT)), FALSE);
1302     TRACE ("atom %i", atom_id);
1303 
1304     return setXAtomManagerOwner(display_info, display_info->atoms[atom_id], root, w);
1305 }
1306 
1307 void
updateXserverTime(DisplayInfo * display_info)1308 updateXserverTime (DisplayInfo *display_info)
1309 {
1310     char c = '\0';
1311 
1312     g_return_if_fail (display_info);
1313 
1314     XChangeProperty (display_info->dpy, display_info->timestamp_win,
1315                      display_info->atoms[XFWM4_TIMESTAMP_PROP],
1316                      display_info->atoms[XFWM4_TIMESTAMP_PROP],
1317                      8, PropModeReplace, (unsigned char *) &c, 1);
1318 }
1319 
1320 guint32
getXServerTime(DisplayInfo * display_info)1321 getXServerTime (DisplayInfo *display_info)
1322 {
1323     ScreenInfo *screen_info;
1324     XEvent xevent;
1325     XfwmEvent *event;
1326     guint32 timestamp;
1327 
1328     g_return_val_if_fail (display_info, CurrentTime);
1329     timestamp = myDisplayGetCurrentTime (display_info);
1330     if (timestamp == CurrentTime)
1331     {
1332         screen_info = myDisplayGetDefaultScreen (display_info);
1333         g_return_val_if_fail (screen_info,  CurrentTime);
1334 
1335         TRACE ("using X server roundtrip");
1336         updateXserverTime (display_info);
1337         XWindowEvent (display_info->dpy, display_info->timestamp_win, PropertyChangeMask, &xevent);
1338         event = xfwm_device_translate_event (display_info->devices, &xevent, NULL);
1339         timestamp = myDisplayUpdateCurrentTime (display_info, event);
1340         xfwm_device_free_event (event);
1341     }
1342 
1343     TRACE ("timestamp=%u", (guint32) timestamp);
1344     return timestamp;
1345 }
1346 
1347 #ifdef ENABLE_KDE_SYSTRAY_PROXY
1348 gboolean
checkKdeSystrayWindow(DisplayInfo * display_info,Window window)1349 checkKdeSystrayWindow (DisplayInfo *display_info, Window window)
1350 {
1351     Atom actual_type;
1352     int actual_format;
1353     unsigned long nitems;
1354     unsigned long bytes_after;
1355     unsigned char *data;
1356     Window trayIconForWindow;
1357     int result, status;
1358 
1359     g_return_val_if_fail (window != None, FALSE);
1360     TRACE ("window 0x%lx", window);
1361 
1362     trayIconForWindow = None;
1363     data = NULL;
1364 
1365     myDisplayErrorTrapPush (display_info);
1366     status = XGetWindowProperty (display_info->dpy, window,
1367                                  display_info->atoms[KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR],
1368                                  0L, sizeof(Window), FALSE, XA_WINDOW, &actual_type,
1369                                  &actual_format, &nitems, &bytes_after,
1370                                  (unsigned char **) &data);
1371     result = myDisplayErrorTrapPop (display_info);
1372 
1373     if ((status != Success) || (result != Success))
1374     {
1375         XFree (data);
1376         return FALSE;
1377     }
1378 
1379     if (data)
1380     {
1381         trayIconForWindow = *((Window *) data);
1382         XFree (data);
1383     }
1384 
1385     if ((actual_format == None) || (actual_type != XA_WINDOW) || (trayIconForWindow == None))
1386     {
1387         return FALSE;
1388     }
1389 
1390     return TRUE;
1391 }
1392 
1393 void
sendSystrayReqDock(DisplayInfo * display_info,Window window,Window systray)1394 sendSystrayReqDock(DisplayInfo *display_info, Window window, Window systray)
1395 {
1396     XClientMessageEvent xev;
1397 
1398     g_return_if_fail (window != None);
1399     g_return_if_fail (systray != None);
1400     TRACE ("window 0x%lx", window);
1401 
1402     xev.type = ClientMessage;
1403     xev.window = systray;
1404     xev.message_type = display_info->atoms[NET_SYSTEM_TRAY_OPCODE];
1405     xev.format = 32;
1406     xev.data.l[0] = (long) myDisplayGetCurrentTime (display_info);
1407     xev.data.l[1] = (long) 0L; /* SYSTEM_TRAY_REQUEST_DOCK */
1408     xev.data.l[2] = (long) window;
1409     xev.data.l[3] = (long) 0L; /* Nada */
1410     xev.data.l[4] = (long) 0L; /* Niet */
1411 
1412     XSendEvent (display_info->dpy, systray, FALSE, NoEventMask, (XEvent *) & xev);
1413 }
1414 
1415 Window
getSystrayWindow(DisplayInfo * display_info,Atom net_system_tray_selection)1416 getSystrayWindow (DisplayInfo *display_info, Atom net_system_tray_selection)
1417 {
1418     Window systray_win;
1419 
1420     TRACE ("entering");
1421 
1422     myDisplayErrorTrapPush (display_info);
1423     systray_win = XGetSelectionOwner (display_info->dpy, net_system_tray_selection);
1424     if (systray_win)
1425     {
1426         XSelectInput (display_info->dpy, systray_win, StructureNotifyMask);
1427     }
1428     myDisplayErrorTrapPopIgnored (display_info);
1429     TRACE ("new systray window:  0x%lx", systray_win);
1430 
1431     return systray_win;
1432 }
1433 #endif
1434 
1435 #ifdef HAVE_LIBSTARTUP_NOTIFICATION
1436 gboolean
getWindowStartupId(DisplayInfo * display_info,Window w,gchar ** startup_id)1437 getWindowStartupId (DisplayInfo *display_info, Window w, gchar **startup_id)
1438 {
1439     char *str;
1440     guint len;
1441 
1442     g_return_val_if_fail (startup_id != NULL, FALSE);
1443     *startup_id = NULL;
1444     g_return_val_if_fail (w != None, FALSE);
1445     TRACE ("window 0x%lx", w);
1446 
1447     if (getUTF8StringData (display_info, w, NET_STARTUP_ID, &str, &len))
1448     {
1449         *startup_id = g_strdup (str);
1450         XFree (str);
1451         return TRUE;
1452     }
1453 
1454     *startup_id = getTextProperty (display_info, w, display_info->atoms[NET_STARTUP_ID]);
1455 
1456     return (*startup_id != NULL);
1457 }
1458 #endif
1459 
1460 GPid
getWindowPID(DisplayInfo * display_info,Window w)1461 getWindowPID (DisplayInfo *display_info, Window w)
1462 {
1463     long pid = 0;
1464 #ifdef HAVE_XRES
1465     XResClientIdSpec client_specs;
1466     XResClientIdValue *client_ids = NULL;
1467     int i;
1468     int result;
1469     long num_ids;
1470 
1471     if (display_info->have_xres)
1472     {
1473         client_specs.client = w;
1474         client_specs.mask = XRES_CLIENT_ID_PID_MASK;
1475 
1476         myDisplayErrorTrapPush (display_info);
1477 
1478         XResQueryClientIds (display_info->dpy, 1, &client_specs, &num_ids, &client_ids);
1479 
1480         result = myDisplayErrorTrapPop (display_info);
1481 
1482         if (result == Success)
1483         {
1484             for (i = 0; i < num_ids; i++)
1485             {
1486                 if (client_ids[i].spec.mask == XRES_CLIENT_ID_PID_MASK)
1487                 {
1488                     CARD32 *value = client_ids[i].value;
1489                     pid = (long) *value;
1490                     break;
1491                 }
1492             }
1493 
1494             XFree(client_ids);
1495 
1496             if (pid > 0)
1497             {
1498                 return (GPid) pid;
1499             }
1500         }
1501     }
1502 #endif /* HAVE_XRES */
1503 
1504     getHint (display_info, w, NET_WM_PID, (long *) &pid);
1505 
1506     return (GPid) pid;
1507 }
1508 
1509 unsigned int
getOpaqueRegionRects(DisplayInfo * display_info,Window w,XRectangle ** p_rects)1510 getOpaqueRegionRects (DisplayInfo *display_info, Window w, XRectangle **p_rects)
1511 {
1512     gulong *data;
1513     XRectangle *rects;
1514     int i, nitems, nrects;
1515 
1516     TRACE ("window 0x%lx", w);
1517     if (getCardinalList (display_info, w, NET_WM_OPAQUE_REGION, &data, &nitems))
1518     {
1519         if (nitems % 4)
1520         {
1521             if (data)
1522             {
1523                 XFree (data);
1524             }
1525 
1526             return 0;
1527         }
1528 
1529         rects = g_new0 (XRectangle, nitems / 4);
1530         nrects = 0;
1531         i = 0;
1532 
1533         while (i < nitems)
1534         {
1535             XRectangle *rect = &rects[nrects++];
1536 
1537             rect->x = data[i++];
1538             rect->y = data[i++];
1539             rect->width = data[i++];
1540             rect->height = data[i++];
1541         }
1542 
1543         XFree (data);
1544         *p_rects = rects;
1545         return (unsigned int) nrects;
1546     }
1547 
1548     return 0;
1549 }
1550