Bug Summary

File:_build/../libvnck/xutils.c
Warning:line 2614, column 25
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name xutils.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/_build -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-19/lib/clang/19 -I libvnck/libvnck-3.so.0.3.0.p -I libvnck -I ../libvnck -I . -I .. -I /usr/include/cairo -I /usr/include/libpng16 -I /usr/include/freetype2 -I /usr/include/pixman-1 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/startup-notification-1.0 -D _FILE_OFFSET_BITS=64 -D G_LOG_DOMAIN="Vnck" -D VNCK_I_KNOW_THIS_IS_UNSTABLE -D VNCK_LOCALEDIR="/usr/local/share/locale" -D VNCK_COMPILATION -D SN_API_NOT_YET_FROZEN=1 -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-07-25-113509-9305-1 -x c ../libvnck/xutils.c
1/* Xlib utils */
2
3
4/*
5 * Copyright (C) 2001 Havoc Pennington
6 * Copyright (C) 2005-2007 Vincent Untz
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <config.h>
23#include "xutils.h"
24#include <string.h>
25#include <stdio.h>
26#include <cairo-xlib.h>
27#if HAVE_CAIRO_XLIB_XRENDER1
28#include <cairo-xlib-xrender.h>
29#endif
30#include "screen.h"
31#include "window.h"
32#include "private.h"
33
34gboolean
35_vnck_get_cardinal (Screen *screen,
36 Window xwindow,
37 Atom atom,
38 int *val)
39{
40 Display *display;
41 Atom type;
42 int format;
43 gulong nitems;
44 gulong bytes_after;
45 gulong *num;
46 int err, result;
47
48 display = DisplayOfScreen (screen)((screen)->display);
49
50 *val = 0;
51
52 _vnck_error_trap_push (display);
53 type = None0L;
54 result = XGetWindowProperty (display,
55 xwindow,
56 atom,
57 0, G_MAXLONG9223372036854775807L,
58 False0, XA_CARDINAL((Atom) 6), &type, &format, &nitems,
59 &bytes_after, (void*)&num);
60 err = _vnck_error_trap_pop (display);
61 if (err != Success0 ||
62 result != Success0)
63 return FALSE(0);
64
65 if (type != XA_CARDINAL((Atom) 6))
66 {
67 XFree (num);
68 return FALSE(0);
69 }
70
71 *val = *num;
72
73 XFree (num);
74
75 return TRUE(!(0));
76}
77
78int
79_vnck_get_wm_state (Screen *screen,
80 Window xwindow)
81{
82 Display *display;
83 Atom type;
84 int format;
85 gulong nitems;
86 gulong bytes_after;
87 gulong *num;
88 int err, result;
89 Atom wm_state;
90 int retval;
91
92 display = DisplayOfScreen (screen)((screen)->display);
93
94 wm_state = _vnck_atom_get ("WM_STATE")cdk_x11_get_xatom_by_name ("WM_STATE");
95 retval = NormalState1;
96
97 _vnck_error_trap_push (display);
98 type = None0L;
99 result = XGetWindowProperty (display,
100 xwindow,
101 wm_state,
102 0, G_MAXLONG9223372036854775807L,
103 False0, wm_state, &type, &format, &nitems,
104 &bytes_after, (void*)&num);
105 err = _vnck_error_trap_pop (display);
106 if (err != Success0 ||
107 result != Success0)
108 return retval;
109
110 if (type != wm_state)
111 {
112 XFree (num);
113 return retval;
114 }
115
116 retval = *num;
117
118 XFree (num);
119
120 return retval;
121}
122
123gboolean
124_vnck_get_window (Screen *screen,
125 Window xwindow,
126 Atom atom,
127 Window *val)
128{
129 Display *display;
130 Atom type;
131 int format;
132 gulong nitems;
133 gulong bytes_after;
134 Window *w;
135 int err, result;
136
137 display = DisplayOfScreen (screen)((screen)->display);
138
139 *val = 0;
140
141 _vnck_error_trap_push (display);
142 type = None0L;
143 result = XGetWindowProperty (display,
144 xwindow,
145 atom,
146 0, G_MAXLONG9223372036854775807L,
147 False0, XA_WINDOW((Atom) 33), &type, &format, &nitems,
148 &bytes_after, (void*)&w);
149 err = _vnck_error_trap_pop (display);
150 if (err != Success0 ||
151 result != Success0)
152 return FALSE(0);
153
154 if (type != XA_WINDOW((Atom) 33))
155 {
156 XFree (w);
157 return FALSE(0);
158 }
159
160 *val = *w;
161
162 XFree (w);
163
164 return TRUE(!(0));
165}
166
167gboolean
168_vnck_get_pixmap (Screen *screen,
169 Window xwindow,
170 Atom atom,
171 Pixmap *val)
172{
173 Display *display;
174 Atom type;
175 int format;
176 gulong nitems;
177 gulong bytes_after;
178 Window *w;
179 int err, result;
180
181 display = DisplayOfScreen (screen)((screen)->display);
182
183 *val = 0;
184
185 _vnck_error_trap_push (display);
186 type = None0L;
187 result = XGetWindowProperty (display,
188 xwindow,
189 atom,
190 0, G_MAXLONG9223372036854775807L,
191 False0, XA_PIXMAP((Atom) 20), &type, &format, &nitems,
192 &bytes_after, (void*)&w);
193 err = _vnck_error_trap_pop (display);
194 if (err != Success0 ||
195 result != Success0)
196 return FALSE(0);
197
198 if (type != XA_PIXMAP((Atom) 20))
199 {
200 XFree (w);
201 return FALSE(0);
202 }
203
204 *val = *w;
205
206 XFree (w);
207
208 return TRUE(!(0));
209}
210
211gboolean
212_vnck_get_atom (Screen *screen,
213 Window xwindow,
214 Atom atom,
215 Atom *val)
216{
217 Display *display;
218 Atom type;
219 int format;
220 gulong nitems;
221 gulong bytes_after;
222 Atom *a;
223 int err, result;
224
225 display = DisplayOfScreen (screen)((screen)->display);
226
227 *val = 0;
228
229 _vnck_error_trap_push (display);
230 type = None0L;
231 result = XGetWindowProperty (display,
232 xwindow,
233 atom,
234 0, G_MAXLONG9223372036854775807L,
235 False0, XA_ATOM((Atom) 4), &type, &format, &nitems,
236 &bytes_after, (void*)&a);
237 err = _vnck_error_trap_pop (display);
238 if (err != Success0 ||
239 result != Success0)
240 return FALSE(0);
241
242 if (type != XA_ATOM((Atom) 4))
243 {
244 XFree (a);
245 return FALSE(0);
246 }
247
248 *val = *a;
249
250 XFree (a);
251
252 return TRUE(!(0));
253}
254
255static char*
256text_property_to_utf8 (Display *display,
257 const XTextProperty *prop)
258{
259 CdkDisplay *cdkdisplay;
260 char **list;
261 int count;
262 char *retval;
263
264 list = NULL((void*)0);
265
266 cdkdisplay = _vnck_cdk_display_lookup_from_display (display);
267 if (!cdkdisplay)
268 return NULL((void*)0);
269
270 count = cdk_text_property_to_utf8_list_for_display (cdkdisplay,
271 cdk_x11_xatom_to_atom (prop->encoding),
272 prop->format,
273 prop->value,
274 prop->nitems,
275 &list);
276
277 if (count == 0)
278 retval = NULL((void*)0);
279 else
280 {
281 retval = list[0];
282 list[0] = g_strdup ("")g_strdup_inline (""); /* something to free */
283 }
284
285 g_strfreev (list);
286
287 return retval;
288}
289
290char*
291_vnck_get_text_property (Screen *screen,
292 Window xwindow,
293 Atom atom)
294{
295 Display *display;
296 XTextProperty text;
297 char *retval;
298
299 display = DisplayOfScreen (screen)((screen)->display);
300
301 _vnck_error_trap_push (display);
302
303 text.nitems = 0;
304 if (XGetTextProperty (display,
305 xwindow,
306 &text,
307 atom))
308 {
309 retval = text_property_to_utf8 (display, &text);
310
311 if (text.value)
312 XFree (text.value);
313 }
314 else
315 {
316 retval = NULL((void*)0);
317 }
318
319 _vnck_error_trap_pop (display);
320
321 return retval;
322}
323
324static char*
325_vnck_get_string_property_latin1 (Screen *screen,
326 Window xwindow,
327 Atom atom)
328{
329 Display *display;
330 Atom type;
331 int format;
332 gulong nitems;
333 gulong bytes_after;
334 gchar *str;
335 int err, result;
336 char *retval;
337
338 display = DisplayOfScreen (screen)((screen)->display);
339
340 _vnck_error_trap_push (display);
341 str = NULL((void*)0);
342 result = XGetWindowProperty (display,
343 xwindow, atom,
344 0, G_MAXLONG9223372036854775807L,
345 False0, XA_STRING((Atom) 31), &type, &format, &nitems,
346 &bytes_after, (guchar **)&str);
347
348 err = _vnck_error_trap_pop (display);
349 if (err != Success0 ||
350 result != Success0)
351 return NULL((void*)0);
352
353 if (type != XA_STRING((Atom) 31))
354 {
355 XFree (str);
356 return NULL((void*)0);
357 }
358
359 retval = g_strdup (str)g_strdup_inline (str);
360
361 XFree (str);
362
363 return retval;
364}
365
366char*
367_vnck_get_utf8_property (Screen *screen,
368 Window xwindow,
369 Atom atom)
370{
371 Display *display;
372 Atom type;
373 int format;
374 gulong nitems;
375 gulong bytes_after;
376 gchar *val;
377 int err, result;
378 char *retval;
379 Atom utf8_string;
380
381 display = DisplayOfScreen (screen)((screen)->display);
382
383 utf8_string = _vnck_atom_get ("UTF8_STRING")cdk_x11_get_xatom_by_name ("UTF8_STRING");
384
385 _vnck_error_trap_push (display);
386 type = None0L;
387 val = NULL((void*)0);
388 result = XGetWindowProperty (display,
389 xwindow,
390 atom,
391 0, G_MAXLONG9223372036854775807L,
392 False0, utf8_string,
393 &type, &format, &nitems,
394 &bytes_after, (guchar **)&val);
395 err = _vnck_error_trap_pop (display);
396
397 if (err != Success0 ||
398 result != Success0)
399 return NULL((void*)0);
400
401 if (type != utf8_string ||
402 format != 8 ||
403 nitems == 0)
404 {
405 if (val)
406 XFree (val);
407 return NULL((void*)0);
408 }
409
410 if (!g_utf8_validate (val, nitems, NULL((void*)0)))
411 {
412 g_warning ("Property %s contained invalid UTF-8\n",
413 _vnck_atom_name (atom)cdk_x11_get_xatom_name (atom));
414 XFree (val);
415 return NULL((void*)0);
416 }
417
418 retval = g_strndup (val, nitems);
419
420 XFree (val);
421
422 return retval;
423}
424
425gboolean
426_vnck_get_window_list (Screen *screen,
427 Window xwindow,
428 Atom atom,
429 Window **windows,
430 int *len)
431{
432 Display *display;
433 Atom type;
434 int format;
435 gulong nitems;
436 gulong bytes_after;
437 Window *data;
438 int err, result;
439
440 display = DisplayOfScreen (screen)((screen)->display);
441
442 *windows = NULL((void*)0);
443 *len = 0;
444
445 _vnck_error_trap_push (display);
446 type = None0L;
447 result = XGetWindowProperty (display,
448 xwindow,
449 atom,
450 0, G_MAXLONG9223372036854775807L,
451 False0, XA_WINDOW((Atom) 33), &type, &format, &nitems,
452 &bytes_after, (void*)&data);
453 err = _vnck_error_trap_pop (display);
454 if (err != Success0 ||
455 result != Success0)
456 return FALSE(0);
457
458 if (type != XA_WINDOW((Atom) 33))
459 {
460 XFree (data);
461 return FALSE(0);
462 }
463
464 *windows = g_new (Window, nitems)((Window *) g_malloc_n ((nitems), sizeof (Window)));
465 memcpy (*windows, data, sizeof (Window) * nitems);
466 *len = nitems;
467
468 XFree (data);
469
470 return TRUE(!(0));
471}
472
473gboolean
474_vnck_get_atom_list (Screen *screen,
475 Window xwindow,
476 Atom atom,
477 Atom **atoms,
478 int *len)
479{
480 Display *display;
481 Atom type;
482 int format;
483 gulong nitems;
484 gulong bytes_after;
485 Atom *data;
486 int err, result;
487
488 display = DisplayOfScreen (screen)((screen)->display);
489
490 *atoms = NULL((void*)0);
491 *len = 0;
492
493 _vnck_error_trap_push (display);
494 type = None0L;
495 result = XGetWindowProperty (display,
496 xwindow,
497 atom,
498 0, G_MAXLONG9223372036854775807L,
499 False0, XA_ATOM((Atom) 4), &type, &format, &nitems,
500 &bytes_after, (void*)&data);
501 err = _vnck_error_trap_pop (display);
502 if (err != Success0 ||
503 result != Success0)
504 return FALSE(0);
505
506 if (type != XA_ATOM((Atom) 4))
507 {
508 XFree (data);
509 return FALSE(0);
510 }
511
512 *atoms = g_new (Atom, nitems)((Atom *) g_malloc_n ((nitems), sizeof (Atom)));
513 memcpy (*atoms, data, sizeof (Atom) * nitems);
514 *len = nitems;
515
516 XFree (data);
517
518 return TRUE(!(0));
519}
520
521gboolean
522_vnck_get_cardinal_list (Screen *screen,
523 Window xwindow,
524 Atom atom,
525 gulong **cardinals,
526 int *len)
527{
528 Display *display;
529 Atom type;
530 int format;
531 gulong nitems;
532 gulong bytes_after;
533 gulong *nums;
534 int err, result;
535
536 display = DisplayOfScreen (screen)((screen)->display);
537
538 *cardinals = NULL((void*)0);
539 *len = 0;
540
541 _vnck_error_trap_push (display);
542 type = None0L;
543 result = XGetWindowProperty (display,
544 xwindow,
545 atom,
546 0, G_MAXLONG9223372036854775807L,
547 False0, XA_CARDINAL((Atom) 6), &type, &format, &nitems,
548 &bytes_after, (void*)&nums);
549 err = _vnck_error_trap_pop (display);
550 if (err != Success0 ||
551 result != Success0)
552 return FALSE(0);
553
554 if (type != XA_CARDINAL((Atom) 6))
555 {
556 XFree (nums);
557 return FALSE(0);
558 }
559
560 *cardinals = g_new (gulong, nitems)((gulong *) g_malloc_n ((nitems), sizeof (gulong)));
561 memcpy (*cardinals, nums, sizeof (gulong) * nitems);
562 *len = nitems;
563
564 XFree (nums);
565
566 return TRUE(!(0));
567}
568
569char**
570_vnck_get_utf8_list (Screen *screen,
571 Window xwindow,
572 Atom atom)
573{
574 Display *display;
575 Atom type;
576 int format;
577 gulong nitems;
578 gulong bytes_after;
579 char *val;
580 int err, result;
581 Atom utf8_string;
582 char **retval;
583 guint i;
584 guint n_strings;
585 char *p;
586
587 display = DisplayOfScreen (screen)((screen)->display);
588
589 utf8_string = _vnck_atom_get ("UTF8_STRING")cdk_x11_get_xatom_by_name ("UTF8_STRING");
590
591 _vnck_error_trap_push (display);
592 type = None0L;
593 val = NULL((void*)0);
594 result = XGetWindowProperty (display,
595 xwindow,
596 atom,
597 0, G_MAXLONG9223372036854775807L,
598 False0, utf8_string,
599 &type, &format, &nitems,
600 &bytes_after, (void*)&val);
601 err = _vnck_error_trap_pop (display);
602
603 if (err != Success0 ||
604 result != Success0)
605 return NULL((void*)0);
606
607 if (type != utf8_string ||
608 format != 8 ||
609 nitems == 0)
610 {
611 if (val)
612 XFree (val);
613 return NULL((void*)0);
614 }
615
616 /* I'm not sure this is right, but I'm guessing the
617 * property is nul-separated
618 */
619 i = 0;
620 n_strings = 0;
621 while (i < nitems)
622 {
623 if (val[i] == '\0')
624 ++n_strings;
625 ++i;
626 }
627
628 if (val[nitems - 1] != '\0')
629 ++n_strings;
630
631 /* we're guaranteed that val has a nul on the end
632 * by XGetWindowProperty
633 */
634
635 retval = g_new0 (char*, n_strings + 1)((char* *) g_malloc0_n ((n_strings + 1), sizeof (char*)));
636
637 p = val;
638 i = 0;
639 while (i < n_strings)
640 {
641 if (!g_utf8_validate (p, -1, NULL((void*)0)))
642 {
643 g_warning ("Property %s contained invalid UTF-8\n",
644 _vnck_atom_name (atom)cdk_x11_get_xatom_name (atom));
645 XFree (val);
646 g_strfreev (retval);
647 return NULL((void*)0);
648 }
649
650 retval[i] = g_strdup (p)g_strdup_inline (p);
651
652 p = p + strlen (p) + 1;
653 ++i;
654 }
655
656 XFree (val);
657
658 return retval;
659}
660
661void
662_vnck_set_utf8_list (Screen *screen,
663 Window xwindow,
664 Atom atom,
665 char **list)
666{
667 Display *display;
668 Atom utf8_string;
669 GString *flattened;
670 int i;
671
672 display = DisplayOfScreen (screen)((screen)->display);
673
674 utf8_string = _vnck_atom_get ("UTF8_STRING")cdk_x11_get_xatom_by_name ("UTF8_STRING");
675
676 /* flatten to nul-separated list */
677 flattened = g_string_new ("");
678 i = 0;
679 while (list[i] != NULL((void*)0))
680 {
681 g_string_append_len (flattened, list[i],g_string_append_len_inline (flattened, list[i], strlen (list[
i]) + 1)
682 strlen (list[i]) + 1)g_string_append_len_inline (flattened, list[i], strlen (list[
i]) + 1)
;
683 ++i;
684 }
685
686 _vnck_error_trap_push (display);
687
688 XChangeProperty (display,
689 xwindow,
690 atom,
691 utf8_string, 8, PropModeReplace0,
692 (guchar *) flattened->str, flattened->len);
693
694 _vnck_error_trap_pop (display);
695
696 g_string_free (flattened, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(flattened), ((!(0)))) : g_string_free_and_steal (flattened))
: (g_string_free) ((flattened), ((!(0)))))
;
697}
698
699void
700_vnck_error_trap_push (Display *display)
701{
702 CdkDisplay *cdk_display;
703
704 cdk_display = cdk_x11_lookup_xdisplay (display);
705 g_assert (cdk_display != NULL)do { if (cdk_display != ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/xutils.c", 705, ((const char*) (__func__
)), "cdk_display != NULL"); } while (0)
;
706
707 cdk_x11_display_error_trap_push (cdk_display);
708}
709
710int
711_vnck_error_trap_pop (Display *display)
712{
713 CdkDisplay *cdk_display;
714
715 cdk_display = cdk_x11_lookup_xdisplay (display);
716 g_assert (cdk_display != NULL)do { if (cdk_display != ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/xutils.c", 716, ((const char*) (__func__
)), "cdk_display != NULL"); } while (0)
;
717
718 cdk_display_flush (cdk_display);
719 return cdk_x11_display_error_trap_pop (cdk_display);
720}
721
722static CdkFilterReturn
723filter_func (CdkXEvent *cdkxevent,
724 CdkEvent *event G_GNUC_UNUSED__attribute__ ((__unused__)),
725 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
726{
727 XEvent *xevent = cdkxevent;
728#ifdef HAVE_STARTUP_NOTIFICATION1
729 int i;
730 Display *display;
731#endif /* HAVE_STARTUP_NOTIFICATION */
732
733 switch (xevent->type)
734 {
735 case PropertyNotify28:
736 {
737 VnckScreen *screen;
738
739 screen = vnck_screen_get_for_root (xevent->xany.window);
740 if (screen != NULL((void*)0))
741 _vnck_screen_process_property_notify (screen, xevent);
742 else
743 {
744 VnckWindow *window;
745 VnckApplication *app;
746
747 window = vnck_window_get (xevent->xany.window);
748 app = vnck_application_get (xevent->xany.window);
749
750 if (app)
751 _vnck_application_process_property_notify (app, xevent);
752
753 if (window)
754 _vnck_window_process_property_notify (window, xevent);
755 }
756 }
757 break;
758
759 case ConfigureNotify22:
760 {
761 VnckWindow *window;
762
763 window = vnck_window_get (xevent->xconfigure.window);
764
765 if (window)
766 _vnck_window_process_configure_notify (window, xevent);
767 }
768 break;
769
770 case SelectionClear29:
771 {
772 _vnck_desktop_layout_manager_process_event (xevent);
773 }
774 break;
775
776 case ClientMessage33:
777#ifdef HAVE_STARTUP_NOTIFICATION1
778 /* We're cheating as officially libsn requires
779 * us to send all events through sn_display_process_event
780 */
781 i = 0;
782 display = ((XAnyEvent *) xevent)->display;
783
784 while (i < ScreenCount (display)(((_XPrivDisplay)(display))->nscreens))
785 {
786 VnckScreen *s;
787
788 s = _vnck_screen_get_existing (i);
789 if (s != NULL((void*)0))
790 sn_display_process_event (_vnck_screen_get_sn_display (s),
791 xevent);
792
793 ++i;
794 }
795#endif /* HAVE_STARTUP_NOTIFICATION */
796 break;
797
798 default:
799 break;
800 }
801
802 return CDK_FILTER_CONTINUE;
803}
804
805static gboolean _vnck_event_filter_initialized = FALSE(0);
806
807void
808_vnck_event_filter_init (void)
809{
810
811 if (!_vnck_event_filter_initialized)
812 {
813 cdk_window_add_filter (NULL((void*)0), filter_func, NULL((void*)0));
814 _vnck_event_filter_initialized = TRUE(!(0));
815 }
816}
817
818void
819_vnck_event_filter_shutdown (void)
820{
821
822 if (_vnck_event_filter_initialized)
823 {
824 cdk_window_remove_filter (NULL((void*)0), filter_func, NULL((void*)0));
825 _vnck_event_filter_initialized = FALSE(0);
826 }
827}
828
829int
830_vnck_xid_equal (gconstpointer v1,
831 gconstpointer v2)
832{
833 return *((const gulong*) v1) == *((const gulong*) v2);
834}
835
836guint
837_vnck_xid_hash (gconstpointer v)
838{
839 gulong val = * (const gulong *) v;
840
841 /* I'm not sure this works so well. */
842#if GLIB_SIZEOF_LONG8 > 4
843 return (guint) (val ^ (val >> 32));
844#else
845 return val;
846#endif
847}
848
849void
850_vnck_iconify (Screen *screen,
851 Window xwindow)
852{
853 Display *display;
854
855 display = DisplayOfScreen (screen)((screen)->display);
856
857 _vnck_error_trap_push (display);
858 XIconifyWindow (display, xwindow, DefaultScreen (display)(((_XPrivDisplay)(display))->default_screen));
859 _vnck_error_trap_pop (display);
860}
861
862void
863_vnck_deiconify (Screen *screen,
864 Window xwindow)
865{
866 /* We need special precautions, because CDK doesn't like
867 * XMapWindow() called on its windows, need to use the
868 * CDK functions
869 */
870 Display *display;
871 CdkWindow *cdkwindow;
872
873 display = DisplayOfScreen (screen)((screen)->display);
874 cdkwindow = _vnck_cdk_window_lookup_from_window (screen, xwindow);
875
876 _vnck_error_trap_push (display);
877 if (cdkwindow)
878 cdk_window_show (cdkwindow);
879 else
880 XMapRaised (display, xwindow);
881 _vnck_error_trap_pop (display);
882}
883
884void
885_vnck_close (VnckScreen *screen,
886 Window xwindow,
887 Time timestamp)
888{
889 Screen *xscreen;
890 Display *display;
891 Window root;
892 XEvent xev;
893
894 xscreen = _vnck_screen_get_xscreen (screen);
895 display = DisplayOfScreen (xscreen)((xscreen)->display);
896 root = RootWindowOfScreen (xscreen)((xscreen)->root);
897
898 xev.xclient.type = ClientMessage33;
899 xev.xclient.serial = 0;
900 xev.xclient.send_event = True1;
901 xev.xclient.display = display;
902 xev.xclient.window = xwindow;
903 xev.xclient.message_type = _vnck_atom_get ("_NET_CLOSE_WINDOW")cdk_x11_get_xatom_by_name ("_NET_CLOSE_WINDOW");
904 xev.xclient.format = 32;
905 xev.xclient.data.l[0] = timestamp;
906 xev.xclient.data.l[1] = _vnck_get_client_type ();
907 xev.xclient.data.l[2] = 0;
908 xev.xclient.data.l[3] = 0;
909 xev.xclient.data.l[4] = 0;
910
911 _vnck_error_trap_push (display);
912 XSendEvent (display,
913 root,
914 False0,
915 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
916 &xev);
917 _vnck_error_trap_pop (display);
918}
919
920#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT0 0
921#define _NET_WM_MOVERESIZE_SIZE_TOP1 1
922#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT2 2
923#define _NET_WM_MOVERESIZE_SIZE_RIGHT3 3
924#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT4 4
925#define _NET_WM_MOVERESIZE_SIZE_BOTTOM5 5
926#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT6 6
927#define _NET_WM_MOVERESIZE_SIZE_LEFT7 7
928#define _NET_WM_MOVERESIZE_MOVE8 8
929#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD9 9
930#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD10 10
931
932void
933_vnck_keyboard_move (VnckScreen *screen,
934 Window xwindow)
935{
936 Screen *xscreen;
937 Display *display;
938 Window root;
939 XEvent xev;
940
941 xscreen = _vnck_screen_get_xscreen (screen);
942 display = DisplayOfScreen (xscreen)((xscreen)->display);
943 root = RootWindowOfScreen (xscreen)((xscreen)->root);
944
945 xev.xclient.type = ClientMessage33;
946 xev.xclient.serial = 0;
947 xev.xclient.send_event = True1;
948 xev.xclient.display = display;
949 xev.xclient.window = xwindow;
950 xev.xclient.message_type = _vnck_atom_get ("_NET_WM_MOVERESIZE")cdk_x11_get_xatom_by_name ("_NET_WM_MOVERESIZE");
951 xev.xclient.format = 32;
952 xev.xclient.data.l[0] = 0; /* unused */
953 xev.xclient.data.l[1] = 0; /* unused */
954 xev.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE_KEYBOARD10;
955 xev.xclient.data.l[3] = 0; /* unused */
956 xev.xclient.data.l[4] = _vnck_get_client_type ();
957
958 _vnck_error_trap_push (display);
959 XSendEvent (display,
960 root,
961 False0,
962 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
963 &xev);
964 _vnck_error_trap_pop (display);
965}
966
967void
968_vnck_keyboard_size (VnckScreen *screen,
969 Window xwindow)
970{
971 Screen *xscreen;
972 Display *display;
973 Window root;
974 XEvent xev;
975
976 xscreen = _vnck_screen_get_xscreen (screen);
977 display = DisplayOfScreen (xscreen)((xscreen)->display);
978 root = RootWindowOfScreen (xscreen)((xscreen)->root);
979
980 xev.xclient.type = ClientMessage33;
981 xev.xclient.serial = 0;
982 xev.xclient.send_event = True1;
983 xev.xclient.display = display;
984 xev.xclient.window = xwindow;
985 xev.xclient.message_type = _vnck_atom_get ("_NET_WM_MOVERESIZE")cdk_x11_get_xatom_by_name ("_NET_WM_MOVERESIZE");
986 xev.xclient.format = 32;
987 xev.xclient.data.l[0] = 0; /* unused */
988 xev.xclient.data.l[1] = 0; /* unused */
989 xev.xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_KEYBOARD9;
990 xev.xclient.data.l[3] = 0; /* unused */
991 xev.xclient.data.l[4] = _vnck_get_client_type ();
992
993 _vnck_error_trap_push (display);
994 XSendEvent (display,
995 root,
996 False0,
997 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
998 &xev);
999 _vnck_error_trap_pop (display);
1000}
1001
1002void
1003_vnck_change_state (VnckScreen *screen,
1004 Window xwindow,
1005 gboolean add,
1006 Atom state1,
1007 Atom state2)
1008{
1009 Screen *xscreen;
1010 Display *display;
1011 Window root;
1012 XEvent xev;
1013
1014#define _NET_WM_STATE_REMOVE0 0 /* remove/unset property */
1015#define _NET_WM_STATE_ADD1 1 /* add/set property */
1016#define _NET_WM_STATE_TOGGLE2 2 /* toggle property */
1017
1018 xscreen = _vnck_screen_get_xscreen (screen);
1019 display = DisplayOfScreen (xscreen)((xscreen)->display);
1020 root = RootWindowOfScreen (xscreen)((xscreen)->root);
1021
1022 xev.xclient.type = ClientMessage33;
1023 xev.xclient.serial = 0;
1024 xev.xclient.send_event = True1;
1025 xev.xclient.display = display;
1026 xev.xclient.window = xwindow;
1027 xev.xclient.message_type = _vnck_atom_get ("_NET_WM_STATE")cdk_x11_get_xatom_by_name ("_NET_WM_STATE");
1028 xev.xclient.format = 32;
1029 xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD1 : _NET_WM_STATE_REMOVE0;
1030 xev.xclient.data.l[1] = state1;
1031 xev.xclient.data.l[2] = state2;
1032 xev.xclient.data.l[3] = _vnck_get_client_type ();
1033 xev.xclient.data.l[4] = 0;
1034
1035 _vnck_error_trap_push (display);
1036 XSendEvent (display,
1037 root,
1038 False0,
1039 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
1040 &xev);
1041 _vnck_error_trap_pop (display);
1042}
1043
1044void
1045_vnck_change_workspace (VnckScreen *screen,
1046 Window xwindow,
1047 int new_space)
1048{
1049 Screen *xscreen;
1050 Display *display;
1051 Window root;
1052 XEvent xev;
1053
1054 xscreen = _vnck_screen_get_xscreen (screen);
1055 display = DisplayOfScreen (xscreen)((xscreen)->display);
1056 root = RootWindowOfScreen (xscreen)((xscreen)->root);
1057
1058 xev.xclient.type = ClientMessage33;
1059 xev.xclient.serial = 0;
1060 xev.xclient.send_event = True1;
1061 xev.xclient.display = display;
1062 xev.xclient.window = xwindow;
1063 xev.xclient.message_type = _vnck_atom_get ("_NET_WM_DESKTOP")cdk_x11_get_xatom_by_name ("_NET_WM_DESKTOP");
1064 xev.xclient.format = 32;
1065 xev.xclient.data.l[0] = new_space;
1066 xev.xclient.data.l[1] = _vnck_get_client_type ();
1067 xev.xclient.data.l[2] = 0;
1068 xev.xclient.data.l[3] = 0;
1069 xev.xclient.data.l[4] = 0;
1070
1071 _vnck_error_trap_push (display);
1072 XSendEvent (display,
1073 root,
1074 False0,
1075 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
1076 &xev);
1077 _vnck_error_trap_pop (display);
1078}
1079
1080void
1081_vnck_activate (VnckScreen *screen,
1082 Window xwindow,
1083 Time timestamp)
1084{
1085 Screen *xscreen;
1086 Display *display;
1087 Window root;
1088 XEvent xev;
1089
1090 if (timestamp == 0)
1091 g_warning ("Received a timestamp of 0; window activation may not "
1092 "function properly.\n");
1093
1094 xscreen = _vnck_screen_get_xscreen (screen);
1095 display = DisplayOfScreen (xscreen)((xscreen)->display);
1096 root = RootWindowOfScreen (xscreen)((xscreen)->root);
1097
1098 xev.xclient.type = ClientMessage33;
1099 xev.xclient.serial = 0;
1100 xev.xclient.send_event = True1;
1101 xev.xclient.display = display;
1102 xev.xclient.window = xwindow;
1103 xev.xclient.message_type = _vnck_atom_get ("_NET_ACTIVE_WINDOW")cdk_x11_get_xatom_by_name ("_NET_ACTIVE_WINDOW");
1104 xev.xclient.format = 32;
1105 xev.xclient.data.l[0] = _vnck_get_client_type ();
1106 xev.xclient.data.l[1] = timestamp;
1107 xev.xclient.data.l[2] = 0;
1108 xev.xclient.data.l[3] = 0;
1109 xev.xclient.data.l[4] = 0;
1110
1111 _vnck_error_trap_push (display);
1112 XSendEvent (display,
1113 root,
1114 False0,
1115 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
1116 &xev);
1117 _vnck_error_trap_pop (display);
1118}
1119
1120void
1121_vnck_activate_workspace (Screen *screen,
1122 int new_active_space,
1123 Time timestamp)
1124{
1125 Display *display;
1126 Window root;
1127 XEvent xev;
1128
1129 display = DisplayOfScreen (screen)((screen)->display);
1130 root = RootWindowOfScreen (screen)((screen)->root);
1131
1132 xev.xclient.type = ClientMessage33;
1133 xev.xclient.serial = 0;
1134 xev.xclient.send_event = True1;
1135 xev.xclient.display = display;
1136 xev.xclient.window = root;
1137 xev.xclient.message_type = _vnck_atom_get ("_NET_CURRENT_DESKTOP")cdk_x11_get_xatom_by_name ("_NET_CURRENT_DESKTOP");
1138 xev.xclient.format = 32;
1139 xev.xclient.data.l[0] = new_active_space;
1140 xev.xclient.data.l[1] = timestamp;
1141 xev.xclient.data.l[2] = 0;
1142 xev.xclient.data.l[3] = 0;
1143 xev.xclient.data.l[4] = 0;
1144
1145 _vnck_error_trap_push (display);
1146 XSendEvent (display,
1147 root,
1148 False0,
1149 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
1150 &xev);
1151 _vnck_error_trap_pop (display);
1152}
1153
1154void
1155_vnck_change_viewport (Screen *screen,
1156 int x,
1157 int y)
1158{
1159 Display *display;
1160 Window root;
1161 XEvent xev;
1162
1163 display = DisplayOfScreen (screen)((screen)->display);
1164 root = RootWindowOfScreen (screen)((screen)->root);
1165
1166 xev.xclient.type = ClientMessage33;
1167 xev.xclient.serial = 0;
1168 xev.xclient.send_event = True1;
1169 xev.xclient.display = display;
1170 xev.xclient.window = root;
1171 xev.xclient.message_type = _vnck_atom_get ("_NET_DESKTOP_VIEWPORT")cdk_x11_get_xatom_by_name ("_NET_DESKTOP_VIEWPORT");
1172 xev.xclient.format = 32;
1173 xev.xclient.data.l[0] = x;
1174 xev.xclient.data.l[1] = y;
1175 xev.xclient.data.l[2] = 0;
1176 xev.xclient.data.l[3] = 0;
1177 xev.xclient.data.l[4] = 0;
1178
1179 _vnck_error_trap_push (display);
1180 XSendEvent (display,
1181 root,
1182 False0,
1183 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
1184 &xev);
1185 _vnck_error_trap_pop (display);
1186}
1187
1188void
1189_vnck_toggle_showing_desktop (Screen *screen,
1190 gboolean show)
1191{
1192 Display *display;
1193 Window root;
1194 XEvent xev;
1195
1196 display = DisplayOfScreen (screen)((screen)->display);
1197 root = RootWindowOfScreen (screen)((screen)->root);
1198
1199 xev.xclient.type = ClientMessage33;
1200 xev.xclient.serial = 0;
1201 xev.xclient.send_event = True1;
1202 xev.xclient.display = display;
1203 xev.xclient.window = root;
1204 xev.xclient.message_type = _vnck_atom_get ("_NET_SHOWING_DESKTOP")cdk_x11_get_xatom_by_name ("_NET_SHOWING_DESKTOP");
1205 xev.xclient.format = 32;
1206 xev.xclient.data.l[0] = show != FALSE(0);
1207 xev.xclient.data.l[1] = 0;
1208 xev.xclient.data.l[2] = 0;
1209 xev.xclient.data.l[3] = 0;
1210 xev.xclient.data.l[4] = 0;
1211
1212 _vnck_error_trap_push (display);
1213 XSendEvent (display,
1214 root,
1215 False0,
1216 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
1217 &xev);
1218 _vnck_error_trap_pop (display);
1219}
1220
1221char*
1222_vnck_get_session_id (Screen *screen,
1223 Window xwindow)
1224{
1225 Window client_leader;
1226
1227 client_leader = None0L;
1228 _vnck_get_window (screen, xwindow,
1229 _vnck_atom_get ("WM_CLIENT_LEADER")cdk_x11_get_xatom_by_name ("WM_CLIENT_LEADER"),
1230 &client_leader);
1231
1232 if (client_leader == None0L)
1233 return NULL((void*)0);
1234
1235 return _vnck_get_string_property_latin1 (screen, client_leader,
1236 _vnck_atom_get ("SM_CLIENT_ID")cdk_x11_get_xatom_by_name ("SM_CLIENT_ID"));
1237}
1238
1239int
1240_vnck_get_pid (Screen *screen,
1241 Window xwindow)
1242{
1243 int val;
1244
1245 if (!_vnck_get_cardinal (screen, xwindow,
1246 _vnck_atom_get ("_NET_WM_PID")cdk_x11_get_xatom_by_name ("_NET_WM_PID"),
1247 &val))
1248 return 0;
1249 else
1250 return val;
1251}
1252
1253char*
1254_vnck_get_name (Screen *screen,
1255 Window xwindow)
1256{
1257 char *name;
1258
1259 name = _vnck_get_utf8_property (screen, xwindow,
1260 _vnck_atom_get ("_NET_WM_VISIBLE_NAME")cdk_x11_get_xatom_by_name ("_NET_WM_VISIBLE_NAME"));
1261
1262 if (name == NULL((void*)0))
1263 name = _vnck_get_utf8_property (screen, xwindow,
1264 _vnck_atom_get ("_NET_WM_NAME")cdk_x11_get_xatom_by_name ("_NET_WM_NAME"));
1265
1266 if (name == NULL((void*)0))
1267 name = _vnck_get_text_property (screen, xwindow,
1268 XA_WM_NAME((Atom) 39));
1269
1270 return name;
1271}
1272
1273char*
1274_vnck_get_icon_name (Screen *screen,
1275 Window xwindow)
1276{
1277 char *name;
1278
1279 name = _vnck_get_utf8_property (screen, xwindow,
1280 _vnck_atom_get ("_NET_WM_VISIBLE_ICON_NAME")cdk_x11_get_xatom_by_name ("_NET_WM_VISIBLE_ICON_NAME"));
1281
1282 if (name == NULL((void*)0))
1283 name = _vnck_get_utf8_property (screen, xwindow,
1284 _vnck_atom_get ("_NET_WM_ICON_NAME")cdk_x11_get_xatom_by_name ("_NET_WM_ICON_NAME"));
1285
1286 if (name == NULL((void*)0))
1287 name = _vnck_get_text_property (screen, xwindow,
1288 XA_WM_ICON_NAME((Atom) 37));
1289
1290 return name;
1291}
1292
1293static char*
1294latin1_to_utf8 (const char *latin1)
1295{
1296 GString *str;
1297 const char *p;
1298
1299 str = g_string_new (NULL((void*)0));
1300
1301 p = latin1;
1302 while (*p)
1303 {
1304 g_string_append_unichar (str, (gunichar) *p);
1305 ++p;
1306 }
1307
1308 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1309}
1310
1311char*
1312_vnck_get_res_class_utf8 (Screen *screen,
1313 Window xwindow)
1314{
1315 char *res_class;
1316
1317 _vnck_get_wmclass (screen, xwindow, &res_class, NULL((void*)0));
1318
1319 return res_class;
1320}
1321
1322void
1323_vnck_get_wmclass (Screen *screen,
1324 Window xwindow,
1325 char **res_class,
1326 char **res_name)
1327{
1328 Display *display;
1329 XClassHint ch;
1330
1331 display = DisplayOfScreen (screen)((screen)->display);
1332
1333 _vnck_error_trap_push (display);
1334
1335 ch.res_name = NULL((void*)0);
1336 ch.res_class = NULL((void*)0);
1337
1338 XGetClassHint (display, xwindow, &ch);
1339
1340 _vnck_error_trap_pop (display);
1341
1342 if (res_class)
1343 *res_class = NULL((void*)0);
1344
1345 if (res_name)
1346 *res_name = NULL((void*)0);
1347
1348 if (ch.res_name)
1349 {
1350 if (res_name)
1351 *res_name = latin1_to_utf8 (ch.res_name);
1352
1353 XFree (ch.res_name);
1354 }
1355
1356 if (ch.res_class)
1357 {
1358 if (res_class)
1359 *res_class = latin1_to_utf8 (ch.res_class);
1360
1361 XFree (ch.res_class);
1362 }
1363}
1364
1365gboolean
1366_vnck_get_frame_extents (Screen *screen,
1367 Window xwindow,
1368 int *left_frame,
1369 int *right_frame,
1370 int *top_frame,
1371 int *bottom_frame)
1372{
1373 gulong *p_size;
1374 int n_size;
1375 gboolean retval;
1376
1377 retval = FALSE(0);
1378 p_size = NULL((void*)0);
1379 n_size = 0;
1380
1381 _vnck_get_cardinal_list (screen, xwindow,
1382 _vnck_atom_get ("_NET_FRAME_EXTENTS")cdk_x11_get_xatom_by_name ("_NET_FRAME_EXTENTS"),
1383 &p_size, &n_size);
1384
1385 if (p_size != NULL((void*)0) && n_size == 4)
1386 {
1387 *left_frame = p_size[0];
1388 *right_frame = p_size[1];
1389 *top_frame = p_size[2];
1390 *bottom_frame = p_size[3];
1391
1392 retval = TRUE(!(0));
1393 }
1394
1395 if (p_size == NULL((void*)0))
1396 {
1397 _vnck_get_cardinal_list (screen, xwindow,
1398 _vnck_atom_get ("_CTK_FRAME_EXTENTS")cdk_x11_get_xatom_by_name ("_CTK_FRAME_EXTENTS"),
1399 &p_size, &n_size);
1400
1401 if (p_size != NULL((void*)0) && n_size == 4)
1402 {
1403 *left_frame = -p_size[0];
1404 *right_frame = -p_size[1];
1405 *top_frame = -p_size[2];
1406 *bottom_frame = -p_size[3];
1407
1408 retval = TRUE(!(0));
1409 }
1410 }
1411
1412 if (p_size != NULL((void*)0))
1413 g_free (p_size);
1414
1415 return retval;
1416}
1417
1418int
1419_vnck_select_input (Screen *screen,
1420 Window xwindow,
1421 int mask,
1422 gboolean update)
1423{
1424 Display *display;
1425 CdkWindow *cdkwindow;
1426 int old_mask = 0;
1427
1428 display = DisplayOfScreen (screen)((screen)->display);
1429
1430 cdkwindow = _vnck_cdk_window_lookup_from_window (screen, xwindow);
1431
1432 _vnck_error_trap_push (display);
1433 if (cdkwindow)
1434 {
1435 /* Avoid breaking CDK's setup,
1436 * this somewhat relies on people setting
1437 * event masks right after realization
1438 * and not changing them again
1439 */
1440 XWindowAttributes attrs;
1441 XGetWindowAttributes (display, xwindow, &attrs);
1442 old_mask = attrs.your_event_mask;
1443
1444 if (update)
1445 mask |= attrs.your_event_mask;
1446 }
1447
1448 XSelectInput (display, xwindow, mask);
1449 _vnck_error_trap_pop (display);
1450
1451 return old_mask;
1452}
1453
1454/* The icon-reading code is copied
1455 * from metacity, please sync bugfixes
1456 */
1457static gboolean
1458find_largest_sizes (gulong *data,
1459 gulong nitems,
1460 int *width,
1461 int *height)
1462{
1463 *width = 0;
1464 *height = 0;
1465
1466 while (nitems > 0)
1467 {
1468 int w, h;
1469
1470 if (nitems < 3)
1471 return FALSE(0); /* no space for w, h */
1472
1473 w = data[0];
1474 h = data[1];
1475
1476 if (nitems < ((gulong) (w * h) + 2))
1477 return FALSE(0); /* not enough data */
1478
1479 *width = MAX (w, *width)(((w) > (*width)) ? (w) : (*width));
1480 *height = MAX (h, *height)(((h) > (*height)) ? (h) : (*height));
1481
1482 data += (w * h) + 2;
1483 nitems -= (w * h) + 2;
1484 }
1485
1486 return TRUE(!(0));
1487}
1488
1489static gboolean
1490find_best_size (gulong *data,
1491 gulong nitems,
1492 int ideal_width,
1493 int ideal_height,
1494 int *width,
1495 int *height,
1496 gulong **start)
1497{
1498 int best_w;
1499 int best_h;
1500 gulong *best_start;
1501 int max_width, max_height;
1502
1503 *width = 0;
1504 *height = 0;
1505 *start = NULL((void*)0);
1506
1507 if (!find_largest_sizes (data, nitems, &max_width, &max_height))
1508 return FALSE(0);
1509
1510 if (ideal_width < 0)
1511 ideal_width = max_width;
1512 if (ideal_height < 0)
1513 ideal_height = max_height;
1514
1515 best_w = 0;
1516 best_h = 0;
1517 best_start = NULL((void*)0);
1518
1519 while (nitems > 0)
1520 {
1521 int w, h;
1522 gboolean replace;
1523
1524 replace = FALSE(0);
1525
1526 if (nitems < 3)
1527 return FALSE(0); /* no space for w, h */
1528
1529 w = data[0];
1530 h = data[1];
1531
1532 if (nitems < ((gulong) (w * h) + 2))
1533 break; /* not enough data */
1534
1535 if (best_start == NULL((void*)0))
1536 {
1537 replace = TRUE(!(0));
1538 }
1539 else
1540 {
1541 /* work with averages */
1542 const int ideal_size = (ideal_width + ideal_height) / 2;
1543 int best_size = (best_w + best_h) / 2;
1544 int this_size = (w + h) / 2;
1545
1546 /* larger than desired is always better than smaller */
1547 if (best_size < ideal_size &&
1548 this_size >= ideal_size)
1549 replace = TRUE(!(0));
1550 /* if we have too small, pick anything bigger */
1551 else if (best_size < ideal_size &&
1552 this_size > best_size)
1553 replace = TRUE(!(0));
1554 /* if we have too large, pick anything smaller
1555 * but still >= the ideal
1556 */
1557 else if (best_size > ideal_size &&
1558 this_size >= ideal_size &&
1559 this_size < best_size)
1560 replace = TRUE(!(0));
1561 }
1562
1563 if (replace)
1564 {
1565 best_start = data + 2;
1566 best_w = w;
1567 best_h = h;
1568 }
1569
1570 data += (w * h) + 2;
1571 nitems -= (w * h) + 2;
1572 }
1573
1574 if (best_start)
1575 {
1576 *start = best_start;
1577 *width = best_w;
1578 *height = best_h;
1579 return TRUE(!(0));
1580 }
1581 else
1582 return FALSE(0);
1583}
1584
1585static void
1586argbdata_to_pixdata (gulong *argb_data, int len, guchar **pixdata)
1587{
1588 guchar *p;
1589 int i;
1590
1591 *pixdata = g_new (guchar, len * 4)((guchar *) g_malloc_n ((len * 4), sizeof (guchar)));
1592 p = *pixdata;
1593
1594 /* One could speed this up a lot. */
1595 i = 0;
1596 while (i < len)
1597 {
1598 guint argb;
1599 guint rgba;
1600
1601 argb = argb_data[i];
1602 rgba = (argb << 8) | (argb >> 24);
1603
1604 *p = rgba >> 24;
1605 ++p;
1606 *p = (rgba >> 16) & 0xff;
1607 ++p;
1608 *p = (rgba >> 8) & 0xff;
1609 ++p;
1610 *p = rgba & 0xff;
1611 ++p;
1612
1613 ++i;
1614 }
1615}
1616
1617static gboolean
1618read_rgb_icon (Screen *screen,
1619 Window xwindow,
1620 int ideal_width,
1621 int ideal_height,
1622 int ideal_mini_width,
1623 int ideal_mini_height,
1624 int *width,
1625 int *height,
1626 guchar **pixdata,
1627 int *mini_width,
1628 int *mini_height,
1629 guchar **mini_pixdata)
1630{
1631 Display *display;
1632 Atom type;
1633 int format;
1634 gulong nitems;
1635 gulong bytes_after;
1636 int result, err;
1637 gulong *data;
1638 gulong *best;
1639 int w, h;
1640 gulong *best_mini;
1641 int mini_w, mini_h;
1642
1643 display = DisplayOfScreen (screen)((screen)->display);
1644
1645 _vnck_error_trap_push (display);
1646 type = None0L;
1647 data = NULL((void*)0);
1648 result = XGetWindowProperty (display,
1649 xwindow,
1650 _vnck_atom_get ("_NET_WM_ICON")cdk_x11_get_xatom_by_name ("_NET_WM_ICON"),
1651 0, G_MAXLONG9223372036854775807L,
1652 False0, XA_CARDINAL((Atom) 6), &type, &format, &nitems,
1653 &bytes_after, (void*)&data);
1654
1655 err = _vnck_error_trap_pop (display);
1656
1657 if (err != Success0 ||
1658 result != Success0)
1659 return FALSE(0);
1660
1661 if (type != XA_CARDINAL((Atom) 6))
1662 {
1663 XFree (data);
1664 return FALSE(0);
1665 }
1666
1667 if (!find_best_size (data, nitems,
1668 ideal_width, ideal_height,
1669 &w, &h, &best))
1670 {
1671 XFree (data);
1672 return FALSE(0);
1673 }
1674
1675 if (!find_best_size (data, nitems,
1676 ideal_mini_width, ideal_mini_height,
1677 &mini_w, &mini_h, &best_mini))
1678 {
1679 XFree (data);
1680 return FALSE(0);
1681 }
1682
1683 *width = w;
1684 *height = h;
1685
1686 *mini_width = mini_w;
1687 *mini_height = mini_h;
1688
1689 argbdata_to_pixdata (best, w * h, pixdata);
1690 argbdata_to_pixdata (best_mini, mini_w * mini_h, mini_pixdata);
1691
1692 XFree (data);
1693
1694 return TRUE(!(0));
1695}
1696
1697static void
1698free_pixels (guchar *pixels,
1699 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
1700{
1701 g_free (pixels);
1702}
1703
1704static cairo_surface_t *
1705_vnck_cairo_surface_get_from_pixmap (Screen *screen,
1706 Pixmap xpixmap)
1707{
1708 cairo_surface_t *surface;
1709 Display *display;
1710 Window root_return;
1711 int x_ret, y_ret;
1712 unsigned int w_ret, h_ret, bw_ret, depth_ret;
1713 XWindowAttributes attrs;
1714
1715 surface = NULL((void*)0);
1716 display = DisplayOfScreen (screen)((screen)->display);
1717
1718 _vnck_error_trap_push (display);
1719
1720 if (!XGetGeometry (display, xpixmap, &root_return,
1721 &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret))
1722 goto TRAP_POP;
1723
1724 if (depth_ret == 1)
1725 {
1726 surface = cairo_xlib_surface_create_for_bitmap (display,
1727 xpixmap,
1728 screen,
1729 w_ret,
1730 h_ret);
1731 }
1732 else
1733 {
1734 if (!XGetWindowAttributes (display, root_return, &attrs))
1735 goto TRAP_POP;
1736
1737 if (depth_ret == (unsigned int) attrs.depth)
1738 {
1739 surface = cairo_xlib_surface_create (display,
1740 xpixmap,
1741 attrs.visual,
1742 w_ret, h_ret);
1743 }
1744 else
1745 {
1746#if HAVE_CAIRO_XLIB_XRENDER1
1747 int std;
1748
1749 switch (depth_ret) {
1750 case 1: std = PictStandardA14; break;
1751 case 4: std = PictStandardA43; break;
1752 case 8: std = PictStandardA82; break;
1753 case 24: std = PictStandardRGB241; break;
1754 case 32: std = PictStandardARGB320; break;
1755 default: goto TRAP_POP;
1756 }
1757
1758 surface = cairo_xlib_surface_create_with_xrender_format (display,
1759 xpixmap,
1760 attrs.screen,
1761 XRenderFindStandardFormat (display, std),
1762 w_ret, h_ret);
1763#endif
1764 }
1765 }
1766
1767TRAP_POP:
1768 _vnck_error_trap_pop (display);
1769
1770 return surface;
1771}
1772
1773GdkPixbuf*
1774_vnck_gdk_pixbuf_get_from_pixmap (Screen *screen,
1775 Pixmap xpixmap)
1776{
1777 cairo_surface_t *surface;
1778 GdkPixbuf *retval;
1779
1780 surface = _vnck_cairo_surface_get_from_pixmap (screen, xpixmap);
1781
1782 if (surface == NULL((void*)0))
1783 return NULL((void*)0);
1784
1785 retval = gdk_pixbuf_get_from_surface (surface,
1786 0,
1787 0,
1788 cairo_xlib_surface_get_width (surface),
1789 cairo_xlib_surface_get_height (surface));
1790 cairo_surface_destroy (surface);
1791
1792 return retval;
1793}
1794
1795static gboolean
1796try_pixmap_and_mask (Screen *screen,
1797 Pixmap src_pixmap,
1798 Pixmap src_mask,
1799 GdkPixbuf **iconp,
1800 int ideal_width,
1801 int ideal_height,
1802 GdkPixbuf **mini_iconp,
1803 int ideal_mini_width,
1804 int ideal_mini_height)
1805{
1806 cairo_surface_t *surface, *mask_surface, *image;
1807 CdkDisplay *cdk_display;
1808 GdkPixbuf *unscaled;
1809 int width, height;
1810 cairo_t *cr;
1811
1812 if (src_pixmap == None0L)
1813 return FALSE(0);
1814
1815 surface = _vnck_cairo_surface_get_from_pixmap (screen, src_pixmap);
1816
1817 if (surface && src_mask != None0L)
1818 mask_surface = _vnck_cairo_surface_get_from_pixmap (screen, src_mask);
1819 else
1820 mask_surface = NULL((void*)0);
1821
1822 if (surface == NULL((void*)0))
1823 return FALSE(0);
1824
1825 cdk_display = cdk_x11_lookup_xdisplay (XDisplayOfScreen (screen));
1826 g_assert (cdk_display != NULL)do { if (cdk_display != ((void*)0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/xutils.c", 1826, ((const char*) (__func__
)), "cdk_display != NULL"); } while (0)
;
1827
1828 cdk_x11_display_error_trap_push (cdk_display);
1829
1830 width = cairo_xlib_surface_get_width (surface);
1831 height = cairo_xlib_surface_get_height (surface);
1832
1833 image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1834 width, height);
1835 cr = cairo_create (image);
1836
1837 /* Need special code for alpha-only surfaces. We only get those
1838 * for bitmaps. And in that case, it's a differentiation between
1839 * foreground (white) and background (black).
1840 */
1841 if (cairo_surface_get_content (surface) & CAIRO_CONTENT_ALPHA)
1842 {
1843 cairo_push_group (cr);
1844
1845 /* black background */
1846 cairo_set_source_rgb (cr, 0, 0, 0);
1847 cairo_paint (cr);
1848 /* mask with white foreground */
1849 cairo_set_source_rgb (cr, 1, 1, 1);
1850 cairo_mask_surface (cr, surface, 0, 0);
1851
1852 cairo_pop_group_to_source (cr);
1853 }
1854 else
1855 cairo_set_source_surface (cr, surface, 0, 0);
1856
1857 if (mask_surface)
1858 {
1859 cairo_mask_surface (cr, mask_surface, 0, 0);
1860 cairo_surface_destroy (mask_surface);
1861 }
1862 else
1863 cairo_paint (cr);
1864
1865 cairo_surface_destroy (surface);
1866 cairo_destroy (cr);
1867
1868 if (cdk_x11_display_error_trap_pop (cdk_display) != Success0)
1869 {
1870 cairo_surface_destroy (image);
1871 return FALSE(0);
1872 }
1873
1874 unscaled = gdk_pixbuf_get_from_surface (image,
1875 0, 0,
1876 width, height);
1877
1878 cairo_surface_destroy (image);
1879
1880 if (unscaled)
1881 {
1882 *iconp =
1883 gdk_pixbuf_scale_simple (unscaled,
1884 ideal_width > 0 ? ideal_width :
1885 gdk_pixbuf_get_width (unscaled),
1886 ideal_height > 0 ? ideal_height :
1887 gdk_pixbuf_get_height (unscaled),
1888 GDK_INTERP_BILINEAR);
1889 *mini_iconp =
1890 gdk_pixbuf_scale_simple (unscaled,
1891 ideal_mini_width > 0 ? ideal_mini_width :
1892 gdk_pixbuf_get_width (unscaled),
1893 ideal_mini_height > 0 ? ideal_mini_height :
1894 gdk_pixbuf_get_height (unscaled),
1895 GDK_INTERP_BILINEAR);
1896
1897 g_object_unref (G_OBJECT (unscaled)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((unscaled)), (((GType) ((20) << (2))))))))
);
1898 return TRUE(!(0));
1899 }
1900 else
1901 return FALSE(0);
1902}
1903
1904static void
1905get_kwm_win_icon (Screen *screen,
1906 Window xwindow,
1907 Pixmap *pixmap,
1908 Pixmap *mask)
1909{
1910 Display *display;
1911 Atom type;
1912 int format;
1913 gulong nitems;
1914 gulong bytes_after;
1915 Pixmap *icons;
1916 int err, result;
1917
1918 display = DisplayOfScreen (screen)((screen)->display);
1919
1920 *pixmap = None0L;
1921 *mask = None0L;
1922
1923 _vnck_error_trap_push (display);
1924 icons = NULL((void*)0);
1925 result = XGetWindowProperty (display, xwindow,
1926 _vnck_atom_get ("KWM_WIN_ICON")cdk_x11_get_xatom_by_name ("KWM_WIN_ICON"),
1927 0, G_MAXLONG9223372036854775807L,
1928 False0,
1929 _vnck_atom_get ("KWM_WIN_ICON")cdk_x11_get_xatom_by_name ("KWM_WIN_ICON"),
1930 &type, &format, &nitems,
1931 &bytes_after, (void*)&icons);
1932
1933 err = _vnck_error_trap_pop (display);
1934 if (err != Success0 ||
1935 result != Success0)
1936 return;
1937
1938 if (type != _vnck_atom_get ("KWM_WIN_ICON")cdk_x11_get_xatom_by_name ("KWM_WIN_ICON"))
1939 {
1940 XFree (icons);
1941 return;
1942 }
1943
1944 *pixmap = icons[0];
1945 *mask = icons[1];
1946
1947 XFree (icons);
1948
1949 return;
1950}
1951
1952typedef enum
1953{
1954 /* These MUST be in ascending order of preference;
1955 * i.e. if we get _NET_WM_ICON and already have
1956 * WM_HINTS, we prefer _NET_WM_ICON
1957 */
1958 USING_NO_ICON,
1959 USING_FALLBACK_ICON,
1960 USING_KWM_WIN_ICON,
1961 USING_WM_HINTS,
1962 USING_NET_WM_ICON
1963} IconOrigin;
1964
1965struct _VnckIconCache
1966{
1967 IconOrigin origin;
1968 Pixmap prev_pixmap;
1969 Pixmap prev_mask;
1970 GdkPixbuf *icon;
1971 GdkPixbuf *mini_icon;
1972 int ideal_width;
1973 int ideal_height;
1974 int ideal_mini_width;
1975 int ideal_mini_height;
1976 guint want_fallback : 1;
1977 /* TRUE if these props have changed */
1978 guint wm_hints_dirty : 1;
1979 guint kwm_win_icon_dirty : 1;
1980 guint net_wm_icon_dirty : 1;
1981};
1982
1983VnckIconCache*
1984_vnck_icon_cache_new (void)
1985{
1986 VnckIconCache *icon_cache;
1987
1988 icon_cache = g_slice_new0 (VnckIconCache)((VnckIconCache*) g_slice_alloc0 (sizeof (VnckIconCache)));
1989
1990 icon_cache->origin = USING_NO_ICON;
1991 icon_cache->prev_pixmap = None0L;
1992 icon_cache->icon = NULL((void*)0);
1993 icon_cache->mini_icon = NULL((void*)0);
1994 icon_cache->ideal_width = -1; /* won't be a legit width */
1995 icon_cache->ideal_height = -1;
1996 icon_cache->ideal_mini_width = -1;
1997 icon_cache->ideal_mini_height = -1;
1998 icon_cache->want_fallback = TRUE(!(0));
1999 icon_cache->wm_hints_dirty = TRUE(!(0));
2000 icon_cache->kwm_win_icon_dirty = TRUE(!(0));
2001 icon_cache->net_wm_icon_dirty = TRUE(!(0));
2002
2003 return icon_cache;
2004}
2005
2006static void
2007clear_icon_cache (VnckIconCache *icon_cache,
2008 gboolean dirty_all)
2009{
2010 if (icon_cache->icon)
2011 g_object_unref (G_OBJECT (icon_cache->icon)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((icon_cache->icon)), (((GType) ((20) << (2))))))
))
);
2012 icon_cache->icon = NULL((void*)0);
2013
2014 if (icon_cache->mini_icon)
2015 g_object_unref (G_OBJECT (icon_cache->mini_icon)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((icon_cache->mini_icon)), (((GType) ((20) << (2)
)))))))
);
2016 icon_cache->mini_icon = NULL((void*)0);
2017
2018 icon_cache->origin = USING_NO_ICON;
2019
2020 if (dirty_all)
2021 {
2022 icon_cache->wm_hints_dirty = TRUE(!(0));
2023 icon_cache->kwm_win_icon_dirty = TRUE(!(0));
2024 icon_cache->net_wm_icon_dirty = TRUE(!(0));
2025 }
2026}
2027
2028void
2029_vnck_icon_cache_free (VnckIconCache *icon_cache)
2030{
2031 clear_icon_cache (icon_cache, FALSE(0));
2032
2033 g_slice_free (VnckIconCache, icon_cache)do { if (1) g_slice_free1 (sizeof (VnckIconCache), (icon_cache
)); else (void) ((VnckIconCache*) 0 == (icon_cache)); } while
(0)
;
2034}
2035
2036void
2037_vnck_icon_cache_property_changed (VnckIconCache *icon_cache,
2038 Atom atom)
2039{
2040 if (atom == _vnck_atom_get ("_NET_WM_ICON")cdk_x11_get_xatom_by_name ("_NET_WM_ICON"))
2041 icon_cache->net_wm_icon_dirty = TRUE(!(0));
2042 else if (atom == _vnck_atom_get ("KWM_WIN_ICON")cdk_x11_get_xatom_by_name ("KWM_WIN_ICON"))
2043 icon_cache->kwm_win_icon_dirty = TRUE(!(0));
2044 else if (atom == _vnck_atom_get ("WM_HINTS")cdk_x11_get_xatom_by_name ("WM_HINTS"))
2045 icon_cache->wm_hints_dirty = TRUE(!(0));
2046}
2047
2048gboolean
2049_vnck_icon_cache_get_icon_invalidated (VnckIconCache *icon_cache)
2050{
2051 if (icon_cache->origin <= USING_KWM_WIN_ICON &&
2052 icon_cache->kwm_win_icon_dirty)
2053 return TRUE(!(0));
2054 else if (icon_cache->origin <= USING_WM_HINTS &&
2055 icon_cache->wm_hints_dirty)
2056 return TRUE(!(0));
2057 else if (icon_cache->origin <= USING_NET_WM_ICON &&
2058 icon_cache->net_wm_icon_dirty)
2059 return TRUE(!(0));
2060 else if (icon_cache->origin < USING_FALLBACK_ICON &&
2061 icon_cache->want_fallback)
2062 return TRUE(!(0));
2063 else if (icon_cache->origin == USING_NO_ICON)
2064 return TRUE(!(0));
2065 else if (icon_cache->origin == USING_FALLBACK_ICON &&
2066 !icon_cache->want_fallback)
2067 return TRUE(!(0));
2068 else
2069 return FALSE(0);
2070}
2071
2072void
2073_vnck_icon_cache_set_want_fallback (VnckIconCache *icon_cache,
2074 gboolean setting)
2075{
2076 icon_cache->want_fallback = setting;
2077}
2078
2079gboolean
2080_vnck_icon_cache_get_is_fallback (VnckIconCache *icon_cache)
2081{
2082 return icon_cache->origin == USING_FALLBACK_ICON;
2083}
2084
2085static void
2086replace_cache (VnckIconCache *icon_cache,
2087 IconOrigin origin,
2088 GdkPixbuf *new_icon,
2089 GdkPixbuf *new_mini_icon)
2090{
2091 clear_icon_cache (icon_cache, FALSE(0));
2092
2093 icon_cache->origin = origin;
2094
2095 if (new_icon)
2096 g_object_ref (G_OBJECT (new_icon))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((new_icon)), (((GType) ((20) << (2)
))))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((new_icon)), (((GType) ((20) << (2)
)))))))))
;
2097
2098 icon_cache->icon = new_icon;
2099
2100 if (new_mini_icon)
2101 g_object_ref (G_OBJECT (new_mini_icon))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((new_mini_icon)), (((GType) ((20) <<
(2)))))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((new_mini_icon)), (((GType) ((20) <<
(2))))))))))
;
2102
2103 icon_cache->mini_icon = new_mini_icon;
2104}
2105
2106static GdkPixbuf*
2107scaled_from_pixdata (guchar *pixdata,
2108 int w,
2109 int h,
2110 int new_w,
2111 int new_h)
2112{
2113 GdkPixbuf *src;
2114 GdkPixbuf *dest;
2115
2116 src = gdk_pixbuf_new_from_data (pixdata,
2117 GDK_COLORSPACE_RGB,
2118 TRUE(!(0)),
2119 8,
2120 w, h, w * 4,
2121 free_pixels,
2122 NULL((void*)0));
2123
2124 if (src == NULL((void*)0))
2125 return NULL((void*)0);
2126
2127 if (w != h)
2128 {
2129 GdkPixbuf *tmp;
2130 int size;
2131
2132 size = MAX (w, h)(((w) > (h)) ? (w) : (h));
2133
2134 tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE(!(0)), 8, size, size);
2135
2136 if (tmp != NULL((void*)0))
2137 {
2138 gdk_pixbuf_fill (tmp, 0);
2139 gdk_pixbuf_copy_area (src, 0, 0, w, h,
2140 tmp,
2141 (size - w) / 2, (size - h) / 2);
2142
2143 g_object_unref (src);
2144 src = tmp;
2145 }
2146 }
2147
2148 if (w != new_w || h != new_h)
2149 {
2150 dest = gdk_pixbuf_scale_simple (src, new_w, new_h, GDK_INTERP_BILINEAR);
2151
2152 g_object_unref (G_OBJECT (src)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((src)), (((GType) ((20) << (2))))))))
);
2153 }
2154 else
2155 {
2156 dest = src;
2157 }
2158
2159 return dest;
2160}
2161
2162gboolean
2163_vnck_read_icons (VnckScreen *screen,
2164 Window xwindow,
2165 VnckIconCache *icon_cache,
2166 GdkPixbuf **iconp,
2167 int ideal_width,
2168 int ideal_height,
2169 GdkPixbuf **mini_iconp,
2170 int ideal_mini_width,
2171 int ideal_mini_height)
2172{
2173 Screen *xscreen;
2174 Display *display;
2175 guchar *pixdata;
2176 int w, h;
2177 guchar *mini_pixdata;
2178 int mini_w, mini_h;
2179 Pixmap pixmap;
2180 Pixmap mask;
2181 XWMHints *hints;
2182
2183 /* Return value is whether the icon changed */
2184
2185 g_return_val_if_fail (icon_cache != NULL, FALSE)do { if ((icon_cache != ((void*)0))) { } else { g_return_if_fail_warning
("Vnck", ((const char*) (__func__)), "icon_cache != NULL"); return
((0)); } } while (0)
;
2186
2187 xscreen = _vnck_screen_get_xscreen (screen);
2188 display = DisplayOfScreen (xscreen)((xscreen)->display);
2189
2190 *iconp = NULL((void*)0);
2191 *mini_iconp = NULL((void*)0);
2192
2193 if (ideal_width != icon_cache->ideal_width ||
2194 ideal_height != icon_cache->ideal_height ||
2195 ideal_mini_width != icon_cache->ideal_mini_width ||
2196 ideal_mini_height != icon_cache->ideal_mini_height)
2197 clear_icon_cache (icon_cache, TRUE(!(0)));
2198
2199 icon_cache->ideal_width = ideal_width;
2200 icon_cache->ideal_height = ideal_height;
2201 icon_cache->ideal_mini_width = ideal_mini_width;
2202 icon_cache->ideal_mini_height = ideal_mini_height;
2203
2204 if (!_vnck_icon_cache_get_icon_invalidated (icon_cache))
2205 return FALSE(0); /* we have no new info to use */
2206
2207 pixdata = NULL((void*)0);
2208
2209 /* Our algorithm here assumes that we can't have for example origin
2210 * < USING_NET_WM_ICON and icon_cache->net_wm_icon_dirty == FALSE
2211 * unless we have tried to read NET_WM_ICON.
2212 *
2213 * Put another way, if an icon origin is not dirty, then we have
2214 * tried to read it at the current size. If it is dirty, then
2215 * we haven't done that since the last change.
2216 */
2217
2218 if (icon_cache->origin <= USING_NET_WM_ICON &&
2219 icon_cache->net_wm_icon_dirty)
2220
2221 {
2222 icon_cache->net_wm_icon_dirty = FALSE(0);
2223
2224 if (read_rgb_icon (xscreen, xwindow,
2225 ideal_width, ideal_height,
2226 ideal_mini_width, ideal_mini_height,
2227 &w, &h, &pixdata,
2228 &mini_w, &mini_h, &mini_pixdata))
2229 {
2230 *iconp = scaled_from_pixdata (pixdata, w, h, ideal_width, ideal_height);
2231
2232 *mini_iconp = scaled_from_pixdata (mini_pixdata, mini_w, mini_h,
2233 ideal_mini_width, ideal_mini_height);
2234
2235 replace_cache (icon_cache, USING_NET_WM_ICON,
2236 *iconp, *mini_iconp);
2237
2238 return TRUE(!(0));
2239 }
2240 }
2241
2242 if (icon_cache->origin <= USING_WM_HINTS &&
2243 icon_cache->wm_hints_dirty)
2244 {
2245 icon_cache->wm_hints_dirty = FALSE(0);
2246
2247 _vnck_error_trap_push (display);
2248 hints = XGetWMHints (display, xwindow);
2249 _vnck_error_trap_pop (display);
2250 pixmap = None0L;
2251 mask = None0L;
2252 if (hints)
2253 {
2254 if (hints->flags & IconPixmapHint(1L << 2))
2255 pixmap = hints->icon_pixmap;
2256 if (hints->flags & IconMaskHint(1L << 5))
2257 mask = hints->icon_mask;
2258
2259 XFree (hints);
2260 hints = NULL((void*)0);
2261 }
2262
2263 /* We won't update if pixmap is unchanged;
2264 * avoids a get_from_drawable() on every geometry
2265 * hints change
2266 */
2267 if ((pixmap != icon_cache->prev_pixmap ||
2268 mask != icon_cache->prev_mask) &&
2269 pixmap != None0L)
2270 {
2271 if (try_pixmap_and_mask (xscreen, pixmap, mask,
2272 iconp, ideal_width, ideal_height,
2273 mini_iconp, ideal_mini_width, ideal_mini_height))
2274 {
2275 icon_cache->prev_pixmap = pixmap;
2276 icon_cache->prev_mask = mask;
2277
2278 replace_cache (icon_cache, USING_WM_HINTS,
2279 *iconp, *mini_iconp);
2280
2281 return TRUE(!(0));
2282 }
2283 }
2284 }
2285
2286 if (icon_cache->origin <= USING_KWM_WIN_ICON &&
2287 icon_cache->kwm_win_icon_dirty)
2288 {
2289 icon_cache->kwm_win_icon_dirty = FALSE(0);
2290
2291 get_kwm_win_icon (xscreen, xwindow, &pixmap, &mask);
2292
2293 if ((pixmap != icon_cache->prev_pixmap ||
2294 mask != icon_cache->prev_mask) &&
2295 pixmap != None0L)
2296 {
2297 if (try_pixmap_and_mask (xscreen, pixmap, mask,
2298 iconp, ideal_width, ideal_height,
2299 mini_iconp, ideal_mini_width, ideal_mini_height))
2300 {
2301 icon_cache->prev_pixmap = pixmap;
2302 icon_cache->prev_mask = mask;
2303
2304 replace_cache (icon_cache, USING_KWM_WIN_ICON,
2305 *iconp, *mini_iconp);
2306
2307 return TRUE(!(0));
2308 }
2309 }
2310 }
2311
2312 if (icon_cache->want_fallback &&
2313 icon_cache->origin < USING_FALLBACK_ICON)
2314 {
2315 _vnck_get_fallback_icons (iconp,
2316 ideal_width,
2317 ideal_height,
2318 mini_iconp,
2319 ideal_mini_width,
2320 ideal_mini_height);
2321
2322 replace_cache (icon_cache, USING_FALLBACK_ICON,
2323 *iconp, *mini_iconp);
2324
2325 return TRUE(!(0));
2326 }
2327
2328 if (!icon_cache->want_fallback &&
2329 icon_cache->origin == USING_FALLBACK_ICON)
2330 {
2331 /* Get rid of current icon */
2332 clear_icon_cache (icon_cache, FALSE(0));
2333
2334 return TRUE(!(0));
2335 }
2336
2337 /* found nothing new */
2338 return FALSE(0);
2339}
2340
2341static GdkPixbuf*
2342default_icon_at_size (int width,
2343 int height)
2344{
2345 GdkPixbuf *base;
2346
2347 base = gdk_pixbuf_new_from_resource ("/org/gnome/libvnck/default_icon.png", NULL((void*)0));
2348
2349 g_assert (base)do { if (base) ; else g_assertion_message_expr ("Vnck", "../libvnck/xutils.c"
, 2349, ((const char*) (__func__)), "base"); } while (0)
;
2350
2351 if ((width < 0 && height < 0) ||
2352 (gdk_pixbuf_get_width (base) == width &&
2353 gdk_pixbuf_get_height (base) == height))
2354 {
2355 return base;
2356 }
2357 else
2358 {
2359 GdkPixbuf *scaled;
2360
2361 scaled = gdk_pixbuf_scale_simple (base,
2362 width > 0 ? width :
2363 gdk_pixbuf_get_width (base),
2364 height > 0 ? height :
2365 gdk_pixbuf_get_height (base),
2366 GDK_INTERP_BILINEAR);
2367
2368 g_object_unref (G_OBJECT (base)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((base)), (((GType) ((20) << (2))))))))
);
2369
2370 return scaled;
2371 }
2372}
2373
2374void
2375_vnck_get_fallback_icons (GdkPixbuf **iconp,
2376 int ideal_width,
2377 int ideal_height,
2378 GdkPixbuf **mini_iconp,
2379 int ideal_mini_width,
2380 int ideal_mini_height)
2381{
2382 if (iconp)
2383 *iconp = default_icon_at_size (ideal_width > 0 ? ideal_width :
2384 (int) _vnck_get_default_icon_size (),
2385 ideal_height > 0 ? ideal_height :
2386 (int) _vnck_get_default_icon_size ());
2387
2388 if (mini_iconp)
2389 *mini_iconp = default_icon_at_size (ideal_mini_width > 0 ? ideal_mini_width :
2390 (int) _vnck_get_default_mini_icon_size (),
2391 ideal_mini_height > 0 ? ideal_mini_height :
2392 (int) _vnck_get_default_mini_icon_size ());
2393}
2394
2395
2396void
2397_vnck_get_window_geometry (Screen *screen,
2398 Window xwindow,
2399 int *xp,
2400 int *yp,
2401 int *widthp,
2402 int *heightp)
2403{
2404 Display *display;
2405 int x, y;
2406 unsigned int width, height, bw, depth;
2407 Window root_window;
2408
2409 width = 1;
2410 height = 1;
2411
2412 display = DisplayOfScreen (screen)((screen)->display);
2413
2414 _vnck_error_trap_push (display);
2415
2416 XGetGeometry (display,
2417 xwindow,
2418 &root_window,
2419 &x, &y, &width, &height, &bw, &depth);
2420
2421 _vnck_error_trap_pop (display);
2422
2423 _vnck_get_window_position (screen, xwindow, xp, yp);
2424
2425 if (widthp)
2426 *widthp = width;
2427 if (heightp)
2428 *heightp = height;
2429}
2430
2431void _vnck_set_window_geometry (Screen *screen,
2432 Window xwindow,
2433 int gravity_and_flags,
2434 int x,
2435 int y,
2436 int width,
2437 int height)
2438{
2439 Display *display;
2440 Window root;
2441 XEvent xev;
2442
2443 display = DisplayOfScreen (screen)((screen)->display);
2444 root = RootWindowOfScreen (screen)((screen)->root);
2445
2446 xev.xclient.type = ClientMessage33;
2447 xev.xclient.serial = 0;
2448 xev.xclient.send_event = True1;
2449 xev.xclient.display = display;
2450 xev.xclient.window = xwindow;
2451 xev.xclient.message_type = _vnck_atom_get ("_NET_MOVERESIZE_WINDOW")cdk_x11_get_xatom_by_name ("_NET_MOVERESIZE_WINDOW");
2452 xev.xclient.format = 32;
2453 xev.xclient.data.l[0] = gravity_and_flags;
2454 xev.xclient.data.l[1] = x;
2455 xev.xclient.data.l[2] = y;
2456 xev.xclient.data.l[3] = width;
2457 xev.xclient.data.l[4] = height;
2458
2459 _vnck_error_trap_push (display);
2460 XSendEvent (display,
2461 root,
2462 False0,
2463 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19),
2464 &xev);
2465 _vnck_error_trap_pop (display);
2466}
2467
2468void
2469_vnck_get_window_position (Screen *screen,
2470 Window xwindow,
2471 int *xp,
2472 int *yp)
2473{
2474 Display *display;
2475 Window root;
2476 int x, y;
2477 Window child;
2478
2479 x = 0;
2480 y = 0;
2481
2482 display = DisplayOfScreen (screen)((screen)->display);
2483 root = RootWindowOfScreen (screen)((screen)->root);
2484
2485 _vnck_error_trap_push (display);
2486 XTranslateCoordinates (display,
2487 xwindow,
2488 root,
2489 0, 0,
2490 &x, &y, &child);
2491 _vnck_error_trap_pop (display);
2492
2493 if (xp)
2494 *xp = x;
2495 if (yp)
2496 *yp = y;
2497}
2498
2499void
2500_vnck_set_icon_geometry (Screen *screen,
2501 Window xwindow,
2502 int x,
2503 int y,
2504 int width,
2505 int height)
2506{
2507 Display *display;
2508 gulong data[4];
2509
2510 display = DisplayOfScreen (screen)((screen)->display);
2511
2512 data[0] = x;
2513 data[1] = y;
2514 data[2] = width;
2515 data[3] = height;
2516
2517 _vnck_error_trap_push (display);
2518
2519 XChangeProperty (display,
2520 xwindow,
2521 _vnck_atom_get ("_NET_WM_ICON_GEOMETRY")cdk_x11_get_xatom_by_name ("_NET_WM_ICON_GEOMETRY"),
2522 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
2523 (guchar *)&data, 4);
2524
2525 _vnck_error_trap_pop (display);
2526}
2527
2528CdkDisplay*
2529_vnck_cdk_display_lookup_from_display (Display *display)
2530{
2531 CdkDisplay *cdkdisplay = NULL((void*)0);
2532
2533 cdkdisplay = cdk_x11_lookup_xdisplay (display);
2534
2535 if (!cdkdisplay)
2536 g_warning ("No CdkDisplay matching Display \"%s\" was found.\n",
2537 DisplayString (display)(((_XPrivDisplay)(display))->display_name));
2538
2539 return cdkdisplay;
2540}
2541
2542CdkWindow*
2543_vnck_cdk_window_lookup_from_window (Screen *screen,
2544 Window xwindow)
2545{
2546 Display *display;
2547 CdkDisplay *cdkdisplay;
2548
2549 display = DisplayOfScreen (screen)((screen)->display);
2550 cdkdisplay = _vnck_cdk_display_lookup_from_display (display);
2551 if (!cdkdisplay)
2552 return NULL((void*)0);
2553
2554 return cdk_x11_window_lookup_for_display (cdkdisplay, xwindow);
2555}
2556
2557/* orientation of pager */
2558#define _NET_WM_ORIENTATION_HORZ0 0
2559#define _NET_WM_ORIENTATION_VERT1 1
2560
2561/* starting corner for counting spaces */
2562#define _NET_WM_TOPLEFT0 0
2563#define _NET_WM_TOPRIGHT1 1
2564#define _NET_WM_BOTTOMRIGHT2 2
2565#define _NET_WM_BOTTOMLEFT3 3
2566
2567void
2568_vnck_set_desktop_layout (Screen *xscreen,
2569 int rows,
2570 int columns)
2571{
2572 Display *display;
2573 Window root;
2574 gulong data[4];
2575
2576 /* FIXME: hack, hack, hack so as not
2577 * to have to add a orientation param
2578 * to vnck_screen_try_set_workspace_layout.
2579 *
2580 * Remove this crack asap.
2581 */
2582 g_assert ((rows == 0) || (columns == 0))do { if ((rows == 0) || (columns == 0)) ; else g_assertion_message_expr
("Vnck", "../libvnck/xutils.c", 2582, ((const char*) (__func__
)), "(rows == 0) || (columns == 0)"); } while (0)
;
2583
2584 display = DisplayOfScreen (xscreen)((xscreen)->display);
2585 root = RootWindowOfScreen (xscreen)((xscreen)->root);
2586
2587 data[0] = (columns == 0) ? _NET_WM_ORIENTATION_HORZ0 : _NET_WM_ORIENTATION_VERT1;
2588 data[1] = columns;
2589 data[2] = rows;
2590 data[3] = _NET_WM_TOPLEFT0;
2591
2592 _vnck_error_trap_push (display);
2593
2594 XChangeProperty (display,
2595 root,
2596 _vnck_atom_get ("_NET_DESKTOP_LAYOUT")cdk_x11_get_xatom_by_name ("_NET_DESKTOP_LAYOUT"),
2597 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
2598 (guchar *)&data, 4);
2599
2600 _vnck_error_trap_pop (display);
2601}
2602
2603typedef struct
2604{
2605 Window window;
2606 Atom timestamp_prop_atom;
2607} TimeStampInfo;
2608
2609static Boolint
2610timestamp_predicate (Display *display G_GNUC_UNUSED__attribute__ ((__unused__)),
2611 XEvent *xevent,
2612 XPointer arg)
2613{
2614 TimeStampInfo *info = (TimeStampInfo *)arg;
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
2615
2616 if (xevent->type == PropertyNotify28 &&
2617 xevent->xproperty.window == info->window &&
2618 xevent->xproperty.atom == info->timestamp_prop_atom)
2619 return True1;
2620
2621 return False0;
2622}
2623
2624/**
2625 * get_server_time:
2626 * @display: display from which to get the time
2627 * @window: a #Window, used for communication with the server.
2628 * The window must have PropertyChangeMask in its
2629 * events mask or a hang will result.
2630 *
2631 * Routine to get the current X server time stamp.
2632 *
2633 * Return value: the time stamp.
2634 **/
2635static Time
2636get_server_time (Display *display,
2637 Window window)
2638{
2639 unsigned char c = 'a';
2640 XEvent xevent;
2641 TimeStampInfo info;
2642
2643 info.timestamp_prop_atom = _vnck_atom_get ("_TIMESTAMP_PROP")cdk_x11_get_xatom_by_name ("_TIMESTAMP_PROP");
2644 info.window = window;
2645
2646 XChangeProperty (display, window,
2647 info.timestamp_prop_atom, info.timestamp_prop_atom,
2648 8, PropModeReplace0, &c, 1);
2649
2650 XIfEvent (display, &xevent,
2651 timestamp_predicate, (XPointer)&info);
2652
2653 return xevent.xproperty.time;
2654}
2655
2656typedef struct
2657{
2658 Display *display;
2659 int screen_number;
2660 int token;
2661 Window window;
2662 Atom selection_atom;
2663 Atom manager_atom;
2664} LayoutManager;
2665
2666static GSList *layout_managers = NULL((void*)0);
2667static int next_token = 1;
2668
2669static void
2670_vnck_free_layout_manager (LayoutManager *lm)
2671{
2672 _vnck_error_trap_push (lm->display);
2673 XDestroyWindow (lm->display, lm->window);
2674 _vnck_error_trap_pop (lm->display);
2675
2676 g_slice_free (LayoutManager, lm)do { if (1) g_slice_free1 (sizeof (LayoutManager), (lm)); else
(void) ((LayoutManager*) 0 == (lm)); } while (0)
;
2677
2678 layout_managers = g_slist_remove (layout_managers, lm);
2679}
2680
2681int
2682_vnck_try_desktop_layout_manager (Screen *xscreen,
2683 int current_token)
2684{
2685 Display *display;
2686 Window root;
2687 Atom selection_atom;
2688 Window owner;
2689 GSList *tmp;
2690 int number;
2691 Time timestamp;
2692 XClientMessageEvent xev;
2693 char buffer[256];
2694 LayoutManager *lm;
2695
2696 display = DisplayOfScreen (xscreen)((xscreen)->display);
2697 root = RootWindowOfScreen (xscreen)((xscreen)->root);
2698 number = XScreenNumberOfScreen (xscreen);
2699
2700 sprintf (buffer, "_NET_DESKTOP_LAYOUT_S%d", number);
2701 selection_atom = _vnck_atom_get (buffer)cdk_x11_get_xatom_by_name (buffer);
2702
2703 owner = XGetSelectionOwner (display, selection_atom);
2704
2705 tmp = layout_managers;
2706 while (tmp != NULL((void*)0))
2707 {
2708 lm = tmp->data;
2709
2710 if (display == lm->display &&
2711 number == lm->screen_number)
2712 {
2713 if (current_token == lm->token)
2714 {
2715 if (owner == lm->window)
2716 return current_token; /* we still have the selection */
2717 else
2718 { /* we lost the selection */
2719 _vnck_free_layout_manager (lm);
2720 break;
2721 }
2722 }
2723 else
2724 return VNCK_NO_MANAGER_TOKEN0; /* someone else has it */
2725 }
2726
2727 tmp = tmp->next;
2728 }
2729
2730 if (owner != None0L)
2731 return VNCK_NO_MANAGER_TOKEN0; /* someone else has the selection */
2732
2733 /* No one has the selection at the moment */
2734
2735 lm = g_slice_new0 (LayoutManager)((LayoutManager*) g_slice_alloc0 (sizeof (LayoutManager)));
2736
2737 lm->display = display;
2738 lm->screen_number = number;
2739 lm->token = next_token;
2740 ++next_token;
2741
2742 lm->selection_atom = selection_atom;
2743 lm->manager_atom = _vnck_atom_get ("MANAGER")cdk_x11_get_xatom_by_name ("MANAGER");
2744
2745 _vnck_error_trap_push (display);
2746
2747 lm->window = XCreateSimpleWindow (display,
2748 root,
2749 0, 0, 10, 10, 0,
2750 WhitePixel (display, number)((&((_XPrivDisplay)(display))->screens[number])->white_pixel
)
,
2751 WhitePixel (display, number)((&((_XPrivDisplay)(display))->screens[number])->white_pixel
)
);
2752
2753 XSelectInput (display, lm->window, PropertyChangeMask(1L<<22));
2754 timestamp = get_server_time (display, lm->window);
2755
2756 XSetSelectionOwner (display, lm->selection_atom,
2757 lm->window, timestamp);
2758
2759 _vnck_error_trap_pop (display);
2760
2761 /* Check to see if we managed to claim the selection. */
2762
2763 if (XGetSelectionOwner (display, lm->selection_atom) !=
2764 lm->window)
2765 {
2766 g_free (lm);
2767 return VNCK_NO_MANAGER_TOKEN0;
2768 }
2769
2770 xev.type = ClientMessage33;
2771 xev.window = root;
2772 xev.message_type = lm->manager_atom;
2773 xev.format = 32;
2774 xev.data.l[0] = timestamp;
2775 xev.data.l[1] = lm->selection_atom;
2776 xev.data.l[2] = lm->window;
2777 xev.data.l[3] = 0; /* manager specific data */
2778 xev.data.l[4] = 0; /* manager specific data */
2779
2780 _vnck_error_trap_push (display);
2781 XSendEvent (display, root,
2782 False0, StructureNotifyMask(1L<<17), (XEvent *)&xev);
2783 _vnck_error_trap_pop (display);
2784
2785 layout_managers = g_slist_prepend (layout_managers,
2786 lm);
2787
2788 return lm->token;
2789}
2790
2791void
2792_vnck_release_desktop_layout_manager (Screen *xscreen,
2793 int current_token)
2794{
2795 Display *display;
2796 GSList *tmp;
2797 int number;
2798 LayoutManager *lm;
2799
2800 display = DisplayOfScreen (xscreen)((xscreen)->display);
2801 number = XScreenNumberOfScreen (xscreen);
2802
2803 tmp = layout_managers;
2804 while (tmp != NULL((void*)0))
2805 {
2806 lm = tmp->data;
2807
2808 if (display == lm->display &&
2809 number == lm->screen_number)
2810 {
2811 if (current_token == lm->token)
2812 {
2813 _vnck_error_trap_push (display);
2814
2815 /* release selection ownership */
2816 if (XGetSelectionOwner (display, lm->selection_atom) !=
2817 lm->window)
2818 {
2819 Time timestamp;
2820
2821 timestamp = get_server_time (display, lm->window);
2822 XSetSelectionOwner (display, lm->selection_atom,
2823 None0L, timestamp);
2824 }
2825
2826 _vnck_error_trap_pop (display);
2827
2828 _vnck_free_layout_manager (lm);
2829 return;
2830 }
2831 }
2832
2833 tmp = tmp->next;
2834 }
2835}
2836
2837gboolean
2838_vnck_desktop_layout_manager_process_event (XEvent *xev)
2839{
2840 GSList *tmp;
2841 LayoutManager *lm = NULL((void*)0);
2842
2843 if (xev->type != SelectionClear29)
2844 return FALSE(0);
2845
2846 tmp = layout_managers;
2847 while (tmp != NULL((void*)0))
2848 {
2849 lm = tmp->data;
2850
2851 if (xev->xany.display == lm->display &&
2852 xev->xany.window == lm->window &&
2853 xev->xselectionclear.selection == lm->selection_atom)
2854 {
2855 _vnck_free_layout_manager (lm);
2856 return TRUE(!(0));
2857 }
2858
2859 tmp = tmp->next;
2860 }
2861
2862 return FALSE(0);
2863}