/* 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); GdkWindow *window = gtk_widget_get_window (widget); if (na_tray_child_has_alpha (child)) { /* Clear to transparent */ cairo_t *cr = gdk_cairo_create (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 (window, event->area.x, event->area.y, event->area.width, event->area.height); } return FALSE; }
static void cinnamon_tray_manager_child_on_realize (GtkWidget *widget, CinnamonTrayManagerChild *child) { /* If the tray child is using an RGBA colormap (and so we have real * transparency), we don't need to worry about the background. If * not, we obey the bg-color property by creating a cairo pattern of * that color and setting it as our background. Then "parent-relative" * background on the socket and the plug within that will cause * the icons contents to appear on top of our background color. */ if (!na_tray_child_has_alpha (NA_TRAY_CHILD (child->socket))) { ClutterColor color = child->manager->priv->bg_color; cairo_pattern_t *bg_pattern; bg_pattern = cairo_pattern_create_rgb (color.red / 255., color.green / 255., color.blue / 255.); gdk_window_set_background_pattern (gtk_widget_get_window (widget), bg_pattern); cairo_pattern_destroy (bg_pattern); } }
na_tray_child_expose_event (GtkWidget *widget, GdkEventExpose *event) #endif { NaTrayChild *child = NA_TRAY_CHILD (widget); GdkWindow *window = gtk_widget_get_window (widget); if (na_tray_child_has_alpha (child)) { /* Clear to transparent */ #if !GTK_CHECK_VERSION (3, 0, 0) cairo_t *cr = gdk_cairo_create (window); #endif cairo_set_source_rgba (cr, 0, 0, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); #if GTK_CHECK_VERSION (3, 0, 0) cairo_paint (cr); #else gdk_cairo_region (cr, event->region); cairo_fill (cr); cairo_destroy (cr); #endif } else if (child->parent_relative_bg) { /* Clear to parent-relative pixmap */ #if GTK_CHECK_VERSION (3, 0, 0) GdkWindow *window; cairo_surface_t *target; GdkRectangle clip_rect; window = gtk_widget_get_window (widget); target = cairo_get_group_target (cr); gdk_cairo_get_clip_rectangle (cr, &clip_rect); /* Clear to parent-relative pixmap * We need to use direct X access here because GDK doesn't know about * the parent relative pixmap. */ cairo_surface_flush (target); XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height, False); cairo_surface_mark_dirty_rectangle (target, clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height); #else gdk_window_clear_area (window, event->area.x, event->area.y, event->area.width, event->area.height); #endif } return FALSE; }
static void na_tray_child_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { NaTrayChild *child = NA_TRAY_CHILD (widget); GtkAllocation widget_allocation; gboolean moved, resized; gtk_widget_get_allocation (widget, &widget_allocation); moved = (allocation->x != widget_allocation.x || allocation->y != widget_allocation.y); 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_get_mapped (widget)) { if (na_tray_child_has_alpha (child)) gdk_window_invalidate_rect (gdk_window_get_parent (gtk_widget_get_window (widget)), &widget_allocation, FALSE); } GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_allocate (widget, allocation); if ((moved || resized) && gtk_widget_get_mapped (widget)) { if (na_tray_child_has_alpha (NA_TRAY_CHILD (widget))) gdk_window_invalidate_rect (gdk_window_get_parent (gtk_widget_get_window (widget)), &widget_allocation, FALSE); else if (moved && child->parent_relative_bg) na_tray_child_force_redraw (child); } }
static void na_tray_child_realize (GtkWidget *widget) { NaTrayChild *child = NA_TRAY_CHILD (widget); GdkVisual *visual = gtk_widget_get_visual (widget); GdkWindow *window; GTK_WIDGET_CLASS (na_tray_child_parent_class)->realize (widget); window = gtk_widget_get_window (widget); if (child->has_alpha) { /* 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 (window, &transparent); gdk_window_set_composited (window, TRUE); child->parent_relative_bg = FALSE; } #if GTK_CHECK_VERSION(3, 0, 0) else if (visual == gdk_window_get_visual(gdk_window_get_parent(window))) #else else if (visual == gdk_drawable_get_visual(GDK_DRAWABLE(gdk_window_get_parent(window)))) #endif { /* 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 (window, NULL, TRUE); child->parent_relative_bg = TRUE; } else { /* Nothing to do; the icon will sit on top of an ugly gray box */ child->parent_relative_bg = FALSE; } gdk_window_set_composited (window, child->composited); gtk_widget_set_app_paintable (GTK_WIDGET (child), child->parent_relative_bg || child->has_alpha); /* 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 gboolean na_tray_manager_plug_removed (GtkSocket *socket, NaTrayManager *manager) { NaTrayChild *child = NA_TRAY_CHILD (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_child_realize (GtkWidget *widget) { NaTrayChild *child = NA_TRAY_CHILD (widget); GdkVisual *visual = gtk_widget_get_visual (widget); GdkWindow *window; GTK_WIDGET_CLASS (na_tray_child_parent_class)->realize (widget); window = gtk_widget_get_window (widget); if (child->has_alpha) { /* We have real transparency with an ARGB visual and the Composite * extension. */ /* Set a transparent background */ cairo_pattern_t *transparent = cairo_pattern_create_rgba (0, 0, 0, 0); gdk_window_set_background_pattern (window, transparent); gdk_window_set_composited (window, TRUE); cairo_pattern_destroy (transparent); child->parent_relative_bg = FALSE; } else if (visual == gdk_window_get_visual (gdk_window_get_parent (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_background_pattern (window, NULL); child->parent_relative_bg = TRUE; } else { /* Nothing to do; the icon will sit on top of an ugly gray box */ child->parent_relative_bg = FALSE; } gdk_window_set_composited (window, child->composited); gtk_widget_set_app_paintable (GTK_WIDGET (child), child->parent_relative_bg || child->has_alpha); /* 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 cinnamon_tray_icon_constructed (GObject *object) { GdkWindow *icon_app_window; CinnamonTrayIcon *icon = CINNAMON_TRAY_ICON (object); CinnamonEmbeddedWindow *window; GdkDisplay *display; Window plug_xid; Atom _NET_WM_PID, type; int result, format; gulong nitems, bytes_after, *val = NULL; /* We do all this now rather than computing it on the fly later, * because Cinnamon may want to see their values from a * tray-icon-removed signal handler, at which point the plug has * already been removed from the socket. */ g_object_get (object, "window", &window, NULL); g_return_if_fail (window != NULL); icon->priv->socket = NA_TRAY_CHILD (gtk_bin_get_child (GTK_BIN (window))); g_object_unref (window); icon->priv->title = na_tray_child_get_title (icon->priv->socket); na_tray_child_get_wm_class (icon->priv->socket, NULL, &icon->priv->wm_class); icon_app_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket)); if (icon_app_window == NULL) { g_warning ("cinnamon tray: icon app window is gone"); return; } plug_xid = GDK_WINDOW_XID (icon_app_window); display = gtk_widget_get_display (GTK_WIDGET (icon->priv->socket)); gdk_error_trap_push (); _NET_WM_PID = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"); result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), plug_xid, _NET_WM_PID, 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems, &bytes_after, (guchar **)&val); if (!gdk_error_trap_pop () && result == Success && type == XA_CARDINAL && nitems == 1) icon->priv->pid = *val; if (val) XFree (val); }
/* The plug window should completely occupy the area of the child, so we won't * get a draw event. But in case we do (the plug unmaps itself, say), this * draw handler draws with real or fake transparency. */ static gboolean na_tray_child_draw (GtkWidget *widget, cairo_t *cr) { NaTrayChild *child = NA_TRAY_CHILD (widget); if (na_tray_child_has_alpha (child)) { /* Clear to transparent */ cairo_set_source_rgba (cr, 0, 0, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); } else if (child->parent_relative_bg) { GdkWindow *window; cairo_surface_t *target; GdkRectangle clip_rect; window = gtk_widget_get_window (widget); target = cairo_get_group_target (cr); gdk_cairo_get_clip_rectangle (cr, &clip_rect); /* Clear to parent-relative pixmap * We need to use direct X access here because GDK doesn't know about * the parent relative pixmap. */ cairo_surface_flush (target); XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height, False); cairo_surface_mark_dirty_rectangle (target, clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height); } return FALSE; }
static void na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket, gpointer user_data) { CinnamonTrayManager *manager = user_data; GtkWidget *win; CinnamonTrayManagerChild *child; /* We don't need the NaTrayIcon to be composited on the window we * put it in: the window is the same size as the tray icon * and transparent. We can just use the default X handling of * subwindows as mode of SOURCE (replace the parent with the * child) and then composite the parent onto the stage. */ na_tray_child_set_composited (NA_TRAY_CHILD (socket), FALSE); win = cinnamon_embedded_window_new (manager->priv->stage); gtk_container_add (GTK_CONTAINER (win), socket); /* The visual of the socket matches that of its contents; make * the window we put it in match that as well */ gtk_widget_set_visual (win, gtk_widget_get_visual (socket)); child = g_slice_new0 (CinnamonTrayManagerChild); child->manager = manager; child->window = win; child->socket = socket; g_signal_connect (win, "realize", G_CALLBACK (cinnamon_tray_manager_child_on_realize), child); gtk_widget_show_all (win); g_hash_table_insert (manager->priv->icons, socket, child); g_signal_connect (socket, "plug-added", G_CALLBACK (on_plug_added), manager); }