2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* tasklist.c - code for tracking windows
22 * Loosly based on code in GNOME's libwnck.
34 #include <X11/Xatom.h>
41 #include "gui_support.h"
47 /* There is one of these for each window controlled by the window
48 * manager (all tasks) in the _NET_CLIENT_LIST property.
50 typedef struct _IconWindow IconWindow
;
53 GtkWidget
*widget
; /* Widget used for icon when iconified */
58 gint timeout_update
; /* Non-zero => timeout callback in use */
61 /* If TRUE, only iconfied windows with _NET_WM_STATE_HIDDEN are really icons */
62 static gboolean wm_supports_hidden
= FALSE
;
64 static GdkAtom xa__NET_SUPPORTED
= GDK_NONE
;
65 static GdkAtom xa_WM_STATE
= GDK_NONE
;
66 static GdkAtom xa_WM_NAME
= GDK_NONE
;
67 static GdkAtom xa_WM_ICON_NAME
= GDK_NONE
;
68 static GdkAtom xa_UTF8_STRING
= GDK_NONE
;
69 static GdkAtom xa_TEXT
= GDK_NONE
;
70 static GdkAtom xa__NET_WM_VISIBLE_NAME
= GDK_NONE
;
71 static GdkAtom xa__NET_WM_ICON_NAME
= GDK_NONE
;
72 static GdkAtom xa__NET_CLIENT_LIST
= GDK_NONE
;
73 static GdkAtom xa__NET_WM_ICON_GEOMETRY
= GDK_NONE
;
74 static GdkAtom xa__NET_WM_STATE
= GDK_NONE
;
75 static GdkAtom xa__NET_WM_STATE_HIDDEN
= GDK_NONE
;
76 static GdkAtom xa__NET_WM_DESKTOP
= GDK_NONE
;
77 static GdkAtom xa__NET_CURRENT_DESKTOP
= GDK_NONE
;
78 static GdkAtom xa__NET_DESKTOP_GEOMETRY
= GDK_NONE
;
79 static GdkAtom xa__NET_DESKTOP_VIEWPORT
= GDK_NONE
;
81 /* We have selected destroy and property events on every window in
84 static GHashTable
*known
= NULL
; /* XID -> IconWindow */
86 /* Static prototypes */
87 static void remove_window(Window win
);
88 static void tasklist_update(gboolean to_empty
);
89 static GdkFilterReturn
window_filter(GdkXEvent
*xevent
,
92 static guint
xid_hash(XID
*xid
);
93 static gboolean
xid_equal(XID
*a
, XID
*b
);
94 static void state_changed(IconWindow
*win
);
95 static void show_icon(IconWindow
*win
);
96 static void icon_win_free(IconWindow
*win
);
97 static void update_style(gpointer key
, gpointer data
, gpointer user_data
);
98 static void update_supported(void);
99 static gboolean
update_title(gpointer data
);
100 static void update_current_desktop(void);
102 /* remember what desktop number (and viewport) is currently displayed */
103 static int cur_desktop
= 0;
104 static GdkRectangle cur_viewport
;
106 /****************************************************************
107 * EXTERNAL INTERFACE *
108 ****************************************************************/
110 void tasklist_set_active(gboolean active
)
112 static gboolean need_init
= TRUE
;
113 static gboolean tasklist_active
= FALSE
;
115 if (active
== tasklist_active
)
117 if (o_pinboard_tasklist_per_workspace
.has_changed
&& active
)
118 tasklist_update(FALSE
);
121 tasklist_active
= active
;
127 root
= gdk_get_default_root_window();
129 xa__NET_SUPPORTED
= gdk_atom_intern("_NET_SUPPORTED", FALSE
);
130 xa_WM_STATE
= gdk_atom_intern("WM_STATE", FALSE
);
131 xa_WM_ICON_NAME
= gdk_atom_intern("WM_ICON_NAME", FALSE
);
132 xa_WM_NAME
= gdk_atom_intern("WM_NAME", FALSE
);
133 xa_UTF8_STRING
= gdk_atom_intern("UTF8_STRING", FALSE
);
134 xa_TEXT
= gdk_atom_intern("TEXT", FALSE
);
135 xa__NET_CLIENT_LIST
=
136 gdk_atom_intern("_NET_CLIENT_LIST", FALSE
);
137 xa__NET_WM_VISIBLE_NAME
=
138 gdk_atom_intern("_NET_WM_VISIBLE_NAME", FALSE
);
139 xa__NET_WM_ICON_NAME
=
140 gdk_atom_intern("_NET_WM_ICON_NAME", FALSE
);
141 xa__NET_WM_ICON_GEOMETRY
=
142 gdk_atom_intern("_NET_WM_ICON_GEOMETRY", FALSE
);
143 xa__NET_WM_STATE
= gdk_atom_intern("_NET_WM_STATE", FALSE
);
144 xa__NET_WM_STATE_HIDDEN
=
145 gdk_atom_intern("_NET_WM_STATE_HIDDEN", FALSE
);
146 xa__NET_WM_DESKTOP
= gdk_atom_intern("_NET_WM_DESKTOP", FALSE
);
147 xa__NET_CURRENT_DESKTOP
= gdk_atom_intern("_NET_CURRENT_DESKTOP", FALSE
);
148 xa__NET_DESKTOP_GEOMETRY
= gdk_atom_intern("_NET_DESKTOP_GEOMETRY", FALSE
);
149 xa__NET_DESKTOP_VIEWPORT
= gdk_atom_intern("_NET_DESKTOP_VIEWPORT", FALSE
);
151 known
= g_hash_table_new_full((GHashFunc
) xid_hash
,
152 (GEqualFunc
) xid_equal
,
154 (GDestroyNotify
) icon_win_free
);
155 gdk_window_set_events(root
, gdk_window_get_events(root
) |
156 GDK_PROPERTY_CHANGE_MASK
);
162 update_current_desktop();
163 gdk_window_add_filter(NULL
, window_filter
, NULL
);
167 gdk_window_remove_filter(NULL
, window_filter
, NULL
);
169 tasklist_update(!active
);
172 /* User has changes the colours in the options box... */
173 void tasklist_style_changed(void)
176 g_hash_table_foreach(known
, update_style
, NULL
);
179 /****************************************************************
180 * INTERNAL FUNCTIONS *
181 ****************************************************************/
183 static void icon_win_free(IconWindow
*win
)
185 g_return_if_fail(win
->widget
== NULL
);
186 g_return_if_fail(win
->label
== NULL
);
188 if (win
->timeout_update
)
189 g_source_remove(win
->timeout_update
);
196 static guint
xid_hash(XID
*xid
)
202 static gboolean
xid_equal(XID
*a
, XID
*b
)
207 static int wincmp(const void *a
, const void *b
)
209 const Window
*aw
= a
;
210 const Window
*bw
= b
;
220 /* Read the list of WINDOWs from (xwindow,atom), returning them
221 * in a (sorted) Array of Windows. On error, an empty array is
223 * Free the array afterwards.
225 static GArray
*get_window_list(Window xwindow
, GdkAtom atom
)
236 array
= g_array_new(FALSE
, FALSE
, sizeof(Window
));
238 gdk_error_trap_push();
240 result
= XGetWindowProperty(gdk_display
,
242 gdk_x11_atom_to_xatom(atom
),
244 False
, XA_WINDOW
, &type
, &format
, &nitems
,
245 &bytes_after
, &data
);
246 err
= gdk_error_trap_pop();
248 if (err
!= Success
|| result
!= Success
)
251 if (type
== XA_WINDOW
)
253 for (i
= 0; i
< nitems
; i
++)
254 g_array_append_val(array
, ((Window
*) data
)[i
]);
257 g_array_sort(array
, wincmp
);
265 static guchar
*get_str(IconWindow
*win
, GdkAtom atom
)
271 unsigned char *data
, *str
= NULL
;
274 gdk_error_trap_push();
276 result
= XGetWindowProperty(gdk_display
, win
->xwindow
,
277 gdk_x11_atom_to_xatom(atom
),
280 &rtype
, &format
, &nitems
,
281 &bytes_after
, &data
);
283 err
= gdk_error_trap_pop();
285 if (err
== Success
&& result
== Success
&& data
)
288 str
= g_strdup(data
);
295 static void get_icon_name(IconWindow
*win
)
297 null_g_free(&win
->text
);
299 /* Keep this list in sync with window_filter */
301 win
->text
= get_str(win
, xa__NET_WM_ICON_NAME
);
303 win
->text
= get_str(win
, xa__NET_WM_VISIBLE_NAME
);
305 win
->text
= get_str(win
, xa_WM_ICON_NAME
);
307 win
->text
= get_str(win
, xa_WM_NAME
);
309 win
->text
= g_strdup(_("Window"));
312 static gboolean
update_title(gpointer data
)
314 IconWindow
*win
= (IconWindow
*) data
;
317 return FALSE
; /* No longer an icon */
320 wrapped_label_set_text(WRAPPED_LABEL(win
->label
), win
->text
);
322 win
->timeout_update
= 0;
327 /* Call from within error_push/pop
328 * See wnck_window_is_in_viewport */
329 static gboolean
within_viewport(Window xwindow
)
332 unsigned int width
, height
, bw
, depth
;
333 Window root_window
, child
;
334 GdkRectangle win_rect
;
336 XGetGeometry (gdk_display
,
339 &x
, &y
, &width
, &height
, &bw
, &depth
);
340 XTranslateCoordinates (gdk_display
,
346 win_rect
.x
= x
+ cur_viewport
.x
;
347 win_rect
.y
= y
+ cur_viewport
.y
;
348 win_rect
.width
= width
;
349 win_rect
.height
= height
;
351 return gdk_rectangle_intersect (&cur_viewport
, &win_rect
, &win_rect
);
354 /* Call from within error_push/pop */
355 static void window_check_status(IconWindow
*win
)
362 Window transient_for
;
363 gboolean iconic
= FALSE
;
365 if (XGetTransientForHint(gdk_display
, win
->xwindow
, &transient_for
) && transient_for
)
367 else if (wm_supports_hidden
&& XGetWindowProperty(gdk_display
, win
->xwindow
,
368 gdk_x11_atom_to_xatom(xa__NET_WM_STATE
),
371 &type
, &format
, &nitems
,
372 &bytes_after
, &data
) == Success
&& data
)
377 for (i
= 0; i
< nitems
; i
++)
379 state
= gdk_x11_xatom_to_atom(((Atom
*) data
)[i
]);
380 if (state
== xa__NET_WM_STATE_HIDDEN
)
388 else if (XGetWindowProperty(gdk_display
, win
->xwindow
,
389 gdk_x11_atom_to_xatom(xa_WM_STATE
),
391 gdk_x11_atom_to_xatom(xa_WM_STATE
),
392 &type
, &format
, &nitems
,
393 &bytes_after
, &data
) == Success
&& data
)
395 iconic
= ((guint32
*) data
)[0] == 3;
401 /* Iconified windows on another desktops are not shown */
402 if (o_pinboard_tasklist_per_workspace
.int_value
&&
403 XGetWindowProperty(gdk_display
, win
->xwindow
,
404 gdk_x11_atom_to_xatom(xa__NET_WM_DESKTOP
),
405 0, G_MAXLONG
, False
, XA_CARDINAL
, &type
, &format
, &nitems
,
406 &bytes_after
, &data
) == Success
&& data
)
408 guint32 desk_on
= ((guint32
*) data
)[0];
410 if ((desk_on
!= 0xffffffff) && ((desk_on
!= cur_desktop
) ||
411 !within_viewport(win
->xwindow
)))
416 if (win
->iconified
== iconic
)
419 win
->iconified
= iconic
;
426 static void update_current_desktop(void)
434 if (XGetWindowProperty(gdk_display
, gdk_x11_get_default_root_xwindow(),
435 gdk_x11_atom_to_xatom(xa__NET_CURRENT_DESKTOP
),
436 0, G_MAXLONG
, False
, XA_CARDINAL
, &type
, &format
, &nitems
,
437 &bytes_after
, (unsigned char **)(&data
)) == Success
&& data
) {
438 cur_desktop
= ((gint32
*)data
)[0];
442 if (XGetWindowProperty(gdk_display
, gdk_x11_get_default_root_xwindow(),
443 gdk_x11_atom_to_xatom(xa__NET_DESKTOP_VIEWPORT
),
444 0, G_MAXLONG
, False
, XA_CARDINAL
, &type
, &format
,
446 &bytes_after
, (unsigned char **)(&data
)) == Success
&&
448 cur_viewport
.x
= ((gint32
*)data
)[0];
449 cur_viewport
.y
= ((gint32
*)data
)[1];
450 cur_viewport
.width
= screen_width
;
451 cur_viewport
.height
= screen_height
;
456 /* Called for all events on all windows */
457 static GdkFilterReturn
window_filter(GdkXEvent
*xevent
,
461 XEvent
*xev
= (XEvent
*) xevent
;
464 if (xev
->type
== PropertyNotify
)
466 GdkAtom atom
= gdk_x11_xatom_to_atom(xev
->xproperty
.atom
);
467 Window win
= ((XPropertyEvent
*) xev
)->window
;
469 if (atom
== xa_WM_STATE
|| atom
== xa__NET_WM_STATE
)
471 w
= g_hash_table_lookup(known
, &win
);
475 gdk_error_trap_push();
476 window_check_status(w
);
477 if (gdk_error_trap_pop() != Success
)
478 g_hash_table_remove(known
, &win
);
481 else if (atom
== xa__NET_CURRENT_DESKTOP
||
482 atom
== xa__NET_DESKTOP_VIEWPORT
||
483 atom
== xa__NET_DESKTOP_GEOMETRY
)
485 update_current_desktop();
486 tasklist_update(FALSE
);
488 else if (atom
== xa__NET_WM_ICON_NAME
||
489 atom
== xa__NET_WM_VISIBLE_NAME
||
490 atom
== xa_WM_ICON_NAME
||
493 /* Keep this list in sync with get_icon_name */
494 w
= g_hash_table_lookup(known
, &win
);
496 if (w
&& w
->widget
&& !w
->timeout_update
)
497 w
->timeout_update
= g_timeout_add(100,
500 else if (atom
== xa__NET_CLIENT_LIST
)
501 tasklist_update(FALSE
);
502 else if (atom
== xa__NET_SUPPORTED
)
506 return GDK_FILTER_CONTINUE
;
509 /* Window has been added to list of managed windows */
510 static void add_window(Window win
)
514 /* g_print("[ New window %ld ]\n", (long) win); */
516 w
= g_hash_table_lookup(known
, &win
);
520 XWindowAttributes attr
;
522 gdk_error_trap_push();
524 XGetWindowAttributes(gdk_display
, win
, &attr
);
526 if (gdk_error_trap_pop() != Success
)
528 gdk_error_trap_push();
530 XSelectInput(gdk_display
, win
, attr
.your_event_mask
|
535 if (gdk_error_trap_pop() != Success
)
538 w
= g_new(IconWindow
, 1);
543 w
->iconified
= FALSE
;
544 w
->timeout_update
= 0;
546 g_hash_table_insert(known
, &w
->xwindow
, w
);
549 gdk_error_trap_push();
551 window_check_status(w
);
557 if (gdk_error_trap_pop() != Success
)
558 g_hash_table_remove(known
, &win
);
561 /* Window is no longer managed, but hasn't been destroyed yet */
562 static void remove_window(Window win
)
566 /* g_print("[ Remove window %ld ]\n", (long) win); */
568 w
= g_hash_table_lookup(known
, &win
);
573 w
->iconified
= FALSE
;
577 g_hash_table_remove(known
, &win
);
581 /* Make sure the window list is up-to-date. Call once to start, and then
582 * everytime _NET_CLIENT_LIST changes.
583 * If 'to_empty' is set them pretend all windows have disappeared.
585 static void tasklist_update(gboolean to_empty
)
587 static GArray
*old_mapping
= NULL
;
588 GArray
*mapping
= NULL
;
593 old_mapping
= g_array_new(FALSE
, FALSE
, sizeof(Window
));
597 mapping
= g_array_new(FALSE
, FALSE
, sizeof(Window
));
599 mapping
= get_window_list(gdk_x11_get_default_root_xwindow(),
600 gdk_atom_intern("_NET_CLIENT_LIST", FALSE
));
604 while (new_i
< mapping
->len
&& old_i
< old_mapping
->len
)
606 Window
new = g_array_index(mapping
, Window
, new_i
);
607 Window old
= g_array_index(old_mapping
, Window
, old_i
);
626 while (new_i
< mapping
->len
)
628 add_window(g_array_index(mapping
, Window
, new_i
));
631 while (old_i
< old_mapping
->len
)
633 remove_window(g_array_index(old_mapping
, Window
, old_i
));
637 g_array_free(old_mapping
, TRUE
);
638 old_mapping
= mapping
;
641 /* Called when the user clicks on the button */
642 static void uniconify(IconWindow
*win
, guint32 timestamp
)
644 XClientMessageEvent sev
;
646 sev
.type
= ClientMessage
;
647 sev
.display
= gdk_display
;
649 sev
.window
= win
->xwindow
;
650 sev
.message_type
= gdk_x11_atom_to_xatom(
651 gdk_atom_intern("_NET_ACTIVE_WINDOW", FALSE
));
653 sev
.data
.l
[1] = timestamp
;
656 gdk_error_trap_push();
658 XSendEvent(gdk_display
, DefaultRootWindow(gdk_display
), False
,
659 SubstructureNotifyMask
| SubstructureRedirectMask
,
661 XSync(gdk_display
, False
);
663 gdk_error_trap_pop();
666 static gint drag_start_x
= -1;
667 static gint drag_start_y
= -1;
668 static gboolean drag_started
= FALSE
;
669 static gint drag_off_x
= -1;
670 static gint drag_off_y
= -1;
672 static void icon_button_press(GtkWidget
*widget
,
673 GdkEventButton
*event
,
676 if (event
->button
== 1)
678 drag_start_x
= event
->x_root
;
679 drag_start_y
= event
->y_root
;
680 drag_started
= FALSE
;
682 drag_off_x
= event
->x
;
683 drag_off_y
= event
->y
;
687 static gboolean
icon_motion_notify(GtkWidget
*widget
,
688 GdkEventMotion
*event
,
691 if (event
->state
& GDK_BUTTON1_MASK
)
693 int dx
= event
->x_root
- drag_start_x
;
694 int dy
= event
->y_root
- drag_start_y
;
698 if (abs(dx
) < 5 && abs(dy
) < 5)
703 fixed_move_fast(GTK_FIXED(win
->widget
->parent
),
705 event
->x_root
- drag_off_x
,
706 event
->y_root
- drag_off_y
);
708 pinboard_moved_widget(win
->widget
, win
->text
,
709 event
->x_root
- drag_off_x
,
710 event
->y_root
- drag_off_y
);
716 static void button_released(GtkWidget
*widget
, GdkEventButton
*event
,
719 if (!drag_started
&& event
->button
== 1)
720 uniconify(win
, event
->time
);
723 static GdkColormap
* get_cmap(GdkPixmap
*pixmap
)
727 cmap
= gdk_drawable_get_colormap(pixmap
);
729 g_object_ref(G_OBJECT(cmap
));
733 if (gdk_drawable_get_depth(pixmap
) == 1)
735 /* Masks don't need colourmaps */
740 /* Try system cmap */
741 cmap
= gdk_colormap_get_system();
742 g_object_ref(G_OBJECT(cmap
));
746 /* Be sure we aren't going to blow up due to visual mismatch */
747 if (cmap
&& (gdk_colormap_get_visual(cmap
)->depth
!=
748 gdk_drawable_get_depth(pixmap
)))
754 /* Copy a pixmap from the server to a client-side pixbuf */
755 static GdkPixbuf
* pixbuf_from_pixmap(Pixmap xpixmap
)
757 GdkDrawable
*drawable
;
764 drawable
= gdk_xid_table_lookup(xpixmap
);
766 if (GDK_IS_DRAWABLE(drawable
))
767 g_object_ref(G_OBJECT(drawable
));
770 drawable
= gdk_pixmap_foreign_new(xpixmap
);
771 if (!GDK_IS_DRAWABLE(drawable
))
775 cmap
= get_cmap(drawable
);
777 /* GDK is supposed to do this but doesn't in GTK 2.0.2,
780 gdk_drawable_get_size(drawable
, &width
, &height
);
782 retval
= gdk_pixbuf_get_from_drawable(NULL
, drawable
, cmap
,
783 0, 0, 0, 0, width
, height
);
786 g_object_unref(G_OBJECT(cmap
));
787 g_object_unref(G_OBJECT(drawable
));
792 /* Creates a new masked pixbuf from a non-masked pixbuf and a mask */
793 static GdkPixbuf
* apply_mask(GdkPixbuf
*pixbuf
, GdkPixbuf
*mask
)
797 GdkPixbuf
*with_alpha
;
803 w
= MIN(gdk_pixbuf_get_width(mask
), gdk_pixbuf_get_width(pixbuf
));
804 h
= MIN(gdk_pixbuf_get_height(mask
), gdk_pixbuf_get_height(pixbuf
));
806 with_alpha
= gdk_pixbuf_add_alpha(pixbuf
, FALSE
, 0, 0, 0);
808 dest
= gdk_pixbuf_get_pixels(with_alpha
);
809 src
= gdk_pixbuf_get_pixels(mask
);
811 dest_stride
= gdk_pixbuf_get_rowstride(with_alpha
);
812 src_stride
= gdk_pixbuf_get_rowstride(mask
);
820 guchar
*s
= src
+ i
* src_stride
+ j
* 3;
821 guchar
*d
= dest
+ i
* dest_stride
+ j
* 4;
823 /* s[0] == s[1] == s[2], they are 255 if the bit was
827 d
[3] = 0; /* transparent */
829 d
[3] = 255; /* opaque */
842 /* Take the icon that the iconified window has given us and modify it to make
843 * it obvious what it is.
845 static GdkPixbuf
*apply_window_effect(GdkPixbuf
*src
)
850 w
= gdk_pixbuf_get_width(src
);
851 h
= gdk_pixbuf_get_height(src
);
853 new = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(src
), TRUE
,
854 8, w
+ BORDER_X
* 2, h
+ BORDER_Y
* 2);
855 gdk_pixbuf_fill(new, 0x88888888);
857 gdk_pixbuf_composite(src
, new,
858 BORDER_X
, BORDER_Y
, w
, h
,
859 BORDER_X
, BORDER_Y
, 1, 1,
860 GDK_INTERP_NEAREST
, 255);
865 /* Return a suitable icon for this window. unref the result.
866 * Never returns NULL.
868 static GdkPixbuf
*get_image_for(IconWindow
*win
)
870 static MaskedPixmap
*default_icon
= NULL
;
871 Pixmap pixmap
= None
;
874 GdkPixbuf
*retval
= NULL
;
876 /* Try the pixmap and mask in the old WMHints... */
877 gdk_error_trap_push();
878 hints
= XGetWMHints(gdk_display
, win
->xwindow
);
882 if (hints
->flags
& IconPixmapHint
)
883 pixmap
= hints
->icon_pixmap
;
884 if (hints
->flags
& IconMaskHint
)
885 mask
= hints
->icon_mask
;
893 GdkPixbuf
*mask_pb
= NULL
;
895 retval
= pixbuf_from_pixmap(pixmap
);
897 if (retval
&& mask
!= None
)
898 mask_pb
= pixbuf_from_pixmap(mask
);
904 masked
= apply_mask(retval
, mask_pb
);
905 g_object_unref(G_OBJECT(mask_pb
));
909 g_object_unref(G_OBJECT(retval
));
917 gdk_error_trap_pop();
922 default_icon
= load_pixmap("iconified");
924 retval
= default_icon
->pixbuf
;
925 g_object_ref(retval
);
928 /* Apply a special effect to make this look different from normal
932 GdkPixbuf
*old
= retval
;
934 small
= scale_pixbuf(old
, ICON_WIDTH
, ICON_HEIGHT
);
936 retval
= apply_window_effect(small
);
937 g_object_unref(small
);
943 /* Stop the button from highlighting */
944 static gint
icon_expose(GtkWidget
*widget
, GdkEventExpose
*event
,
947 static GtkWidgetClass
*parent_class
= NULL
;
949 g_return_val_if_fail(win
!= NULL
, TRUE
);
950 g_return_val_if_fail(win
->label
!= NULL
, TRUE
);
954 gpointer c
= ((GTypeInstance
*) widget
)->g_class
;
955 parent_class
= (GtkWidgetClass
*) g_type_class_peek_parent(c
);
958 draw_label_shadow((WrappedLabel
*) win
->label
, event
->region
);
960 gdk_gc_set_clip_region(win
->label
->style
->fg_gc
[win
->label
->state
],
962 (parent_class
->expose_event
)(widget
, event
);
963 gdk_gc_set_clip_region(win
->label
->style
->fg_gc
[win
->label
->state
],
966 /* Stop the button effect */
970 /* A window has been iconified -- display it on the screen */
971 static void show_icon(IconWindow
*win
)
976 g_return_if_fail(win
->widget
== NULL
);
977 g_return_if_fail(win
->label
== NULL
);
979 win
->widget
= gtk_button_new();
980 gtk_button_set_relief(GTK_BUTTON(win
->widget
), GTK_RELIEF_NONE
);
981 g_signal_connect(win
->widget
, "expose-event",
982 G_CALLBACK(icon_expose
), win
);
983 vbox
= gtk_vbox_new(FALSE
, 0);
984 gtk_container_add(GTK_CONTAINER(win
->widget
), vbox
);
986 pixbuf
= get_image_for(win
);
988 gtk_box_pack_start(GTK_BOX(vbox
), simple_image_new(pixbuf
),
990 g_object_unref(pixbuf
);
992 win
->label
= wrapped_label_new(win
->text
, 180);
994 update_style(NULL
, win
, NULL
);
996 gtk_box_pack_start(GTK_BOX(vbox
), win
->label
, FALSE
, TRUE
, 0);
998 gtk_widget_add_events(win
->widget
,
999 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON_RELEASE_MASK
);
1000 g_signal_connect(win
->widget
, "button-press-event",
1001 G_CALLBACK(icon_button_press
), win
);
1002 g_signal_connect(win
->widget
, "motion-notify-event",
1003 G_CALLBACK(icon_motion_notify
), win
);
1004 g_signal_connect(win
->widget
, "button-release-event",
1005 G_CALLBACK(button_released
), win
);
1007 gtk_widget_show_all(vbox
); /* So the size comes out right */
1008 pinboard_add_widget(win
->widget
, win
->text
);
1009 gtk_widget_show(win
->widget
);
1012 /* A window has been destroyed/expanded -- remove its icon */
1013 static void hide_icon(IconWindow
*win
)
1015 g_return_if_fail(win
->widget
!= NULL
);
1017 gtk_widget_hide(win
->widget
); /* Stops flicker - stupid GtkFixed! */
1018 gtk_widget_destroy(win
->widget
);
1023 static void state_changed(IconWindow
*win
)
1035 /* Set the _NET_WM_ICON_GEOMETRY property, which indicates where this window
1036 * will be iconified to. Should be inside a push/pop.
1038 static void set_iconify_pos(IconWindow
*win
)
1042 data
[0] = iconify_next_x
;
1043 data
[1] = iconify_next_y
;
1047 XChangeProperty(gdk_display
, win
->xwindow
,
1048 gdk_x11_atom_to_xatom(xa__NET_WM_ICON_GEOMETRY
),
1049 XA_CARDINAL
, 32, PropModeReplace
, (guchar
*) data
, 4);
1053 static void update_style(gpointer key
, gpointer data
, gpointer user_data
)
1055 IconWindow
*win
= (IconWindow
*) data
;
1060 widget_modify_font(win
->label
, pinboard_font
);
1061 gtk_widget_modify_fg(win
->label
, GTK_STATE_NORMAL
, &pin_text_fg_col
);
1062 gtk_widget_modify_bg(win
->label
, GTK_STATE_NORMAL
, &pin_text_bg_col
);
1063 gtk_widget_modify_fg(win
->label
, GTK_STATE_PRELIGHT
, &pin_text_fg_col
);
1064 gtk_widget_modify_bg(win
->label
, GTK_STATE_PRELIGHT
, &pin_text_bg_col
);
1067 /* Find out what the new window manager can do... */
1068 static void update_supported(void)
1074 unsigned char *data
;
1077 gboolean old_supports_hidden
= wm_supports_hidden
;
1079 wm_supports_hidden
= FALSE
;
1081 gdk_error_trap_push();
1083 result
= XGetWindowProperty(gdk_display
,
1084 gdk_x11_get_default_root_xwindow(),
1085 gdk_x11_atom_to_xatom(xa__NET_SUPPORTED
),
1087 False
, XA_ATOM
, &type
, &format
, &nitems
,
1088 &bytes_after
, &data
);
1089 err
= gdk_error_trap_pop();
1091 if (err
!= Success
|| result
!= Success
)
1094 for (i
= 0; i
< nitems
; i
++)
1096 GdkAtom atom
= gdk_x11_xatom_to_atom(((Atom
*) data
)[i
]);
1098 if (atom
== xa__NET_WM_STATE_HIDDEN
)
1099 wm_supports_hidden
= TRUE
;
1105 if (wm_supports_hidden
!= old_supports_hidden
)
1107 tasklist_update(TRUE
);
1108 tasklist_update(FALSE
);