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