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