gnome-panel r11363 - trunk/applets/notification_area
- From: vuntz svn gnome org
- To: svn-commits-list gnome org
- Subject: gnome-panel r11363 - trunk/applets/notification_area
- Date: Mon, 8 Dec 2008 14:59:09 +0000 (UTC)
Author: vuntz
Date: Mon Dec 8 14:59:08 2008
New Revision: 11363
URL: http://svn.gnome.org/viewvc/gnome-panel?rev=11363&view=rev
Log:
2008-12-08 Vincent Untz <vuntz gnome org>
Real tray icons transparency.
Patch by Owen Taylor <otaylor redhat com>
Fix bug #552953.
* Makefile.am:
* na-tray-child.[ch]: new files, to subclass GtkSocket, and have a
better life
* na-tray-manager.c: (na_tray_manager_plug_removed): trivial update
(na_tray_manager_make_socket_transparent): killed
(na_tray_manager_socket_exposed): killed
(na_tray_manager_socket_style_set): killed
(na_tray_manager_handle_dock_request): updated for NaTrayChild
(na_tray_manager_set_visual_property): set _NET_SYSTEM_TRAY_VISUAL
(na_tray_manager_manage_screen_x11): call
na_tray_manager_set_visual_property(), and some cleanups
(na_tray_manager_get_child_title): killed, replaced by a NaTrayChild
method
* na-tray-manager.h:
* na-tray.c: (tray_added), (tray_removed): don't force a redraw of the
icon. It shouldn't be needed anymore now, with NaTrayChild.
(na_tray_expose_icon): new, paint the icon if it's composited.
(na_tray_expose_box): updated to for na_tray_expose_icon()
(na_tray_init): connect to the expose event of the box
(idle_redraw_cb): updated to use na_tray_child_force_redraw()
(na_tray_force_redraw): remove a comment
* na-tray.h: remove NaTrayChild from there
* testtray.c: (tray_added_cb): update some code
Added:
trunk/applets/notification_area/na-tray-child.c
trunk/applets/notification_area/na-tray-child.h
Modified:
trunk/applets/notification_area/ChangeLog
trunk/applets/notification_area/Makefile.am
trunk/applets/notification_area/na-tray-manager.c
trunk/applets/notification_area/na-tray-manager.h
trunk/applets/notification_area/na-tray.c
trunk/applets/notification_area/na-tray.h
trunk/applets/notification_area/testtray.c
Modified: trunk/applets/notification_area/Makefile.am
==============================================================================
--- trunk/applets/notification_area/Makefile.am (original)
+++ trunk/applets/notification_area/Makefile.am Mon Dec 8 14:59:08 2008
@@ -22,6 +22,8 @@
obox.h \
na-tray.c \
na-tray.h \
+ na-tray-child.c \
+ na-tray-child.h \
na-tray-manager.c \
na-tray-manager.h \
na-marshal.c \
@@ -94,6 +96,8 @@
na-marshal.h \
na-tray.c \
na-tray.h \
+ na-tray-child.c \
+ na-tray-child.h \
na-tray-manager.c \
na-tray-manager.h \
obox.c \
Added: trunk/applets/notification_area/na-tray-child.c
==============================================================================
--- (empty file)
+++ trunk/applets/notification_area/na-tray-child.c Mon Dec 8 14:59:08 2008
@@ -0,0 +1,390 @@
+/* na-tray-child.c
+ * Copyright (C) 2002 Anders Carlsson <andersca gnu org>
+ * Copyright (C) 2003-2006 Vincent Untz
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "na-tray-child.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+
+G_DEFINE_TYPE (NaTrayChild, na_tray_child, GTK_TYPE_SOCKET)
+
+static void
+na_tray_child_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (na_tray_child_parent_class)->finalize (object);
+}
+
+static void
+na_tray_child_realize (GtkWidget *widget)
+{
+ NaTrayChild *child = NA_TRAY_CHILD (widget);
+ GdkVisual *visual = gtk_widget_get_visual (widget);
+ gboolean visual_has_alpha;
+
+ GTK_WIDGET_CLASS (na_tray_child_parent_class)->realize (widget);
+
+ /* We have alpha if the visual has something other than red, green,
+ * and blue */
+ visual_has_alpha = visual->red_prec + visual->blue_prec + visual->green_prec < visual->depth;
+
+ if (visual_has_alpha && gdk_display_supports_composite (gtk_widget_get_display (widget)))
+ {
+ /* We have real transparency with an ARGB visual and the Composite
+ * extension. */
+
+ /* Set a transparent background */
+ GdkColor transparent = { 0, 0, 0, 0 }; /* only pixel=0 matters */
+ gdk_window_set_background (widget->window, &transparent);
+ gdk_window_set_composited (widget->window, TRUE);
+
+ child->is_composited = TRUE;
+ child->parent_relative_bg = FALSE;
+ }
+ else if (visual == gdk_window_get_visual (gdk_window_get_parent (widget->window)))
+ {
+ /* Otherwise, if the visual matches the visual of the parent window, we
+ * can use a parent-relative background and fake transparency. */
+ gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
+
+ child->is_composited = FALSE;
+ child->parent_relative_bg = TRUE;
+ }
+ else
+ {
+ /* Nothing to do; the icon will sit on top of an ugly gray box */
+ child->is_composited = FALSE;
+ child->parent_relative_bg = FALSE;
+ }
+
+ gtk_widget_set_app_paintable (GTK_WIDGET (child),
+ child->parent_relative_bg || child->is_composited);
+
+ /* Double-buffering will interfere with the parent-relative-background fake
+ * transparency, since the double-buffer code doesn't know how to fill in the
+ * background of the double-buffer correctly.
+ */
+ gtk_widget_set_double_buffered (GTK_WIDGET (child),
+ child->parent_relative_bg);
+}
+
+static void
+na_tray_child_style_set (GtkWidget *widget,
+ GtkStyle *previous_style)
+{
+ /* The default handler resets the background according to the new style.
+ * We either use a transparent background or a parent-relative background
+ * and ignore the style background. So, just don't chain up.
+ */
+}
+
+#if 0
+/* This is adapted from code that was commented out in na-tray-manager.c; the
+ * code in na-tray-manager.c wouldn't have worked reliably, this will. So maybe
+ * it can be reenabled. On other hand, things seem to be working fine without
+ * it.
+ *
+ * If reenabling, you need to hook it up in na_tray_child_class_init().
+ */
+static void
+na_tray_child_size_request (GtkWidget *widget,
+ GtkRequisition *request)
+{
+ GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_request (widget, request);
+
+ /*
+ * Make sure the icons have a meaningful size ..
+ */
+ if ((request->width < 16) || (request->height < 16))
+ {
+ gint nw = MAX (24, request->width);
+ gint nh = MAX (24, request->height);
+ g_warning (_("tray icon has requested a size of (%i x %i), resizing to (%i x %i)"),
+ req.width, req.height, nw, nh);
+ request->width = nw;
+ request->height = nh;
+ }
+}
+#endif
+
+static void
+na_tray_child_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ NaTrayChild *child = NA_TRAY_CHILD (widget);
+
+ gboolean moved = allocation->x != widget->allocation.x ||
+ allocation->y != widget->allocation.y;
+ gboolean resized = allocation->width != widget->allocation.width ||
+ allocation->height != widget->allocation.height;
+
+ /* When we are allocating the widget while mapped we need special handling
+ * for both real and fake transparency.
+ *
+ * Real transparency: we need to invalidate and trigger a redraw of the old
+ * and new areas. (GDK really should handle this for us, but doesn't as of
+ * GTK+-2.14)
+ *
+ * Fake transparency: if the widget moved, we need to force the contents to
+ * be redrawn with the new offset for the parent-relative background.
+ */
+ if ((moved || resized) && GTK_WIDGET_MAPPED (widget))
+ {
+ if (na_tray_child_is_composited (child))
+ gdk_window_invalidate_rect (gdk_window_get_parent (widget->window),
+ &widget->allocation, FALSE);
+ }
+
+ GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_allocate (widget,
+ allocation);
+
+ if ((moved || resized) && GTK_WIDGET_MAPPED (widget))
+ {
+ if (na_tray_child_is_composited (NA_TRAY_CHILD (widget)))
+ gdk_window_invalidate_rect (gdk_window_get_parent (widget->window),
+ &widget->allocation, FALSE);
+ else if (moved && child->parent_relative_bg)
+ na_tray_child_force_redraw (child);
+ }
+}
+
+/* The plug window should completely occupy the area of the child, so we won't
+ * get an expose event. But in case we do (the plug unmaps itself, say), this
+ * expose handler draws with real or fake transparency.
+ */
+static gboolean
+na_tray_child_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ NaTrayChild *child = NA_TRAY_CHILD (widget);
+
+ if (na_tray_child_is_composited (child))
+ {
+ /* Clear to transparent */
+ cairo_t *cr = gdk_cairo_create (widget->window);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ gdk_cairo_region (cr, event->region);
+ cairo_fill (cr);
+ cairo_destroy (cr);
+ }
+ else if (child->parent_relative_bg)
+ {
+ /* Clear to parent-relative pixmap */
+ gdk_window_clear_area (widget->window,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ }
+
+ return FALSE;
+}
+
+static void
+na_tray_child_init (NaTrayChild *child)
+{
+}
+
+static void
+na_tray_child_class_init (NaTrayChildClass *klass)
+{
+ GObjectClass *gobject_class;
+ GtkWidgetClass *widget_class;
+
+ gobject_class = (GObjectClass *)klass;
+ widget_class = (GtkWidgetClass *)klass;
+
+ gobject_class->finalize = na_tray_child_finalize;
+ widget_class->style_set = na_tray_child_style_set;
+ widget_class->realize = na_tray_child_realize;
+ widget_class->size_allocate = na_tray_child_size_allocate;
+ widget_class->expose_event = na_tray_child_expose_event;
+}
+
+GtkWidget *
+na_tray_child_new (GdkScreen *screen,
+ Window icon_window)
+{
+ XWindowAttributes window_attributes;
+ Display *xdisplay;
+ NaTrayChild *child;
+ GdkVisual *visual;
+ GdkColormap *colormap;
+ gboolean new_colormap;
+ int result;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+ g_return_val_if_fail (icon_window != None, NULL);
+
+ xdisplay = GDK_SCREEN_XDISPLAY (screen);
+
+ /* We need to determine the visual of the window we are embedding and create
+ * the socket in the same visual.
+ */
+
+ gdk_error_trap_push ();
+ result = XGetWindowAttributes (xdisplay, icon_window,
+ &window_attributes);
+ gdk_error_trap_pop ();
+
+ if (!result) /* Window already gone */
+ return NULL;
+
+ visual = gdk_x11_screen_lookup_visual (screen,
+ window_attributes.visual->visualid);
+ if (!visual) /* Icon window is on another screen? */
+ return NULL;
+
+ new_colormap = FALSE;
+
+ if (visual == gdk_screen_get_rgb_visual (screen))
+ colormap = gdk_screen_get_rgb_colormap (screen);
+ else if (visual == gdk_screen_get_rgba_visual (screen))
+ colormap = gdk_screen_get_rgba_colormap (screen);
+ else if (visual == gdk_screen_get_system_visual (screen))
+ colormap = gdk_screen_get_system_colormap (screen);
+ else
+ {
+ colormap = gdk_colormap_new (visual, FALSE);
+ new_colormap = TRUE;
+ }
+
+ child = g_object_new (NA_TYPE_TRAY_CHILD, NULL);
+ child->icon_window = icon_window;
+
+ gtk_widget_set_colormap (GTK_WIDGET (child), colormap);
+
+ if (new_colormap)
+ g_object_unref (colormap);
+
+ return GTK_WIDGET (child);
+}
+
+char *
+na_tray_child_get_title (NaTrayChild *child)
+{
+ char *retval = NULL;
+ GdkDisplay *display;
+ Atom utf8_string, atom, type;
+ int result;
+ int format;
+ gulong nitems;
+ gulong bytes_after;
+ gchar *val;
+
+ g_return_val_if_fail (NA_IS_TRAY_CHILD (child), NULL);
+
+ display = gtk_widget_get_display (GTK_WIDGET (child));
+
+ utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME");
+
+ gdk_error_trap_push ();
+
+ result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+ child->icon_window,
+ atom,
+ 0, G_MAXLONG,
+ False, utf8_string,
+ &type, &format, &nitems,
+ &bytes_after, (guchar **)&val);
+
+ if (gdk_error_trap_pop () || result != Success)
+ return NULL;
+
+ if (type != utf8_string ||
+ format != 8 ||
+ nitems == 0)
+ {
+ if (val)
+ XFree (val);
+ return NULL;
+ }
+
+ if (!g_utf8_validate (val, nitems, NULL))
+ {
+ XFree (val);
+ return NULL;
+ }
+
+ retval = g_strndup (val, nitems);
+
+ XFree (val);
+
+ return retval;
+}
+
+gboolean
+na_tray_child_is_composited (NaTrayChild *child)
+{
+ g_return_val_if_fail (NA_IS_TRAY_CHILD (child), FALSE);
+
+ return child->is_composited;
+}
+
+/* If we are faking transparency with a window-relative background, force a
+ * redraw of the icon. This should be called if the background changes or if
+ * the child is shifted with respect to the background.
+ */
+void
+na_tray_child_force_redraw (NaTrayChild *child)
+{
+ GtkWidget *widget = GTK_WIDGET (child);
+
+ if (GTK_WIDGET_MAPPED (child) && child->parent_relative_bg)
+ {
+#if 1
+ /* Sending an ExposeEvent might cause redraw problems if the
+ * icon is expecting the server to clear-to-background before
+ * the redraw. It should be ok for GtkStatusIcon or EggTrayIcon.
+ */
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
+ XEvent xev;
+
+ xev.xexpose.type = Expose;
+ xev.xexpose.window = GDK_WINDOW_XWINDOW (GTK_SOCKET (child)->plug_window);
+ xev.xexpose.x = 0;
+ xev.xexpose.y = 0;
+ xev.xexpose.width = widget->allocation.width;
+ xev.xexpose.height = widget->allocation.height;
+ xev.xexpose.count = 0;
+
+ gdk_error_trap_push ();
+ XSendEvent (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)),
+ xev.xexpose.window,
+ False, ExposureMask,
+ &xev);
+ /* We have to sync to reliably catch errors from the XSendEvent(),
+ * since that is asynchronous.
+ */
+ XSync (xdisplay, False);
+ gdk_error_trap_pop ();
+#else
+ /* Hiding and showing is the safe way to do it, but can result in more
+ * flickering.
+ */
+ gdk_window_hide (widget->window);
+ gdk_window_show (widget->window);
+#endif
+ }
+}
Added: trunk/applets/notification_area/na-tray-child.h
==============================================================================
--- (empty file)
+++ trunk/applets/notification_area/na-tray-child.h Mon Dec 8 14:59:08 2008
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* na-tray-child.h
+ * Copyright (C) 2002 Anders Carlsson <andersca gnu org>
+ * Copyright (C) 2003-2006 Vincent Untz
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __NA_TRAY_CHILD_H__
+#define __NA_TRAY_CHILD_H__
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+G_BEGIN_DECLS
+
+#define NA_TYPE_TRAY_CHILD (na_tray_child_get_type ())
+#define NA_TRAY_CHILD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NA_TYPE_TRAY_CHILD, NaTrayChild))
+#define NA_TRAY_CHILD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NA_TYPE_TRAY_CHILD, NaTrayChildClass))
+#define NA_IS_TRAY_CHILD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NA_TYPE_TRAY_CHILD))
+#define NA_IS_TRAY_CHILD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NA_TYPE_TRAY_CHILD))
+#define NA_TRAY_CHILD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NA_TYPE_TRAY_CHILD, NaTrayChildClass))
+
+typedef struct _NaTrayChild NaTrayChild;
+typedef struct _NaTrayChildClass NaTrayChildClass;
+typedef struct _NaTrayChildChild NaTrayChildChild;
+
+struct _NaTrayChild
+{
+ GtkSocket parent_instance;
+ Window icon_window;
+ guint is_composited : 1;
+ guint parent_relative_bg : 1;
+};
+
+struct _NaTrayChildClass
+{
+ GtkSocketClass parent_class;
+};
+
+GType na_tray_child_get_type (void);
+
+GtkWidget *na_tray_child_new (GdkScreen *screen,
+ Window icon_window);
+char *na_tray_child_get_title (NaTrayChild *child);
+gboolean na_tray_child_is_composited (NaTrayChild *child);
+void na_tray_child_force_redraw (NaTrayChild *child);
+
+G_END_DECLS
+
+#endif /* __NA_TRAY_CHILD_H__ */
Modified: trunk/applets/notification_area/na-tray-manager.c
==============================================================================
--- trunk/applets/notification_area/na-tray-manager.c (original)
+++ trunk/applets/notification_area/na-tray-manager.c Mon Dec 8 14:59:08 2008
@@ -254,120 +254,61 @@
na_tray_manager_plug_removed (GtkSocket *socket,
NaTrayManager *manager)
{
- Window *window;
+ NaTrayChild *child = NA_TRAY_CHILD (socket);
- window = g_object_get_data (G_OBJECT (socket), "na-tray-child-window");
-
- g_hash_table_remove (manager->socket_table, GINT_TO_POINTER (*window));
- g_object_set_data (G_OBJECT (socket), "na-tray-child-window",
- NULL);
-
- g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, socket);
+ g_hash_table_remove (manager->socket_table,
+ GINT_TO_POINTER (child->icon_window));
+ g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child);
/* This destroys the socket. */
return FALSE;
}
static void
-na_tray_manager_make_socket_transparent (GtkWidget *widget,
- gpointer user_data)
+na_tray_manager_handle_dock_request (NaTrayManager *manager,
+ XClientMessageEvent *xevent)
{
- if (GTK_WIDGET_NO_WINDOW (widget))
- return;
+ Window icon_window = xevent->data.l[2];
+ GtkWidget *child;
- gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
-}
-
-static gboolean
-na_tray_manager_socket_exposed (GtkWidget *widget,
- GdkEventExpose *event,
- gpointer user_data)
-{
- gdk_window_clear_area (widget->window,
- event->area.x, event->area.y,
- event->area.width, event->area.height);
- return FALSE;
-}
+ if (g_hash_table_lookup (manager->socket_table,
+ GINT_TO_POINTER (icon_window)))
+ {
+ /* We already got this notification earlier, ignore this one */
+ return;
+ }
-static void
-na_tray_manager_socket_style_set (GtkWidget *widget,
- GtkStyle *previous_style,
- gpointer user_data)
-{
- if (widget->window == NULL)
+ child = na_tray_child_new (manager->screen, icon_window);
+ if (child == NULL) /* already gone or other error */
return;
- na_tray_manager_make_socket_transparent (widget, user_data);
-}
+ g_signal_emit (manager, manager_signals[TRAY_ICON_ADDED], 0,
+ child);
-static void
-na_tray_manager_handle_dock_request (NaTrayManager *manager,
- XClientMessageEvent *xevent)
-{
- GtkWidget *socket;
- Window *window;
- GtkRequisition req;
+ /* If the child wasn't attached, then destroy it */
- if (g_hash_table_lookup (manager->socket_table, GINT_TO_POINTER (xevent->data.l[2])))
+ if (!GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (child))))
{
- /* We already got this notification earlier, ignore this one */
+ gtk_widget_destroy (child);
return;
}
-
- socket = gtk_socket_new ();
- gtk_widget_set_app_paintable (socket, TRUE);
- //FIXME: need to find a theme where this (and expose event) is needed
- gtk_widget_set_double_buffered (socket, FALSE);
- g_signal_connect (socket, "realize",
- G_CALLBACK (na_tray_manager_make_socket_transparent), NULL);
- g_signal_connect (socket, "expose_event",
- G_CALLBACK (na_tray_manager_socket_exposed), NULL);
- g_signal_connect_after (socket, "style_set",
- G_CALLBACK (na_tray_manager_socket_style_set), NULL);
-
- /* We need to set the child window here
- * so that the client can call _get functions
- * in the signal handler
- */
- window = g_new (Window, 1);
- *window = xevent->data.l[2];
-
- g_object_set_data_full (G_OBJECT (socket),
- "na-tray-child-window",
- window, g_free);
- g_signal_emit (manager, manager_signals[TRAY_ICON_ADDED], 0,
- socket);
+ g_signal_connect (child, "plug_removed",
+ G_CALLBACK (na_tray_manager_plug_removed), manager);
+
+ gtk_socket_add_id (GTK_SOCKET (child), icon_window);
- /* Add the socket only if it's been attached */
- if (GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket))))
+ if (!GTK_SOCKET (child)->plug_window)
{
- g_signal_connect (socket, "plug_removed",
- G_CALLBACK (na_tray_manager_plug_removed), manager);
-
- gtk_socket_add_id (GTK_SOCKET (socket), *window);
-
- g_hash_table_insert (manager->socket_table, GINT_TO_POINTER (*window), socket);
-
- /*
- * Make sure the icons have a meaningfull size ...
- */
- req.width = req.height = 1;
- gtk_widget_size_request (socket, &req);
- /*
- if ((req.width < 16) || (req.height < 16))
- {
- gint nw = MAX (24, req.width);
- gint nh = MAX (24, req.height);
- g_warning (_("tray icon has requested a size of (%i x %i), resizing to (%i x %i)"),
- req.width, req.height, nw, nh);
- gtk_widget_set_size_request(icon, nw, nh);
- }
- */
- gtk_widget_show(socket);
+ /* Embedding failed, we won't get a plug-removed signal */
+ g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child);
+ gtk_widget_destroy (child);
+ return;
}
- else
- gtk_widget_destroy (socket);
+
+ g_hash_table_insert (manager->socket_table,
+ GINT_TO_POINTER (icon_window), child);
+ gtk_widget_show (child);
}
static void
@@ -662,6 +603,58 @@
#endif
}
+static void
+na_tray_manager_set_visual_property (NaTrayManager *manager)
+{
+#ifdef GDK_WINDOWING_X11
+ GdkDisplay *display;
+ Visual *xvisual;
+ Atom visual_atom;
+ gulong data[1];
+
+ if (!manager->invisible || !manager->invisible->window)
+ return;
+
+ /* The visual property is a hint to the tray icons as to what visual they
+ * should use for their windows. If the X server has RGBA colormaps, then
+ * we tell the tray icons to use a RGBA colormap and we'll composite the
+ * icon onto its parents with real transparency. Otherwise, we just tell
+ * the icon to use our colormap, and we'll do some hacks with parent
+ * relative backgrounds to simulate transparency.
+ */
+
+ display = gtk_widget_get_display (manager->invisible);
+ visual_atom = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_SYSTEM_TRAY_VISUAL");
+
+ if (gdk_screen_get_rgba_visual (manager->screen) != NULL &&
+ gdk_display_supports_composite (display))
+ {
+ xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_rgba_visual (manager->screen));
+ }
+ else
+ {
+ /* We actually want the visual of the tray where the icons will
+ * be embedded. In almost all cases, this will be the same as the visual
+ * of the screen.
+ */
+ GdkColormap *colormap;
+
+ colormap = gdk_screen_get_default_colormap (manager->screen);
+ xvisual = GDK_VISUAL_XVISUAL (gdk_colormap_get_visual (colormap));
+ }
+
+ data[0] = XVisualIDFromVisual (xvisual);
+
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_WINDOW_XWINDOW (manager->invisible->window),
+ visual_atom,
+ XA_VISUALID, 32,
+ PropModeReplace,
+ (guchar *) &data, 1);
+#endif
+}
+
#ifdef GDK_WINDOWING_X11
static gboolean
@@ -684,6 +677,9 @@
if (na_tray_manager_check_running_screen_x11 (screen))
return FALSE;
#endif
+
+ manager->screen = screen;
+
display = gdk_screen_get_display (screen);
xscreen = GDK_SCREEN_XSCREEN (screen);
@@ -698,7 +694,11 @@
manager->selection_atom = gdk_atom_intern (selection_atom_name, FALSE);
g_free (selection_atom_name);
+ manager->invisible = invisible;
+ g_object_ref (G_OBJECT (manager->invisible));
+
na_tray_manager_set_orientation_property (manager);
+ na_tray_manager_set_visual_property (manager);
timestamp = gdk_x11_get_server_time (invisible->window);
@@ -730,9 +730,6 @@
RootWindowOfScreen (xscreen),
False, StructureNotifyMask, (XEvent *)&xev);
- manager->invisible = invisible;
- g_object_ref (G_OBJECT (manager->invisible));
-
opcode_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_OPCODE", FALSE);
manager->opcode_atom = gdk_x11_atom_to_xatom_for_display (display,
opcode_atom);
@@ -763,6 +760,10 @@
else
{
gtk_widget_destroy (invisible);
+ g_object_unref (invisible);
+ manager->invisible = NULL;
+
+ manager->screen = NULL;
return FALSE;
}
@@ -821,67 +822,6 @@
#endif
}
-char *
-na_tray_manager_get_child_title (NaTrayManager *manager,
- NaTrayManagerChild *child)
-{
- char *retval = NULL;
-#ifdef GDK_WINDOWING_X11
- GdkDisplay *display;
- Window *child_window;
- Atom utf8_string, atom, type;
- int result;
- int format;
- gulong nitems;
- gulong bytes_after;
- gchar *val;
-
- g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), NULL);
- g_return_val_if_fail (GTK_IS_SOCKET (child), NULL);
-
- display = gdk_screen_get_display (manager->screen);
-
- child_window = g_object_get_data (G_OBJECT (child),
- "na-tray-child-window");
-
- utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME");
-
- gdk_error_trap_push ();
-
- result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
- *child_window,
- atom,
- 0, G_MAXLONG,
- False, utf8_string,
- &type, &format, &nitems,
- &bytes_after, (guchar **)&val);
-
- if (gdk_error_trap_pop () || result != Success)
- return NULL;
-
- if (type != utf8_string ||
- format != 8 ||
- nitems == 0)
- {
- if (val)
- XFree (val);
- return NULL;
- }
-
- if (!g_utf8_validate (val, nitems, NULL))
- {
- XFree (val);
- return NULL;
- }
-
- retval = g_strndup (val, nitems);
-
- XFree (val);
-#endif
- return retval;
-}
-
void
na_tray_manager_set_orientation (NaTrayManager *manager,
GtkOrientation orientation)
Modified: trunk/applets/notification_area/na-tray-manager.h
==============================================================================
--- trunk/applets/notification_area/na-tray-manager.h (original)
+++ trunk/applets/notification_area/na-tray-manager.h Mon Dec 8 14:59:08 2008
@@ -29,6 +29,8 @@
#include <gdk/gdkx.h>
#endif
+#include "na-tray-child.h"
+
G_BEGIN_DECLS
#define NA_TYPE_TRAY_MANAGER (na_tray_manager_get_type ())
@@ -40,7 +42,6 @@
typedef struct _NaTrayManager NaTrayManager;
typedef struct _NaTrayManagerClass NaTrayManagerClass;
-typedef struct _NaTrayManagerChild NaTrayManagerChild;
struct _NaTrayManager
{
@@ -64,18 +65,18 @@
GObjectClass parent_class;
void (* tray_icon_added) (NaTrayManager *manager,
- NaTrayManagerChild *child);
+ NaTrayChild *child);
void (* tray_icon_removed) (NaTrayManager *manager,
- NaTrayManagerChild *child);
+ NaTrayChild *child);
void (* message_sent) (NaTrayManager *manager,
- NaTrayManagerChild *child,
+ NaTrayChild *child,
const gchar *message,
glong id,
glong timeout);
void (* message_cancelled) (NaTrayManager *manager,
- NaTrayManagerChild *child,
+ NaTrayChild *child,
glong id);
void (* lost_selection) (NaTrayManager *manager);
@@ -87,8 +88,6 @@
NaTrayManager *na_tray_manager_new (void);
gboolean na_tray_manager_manage_screen (NaTrayManager *manager,
GdkScreen *screen);
-char *na_tray_manager_get_child_title (NaTrayManager *manager,
- NaTrayManagerChild *child);
void na_tray_manager_set_orientation (NaTrayManager *manager,
GtkOrientation orientation);
GtkOrientation na_tray_manager_get_orientation (NaTrayManager *manager);
Modified: trunk/applets/notification_area/na-tray.c
==============================================================================
--- trunk/applets/notification_area/na-tray.c (original)
+++ trunk/applets/notification_area/na-tray.c Mon Dec 8 14:59:08 2008
@@ -120,7 +120,6 @@
gtk_box_pack_end (GTK_BOX (priv->box), icon, FALSE, FALSE, 0);
gtk_widget_show (icon);
- na_tray_force_redraw (tray);
}
static void
@@ -136,8 +135,6 @@
g_assert (tray->priv->trays_screen == trays_screen);
- na_tray_force_redraw (tray);
-
g_hash_table_remove (trays_screen->icon_table, icon);
/* this will also destroy the tip associated to this icon */
g_hash_table_remove (trays_screen->tip_table, icon);
@@ -404,8 +401,38 @@
gtk_widget_set_size_request (priv->box, -1, MIN_BOX_SIZE);
break;
}
+}
+
+/* Children with alpha channels have been set to be composited by calling
+ * gdk_window_set_composited(). We need to paint these children ourselves.
+ */
+static void
+na_tray_expose_icon (GtkWidget *widget,
+ gpointer data)
+{
+ cairo_t *cr = data;
+
+ if (na_tray_child_is_composited (NA_TRAY_CHILD (widget)))
+ {
+ gdk_cairo_set_source_pixmap (cr, widget->window,
+ widget->allocation.x,
+ widget->allocation.y);
+ cairo_paint (cr);
+ }
+}
+
+static void
+na_tray_expose_box (GtkWidget *box,
+ GdkEventExpose *event)
+{
+ cairo_t *cr = gdk_cairo_create (box->window);
- na_tray_force_redraw (tray);
+ gdk_cairo_region (cr, event->region);
+ cairo_clip (cr);
+
+ gtk_container_foreach (GTK_CONTAINER (box), na_tray_expose_icon, cr);
+
+ cairo_destroy (cr);
}
static void
@@ -423,6 +450,8 @@
gtk_widget_show (priv->frame);
priv->box = na_obox_new ();
+ g_signal_connect (priv->box, "expose-event",
+ G_CALLBACK (na_tray_expose_box), tray);
gtk_box_set_spacing (GTK_BOX (priv->box), ICON_SPACING);
gtk_container_add (GTK_CONTAINER (priv->frame), priv->box);
gtk_widget_show (priv->box);
@@ -663,9 +692,9 @@
{
NaTrayPrivate *priv = tray->priv;
+ gtk_container_foreach (GTK_CONTAINER (priv->box), (GtkCallback)na_tray_child_force_redraw, tray);
+
priv->idle_redraw_id = 0;
- gtk_widget_hide (priv->box);
- gtk_widget_show (priv->box);
return FALSE;
}
@@ -676,8 +705,6 @@
NaTrayPrivate *priv = tray->priv;
/* Force the icons to redraw their backgrounds.
- * gtk_widget_queue_draw() doesn't work across process boundaries,
- * so we do this instead.
*/
if (priv->idle_redraw_id == 0)
priv->idle_redraw_id = g_idle_add ((GSourceFunc) idle_redraw_cb, tray);
Modified: trunk/applets/notification_area/na-tray.h
==============================================================================
--- trunk/applets/notification_area/na-tray.h (original)
+++ trunk/applets/notification_area/na-tray.h Mon Dec 8 14:59:08 2008
@@ -41,7 +41,6 @@
typedef struct _NaTray NaTray;
typedef struct _NaTrayPrivate NaTrayPrivate;
typedef struct _NaTrayClass NaTrayClass;
-typedef struct _NaTrayChild NaTrayChild;
struct _NaTray
{
Modified: trunk/applets/notification_area/testtray.c
==============================================================================
--- trunk/applets/notification_area/testtray.c (original)
+++ trunk/applets/notification_area/testtray.c Mon Dec 8 14:59:08 2008
@@ -66,7 +66,7 @@
tray_added_cb (GtkContainer *box, GtkWidget *icon, TrayData *data)
{
g_print ("[Screen %u tray %p] Child %p added to tray: \"%s\"\n",
- data->screen_num, data->tray, icon, "XXX");//na_tray_manager_get_child_title (manager, icon));
+ data->screen_num, data->tray, icon, "XXX");//na_tray_child_get_title (icon));
update_child_count (data);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]