2
* Copyright (c) 2002 Anders Carlsson <andersca@gnu.org>
3
* Copyright (c) 2003-2006 Vincent Untz
4
* Copyright (c) 2008 Red Hat, Inc.
5
* Copyright (c) 2009-2010 Nick Schermer <nick@xfce.org>
7
* This library is free software; you can redistribute it and/or modify it
8
* under the terms of the GNU General Public License as published by the Free
9
* Software Foundation; either version 2 of the License, or (at your option)
12
* This library is distributed in the hope that it will be useful, but WITHOUT
13
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17
* You should have received a copy of the GNU Library General Public License
18
* along with this library; if not, write to the Free Software Foundation,
19
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
31
#include <X11/Xatom.h>
37
#include <libxfce4panel/libxfce4panel.h>
39
#include <common/panel-private.h>
40
#include <common/panel-debug.h>
42
#include "systray-socket.h"
46
struct _SystraySocketClass
48
GtkSocketClass __parent__;
56
GdkNativeWindow window;
60
guint is_composited : 1;
61
guint parent_relative_bg : 1;
67
static void systray_socket_finalize (GObject *object);
68
static void systray_socket_realize (GtkWidget *widget);
69
static void systray_socket_size_allocate (GtkWidget *widget,
70
GtkAllocation *allocation);
71
static gboolean systray_socket_expose_event (GtkWidget *widget,
72
GdkEventExpose *event);
73
static void systray_socket_style_set (GtkWidget *widget,
74
GtkStyle *previous_style);
78
XFCE_PANEL_DEFINE_TYPE (SystraySocket, systray_socket, GTK_TYPE_SOCKET)
83
systray_socket_class_init (SystraySocketClass *klass)
85
GtkWidgetClass *gtkwidget_class;
86
GObjectClass *gobject_class;
88
gobject_class = G_OBJECT_CLASS (klass);
89
gobject_class->finalize = systray_socket_finalize;
91
gtkwidget_class = GTK_WIDGET_CLASS (klass);
92
gtkwidget_class->realize = systray_socket_realize;
93
gtkwidget_class->size_allocate = systray_socket_size_allocate;
94
gtkwidget_class->expose_event = systray_socket_expose_event;
95
gtkwidget_class->style_set = systray_socket_style_set;
101
systray_socket_init (SystraySocket *socket)
103
socket->hidden = FALSE;
110
systray_socket_finalize (GObject *object)
112
SystraySocket *socket = XFCE_SYSTRAY_SOCKET (object);
114
g_free (socket->name);
116
G_OBJECT_CLASS (systray_socket_parent_class)->finalize (object);
122
systray_socket_realize (GtkWidget *widget)
124
SystraySocket *socket = XFCE_SYSTRAY_SOCKET (widget);
125
GdkColor transparent = { 0, 0, 0, 0 };
128
GTK_WIDGET_CLASS (systray_socket_parent_class)->realize (widget);
130
window = gtk_widget_get_window (widget);
132
if (socket->is_composited)
134
gdk_window_set_background (window, &transparent);
135
gdk_window_set_composited (window, TRUE);
137
socket->parent_relative_bg = FALSE;
139
else if (gtk_widget_get_visual (widget) ==
140
gdk_drawable_get_visual (GDK_DRAWABLE (gdk_window_get_parent (window))))
142
gdk_window_set_back_pixmap (window, NULL, TRUE);
144
socket->parent_relative_bg = TRUE;
148
socket->parent_relative_bg = FALSE;
151
gdk_window_set_composited (window, socket->is_composited);
153
gtk_widget_set_app_paintable (widget,
154
socket->parent_relative_bg || socket->is_composited);
156
gtk_widget_set_double_buffered (widget, socket->parent_relative_bg);
158
panel_debug_filtered (PANEL_DEBUG_SYSTRAY,
159
"socket %s[%p] (composited=%s, relative-bg=%s",
160
systray_socket_get_name (socket), socket,
161
PANEL_DEBUG_BOOL (socket->is_composited),
162
PANEL_DEBUG_BOOL (socket->parent_relative_bg));
168
systray_socket_size_allocate (GtkWidget *widget,
169
GtkAllocation *allocation)
171
SystraySocket *socket = XFCE_SYSTRAY_SOCKET (widget);
172
gboolean moved = allocation->x != widget->allocation.x
173
|| allocation->y != widget->allocation.y;
174
gboolean resized = allocation->width != widget->allocation.width
175
||allocation->height != widget->allocation.height;
177
if ((moved || resized)
178
&& GTK_WIDGET_MAPPED (widget))
180
if (socket->is_composited)
181
gdk_window_invalidate_rect (gdk_window_get_parent (widget->window),
182
&widget->allocation, FALSE);
185
GTK_WIDGET_CLASS (systray_socket_parent_class)->size_allocate (widget, allocation);
187
if ((moved || resized)
188
&& GTK_WIDGET_MAPPED (widget))
190
if (socket->is_composited)
191
gdk_window_invalidate_rect (gdk_window_get_parent (widget->window),
192
&widget->allocation, FALSE);
193
else if (moved && socket->parent_relative_bg)
194
systray_socket_force_redraw (socket);
201
systray_socket_expose_event (GtkWidget *widget,
202
GdkEventExpose *event)
204
SystraySocket *socket = XFCE_SYSTRAY_SOCKET (widget);
207
if (socket->is_composited)
209
/* clear to transparent */
210
cr = gdk_cairo_create (widget->window);
211
cairo_set_source_rgba (cr, 0, 0, 0, 0);
212
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
213
gdk_cairo_region (cr, event->region);
217
else if (socket->parent_relative_bg)
219
/* clear to parent-relative pixmap */
220
gdk_window_clear_area (widget->window,
233
systray_socket_style_set (GtkWidget *widget,
234
GtkStyle *previous_style)
241
systray_socket_new (GdkScreen *screen,
242
GdkNativeWindow window)
244
SystraySocket *socket;
246
XWindowAttributes attr;
249
GdkColormap *colormap;
250
gboolean release_colormap = FALSE;
252
panel_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
254
/* get the window attributes */
255
display = gdk_screen_get_display (screen);
256
gdk_error_trap_push ();
257
result = XGetWindowAttributes (GDK_DISPLAY_XDISPLAY (display),
260
/* leave on an error or if the window does not exist */
261
if (gdk_error_trap_pop () != 0 || result == 0)
264
/* get the windows visual */
265
visual = gdk_x11_screen_lookup_visual (screen, attr.visual->visualid);
266
panel_return_val_if_fail (visual == NULL || GDK_IS_VISUAL (visual), NULL);
267
if (G_UNLIKELY (visual == NULL))
270
/* get the correct colormap */
271
if (visual == gdk_screen_get_rgb_visual (screen))
272
colormap = gdk_screen_get_rgb_colormap (screen);
273
else if (visual == gdk_screen_get_rgba_visual (screen))
274
colormap = gdk_screen_get_rgba_colormap (screen);
275
else if (visual == gdk_screen_get_system_visual (screen))
276
colormap = gdk_screen_get_system_colormap (screen);
279
/* create custom colormap */
280
colormap = gdk_colormap_new (visual, FALSE);
281
release_colormap = TRUE;
284
/* create a new socket */
285
socket = g_object_new (XFCE_TYPE_SYSTRAY_SOCKET, NULL);
286
socket->window = window;
287
socket->is_composited = FALSE;
288
gtk_widget_set_colormap (GTK_WIDGET (socket), colormap);
290
/* release the custom colormap */
291
if (release_colormap)
292
g_object_unref (G_OBJECT (colormap));
294
/* check if there is an alpha channel in the visual */
295
if (visual->red_prec + visual->blue_prec + visual->green_prec < visual->depth
296
&& gdk_display_supports_composite (gdk_screen_get_display (screen)))
297
socket->is_composited = TRUE;
299
return GTK_WIDGET (socket);
305
systray_socket_force_redraw (SystraySocket *socket)
307
GtkWidget *widget = GTK_WIDGET (socket);
311
panel_return_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket));
313
if (GTK_WIDGET_MAPPED (socket) && socket->parent_relative_bg)
315
display = gtk_widget_get_display (widget);
317
xev.xexpose.type = Expose;
318
xev.xexpose.window = GDK_WINDOW_XWINDOW (GTK_SOCKET (socket)->plug_window);
321
xev.xexpose.width = widget->allocation.width;
322
xev.xexpose.height = widget->allocation.height;
323
xev.xexpose.count = 0;
325
gdk_error_trap_push ();
326
XSendEvent (GDK_DISPLAY_XDISPLAY (display),
330
/* We have to sync to reliably catch errors from the XSendEvent(),
331
* since that is asynchronous.
333
XSync (GDK_DISPLAY_XDISPLAY (display), False);
334
gdk_error_trap_pop ();
341
systray_socket_is_composited (SystraySocket *socket)
343
panel_return_val_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket), FALSE);
345
return socket->is_composited;
351
systray_socket_get_name_prop (SystraySocket *socket,
352
const gchar *prop_name,
353
const gchar *type_name)
364
panel_return_val_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket), NULL);
365
panel_return_val_if_fail (type_name != NULL && prop_name != NULL, NULL);
367
display = gtk_widget_get_display (GTK_WIDGET (socket));
369
req_type = gdk_x11_get_xatom_by_name_for_display (display, type_name);
371
gdk_error_trap_push ();
373
result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
375
gdk_x11_get_xatom_by_name_for_display (display, prop_name),
378
&type, &format, &nitems,
382
/* check if everything went fine */
383
if (gdk_error_trap_pop () != 0
388
/* check the returned data */
392
&& g_utf8_validate (val, nitems, NULL))
394
/* lowercase the result */
395
name = g_utf8_strdown (val, nitems);
406
systray_socket_get_name (SystraySocket *socket)
408
panel_return_val_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket), NULL);
410
if (G_LIKELY (socket->name != NULL))
413
/* try _NET_WM_NAME first, for gtk icon implementations, fall back to
414
* WM_NAME for qt icons */
415
socket->name = systray_socket_get_name_prop (socket, "_NET_WM_NAME", "UTF8_STRING");
416
if (G_UNLIKELY (socket->name == NULL))
417
socket->name = systray_socket_get_name_prop (socket, "WM_NAME", "STRING");
425
systray_socket_get_window (SystraySocket *socket)
427
panel_return_val_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket), NULL);
429
return &socket->window;
435
systray_socket_get_hidden (SystraySocket *socket)
437
panel_return_val_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket), FALSE);
439
return socket->hidden;
445
systray_socket_set_hidden (SystraySocket *socket,
448
panel_return_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket));
450
socket->hidden = hidden;