diff --git a/src/meson.build b/src/meson.build index de88a45d9..b06b043a0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -98,9 +98,7 @@ libshell_public_headers = [ 'shell-app-system.h', 'shell-app-usage.h', 'shell-blur-effect.h', - 'shell-embedded-window.h', 'shell-glsl-effect.h', - 'shell-gtk-embed.h', 'shell-global.h', 'shell-invert-lightness-effect.h', 'shell-action-modes.h', @@ -128,6 +126,7 @@ libshell_private_headers = [ 'shell-app-cache-private.h', 'shell-app-system-private.h', 'shell-global-private.h', + 'shell-tray-icon-private.h', 'shell-window-tracker-private.h', 'shell-wm-private.h' ] @@ -138,11 +137,8 @@ libshell_sources = [ 'shell-app-system.c', 'shell-app-usage.c', 'shell-blur-effect.c', - 'shell-embedded-window.c', - 'shell-embedded-window-private.h', 'shell-global.c', 'shell-glsl-effect.c', - 'shell-gtk-embed.c', 'shell-invert-lightness-effect.c', 'shell-keyring-prompt.c', 'shell-keyring-prompt.h', diff --git a/src/shell-embedded-window-private.h b/src/shell-embedded-window-private.h deleted file mode 100644 index 5714af99b..000000000 --- a/src/shell-embedded-window-private.h +++ /dev/null @@ -1,20 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -#ifndef __SHELL_EMBEDDED_WINDOW_PRIVATE_H__ -#define __SHELL_EMBEDDED_WINDOW_PRIVATE_H__ - -#include "shell-embedded-window.h" -#include "shell-gtk-embed.h" - -void _shell_embedded_window_set_actor (ShellEmbeddedWindow *window, - ShellGtkEmbed *embed); - -void _shell_embedded_window_allocate (ShellEmbeddedWindow *window, - int x, - int y, - int width, - int height); - -void _shell_embedded_window_map (ShellEmbeddedWindow *window); -void _shell_embedded_window_unmap (ShellEmbeddedWindow *window); - -#endif /* __SHELL_EMBEDDED_WINDOW_PRIVATE_H__ */ diff --git a/src/shell-embedded-window.c b/src/shell-embedded-window.c deleted file mode 100644 index 8fd611287..000000000 --- a/src/shell-embedded-window.c +++ /dev/null @@ -1,247 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#include "config.h" - -#include - -#include "shell-embedded-window-private.h" - -/* This type is a subclass of GtkWindow that ties the window to a - * ShellGtkEmbed; the resizing logic is bound to the clutter logic. - * - * The typical usage we might expect is - * - * - ShellEmbeddedWindow is created and filled with content - * - ShellEmbeddedWindow is shown with gtk_widget_show_all() - * - ShellGtkEmbed is created for the ShellEmbeddedWindow - * - actor is added to a stage - * - * The way it works is that the GtkWindow is mapped if and only if both: - * - * - gtk_widget_visible (window) [widget has been shown] - * - Actor is mapped [actor and all parents visible, actor in stage] - */ - -enum { - PROP_0 -}; - -typedef struct _ShellEmbeddedWindowPrivate ShellEmbeddedWindowPrivate; - -struct _ShellEmbeddedWindowPrivate { - ShellGtkEmbed *actor; - - GdkRectangle position; -}; - -G_DEFINE_TYPE_WITH_PRIVATE (ShellEmbeddedWindow, - shell_embedded_window, - GTK_TYPE_WINDOW); - -/* - * The normal gtk_window_show() starts all of the complicated asynchronous - * window resizing code running; we don't want or need any of that. - * Bypassing the normal code does mean that the extra geometry management - * available on GtkWindow: gridding, maximum sizes, etc, is ignored; we - * don't really want that anyways - we just want a way of embedding a - * GtkWidget into a Clutter stage. - */ -static void -shell_embedded_window_show (GtkWidget *widget) -{ - ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget); - ShellEmbeddedWindowPrivate *priv; - GtkWidgetClass *widget_class; - - priv = shell_embedded_window_get_instance_private (window); - - /* Skip GtkWindow, but run the default GtkWidget handling which - * marks the widget visible */ - widget_class = g_type_class_peek (GTK_TYPE_WIDGET); - widget_class->show (widget); - - if (priv->actor) - { - /* Size is 0x0 if the GtkWindow is not shown */ - clutter_actor_queue_relayout (CLUTTER_ACTOR (priv->actor)); - - if (clutter_actor_is_realized (CLUTTER_ACTOR (priv->actor))) - gtk_widget_map (widget); - } -} - -static void -shell_embedded_window_hide (GtkWidget *widget) -{ - ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget); - ShellEmbeddedWindowPrivate *priv; - - priv = shell_embedded_window_get_instance_private (window); - - if (priv->actor) - clutter_actor_queue_relayout (CLUTTER_ACTOR (priv->actor)); - - GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->hide (widget); -} - -static gboolean -shell_embedded_window_configure_event (GtkWidget *widget, - GdkEventConfigure *event) -{ - /* Normally a configure event coming back from X triggers the - * resizing logic inside GtkWindow; we just ignore them - * since we are handling the resizing logic separately. - */ - return FALSE; -} - -static void -shell_embedded_window_check_resize (GtkContainer *container) -{ - ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (container); - ShellEmbeddedWindowPrivate *priv; - - priv = shell_embedded_window_get_instance_private (window); - - /* Check resize is called when a resize is queued on something - * inside the GtkWindow; we need to make sure that in response - * to this gtk_widget_size_request() and then - * gtk_widget_size_allocate() are called; we defer to the Clutter - * logic and assume it will do the right thing. - */ - if (priv->actor) - clutter_actor_queue_relayout (CLUTTER_ACTOR (priv->actor)); -} - -static GObject * -shell_embedded_window_constructor (GType gtype, - guint n_properties, - GObjectConstructParam *properties) -{ - GObject *object; - GObjectClass *parent_class; - - parent_class = G_OBJECT_CLASS (shell_embedded_window_parent_class); - object = parent_class->constructor (gtype, n_properties, properties); - - /* Setting the resize mode to immediate means that calling queue_resize() - * on a widget within the window will immediately call check_resize() - * to be called, instead of having it queued to an idle. From our perspective, - * this is ideal since we just are going to queue a resize to Clutter's - * idle resize anyways. - */ - g_object_set (object, - "app-paintable", TRUE, - "resize-mode", GTK_RESIZE_IMMEDIATE, - "type", GTK_WINDOW_POPUP, - NULL); - - return object; -} - -static void -shell_embedded_window_class_init (ShellEmbeddedWindowClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); - - object_class->constructor = shell_embedded_window_constructor; - - widget_class->show = shell_embedded_window_show; - widget_class->hide = shell_embedded_window_hide; - widget_class->configure_event = shell_embedded_window_configure_event; - - container_class->check_resize = shell_embedded_window_check_resize; -} - -static void -shell_embedded_window_init (ShellEmbeddedWindow *window) -{ -} - -/* - * Private routines called by ShellGtkEmbed - */ - -void -_shell_embedded_window_set_actor (ShellEmbeddedWindow *window, - ShellGtkEmbed *actor) - -{ - ShellEmbeddedWindowPrivate *priv; - - g_return_if_fail (SHELL_IS_EMBEDDED_WINDOW (window)); - - priv = shell_embedded_window_get_instance_private (window); - priv->actor = actor; - - if (actor && - clutter_actor_is_mapped (CLUTTER_ACTOR (actor)) && - gtk_widget_get_visible (GTK_WIDGET (window))) - gtk_widget_map (GTK_WIDGET (window)); -} - -void -_shell_embedded_window_allocate (ShellEmbeddedWindow *window, - int x, - int y, - int width, - int height) -{ - ShellEmbeddedWindowPrivate *priv; - GtkAllocation allocation; - - g_return_if_fail (SHELL_IS_EMBEDDED_WINDOW (window)); - - priv = shell_embedded_window_get_instance_private (window); - - if (priv->position.x == x && - priv->position.y == y && - priv->position.width == width && - priv->position.height == height) - return; - - priv->position.x = x; - priv->position.y = y; - priv->position.width = width; - priv->position.height = height; - - if (gtk_widget_get_realized (GTK_WIDGET (window))) - gdk_window_move_resize (gtk_widget_get_window (GTK_WIDGET (window)), - x, y, width, height); - - allocation.x = 0; - allocation.y = 0; - allocation.width = width; - allocation.height = height; - - gtk_widget_size_allocate (GTK_WIDGET (window), &allocation); -} - -void -_shell_embedded_window_map (ShellEmbeddedWindow *window) -{ - g_return_if_fail (SHELL_IS_EMBEDDED_WINDOW (window)); - - if (gtk_widget_get_visible (GTK_WIDGET (window))) - gtk_widget_map (GTK_WIDGET (window)); -} - -void -_shell_embedded_window_unmap (ShellEmbeddedWindow *window) -{ - g_return_if_fail (SHELL_IS_EMBEDDED_WINDOW (window)); - - gtk_widget_unmap (GTK_WIDGET (window)); -} - -/* - * Public API - */ -GtkWidget * -shell_embedded_window_new (void) -{ - return g_object_new (SHELL_TYPE_EMBEDDED_WINDOW, - NULL); -} diff --git a/src/shell-embedded-window.h b/src/shell-embedded-window.h deleted file mode 100644 index 835165ba9..000000000 --- a/src/shell-embedded-window.h +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -#ifndef __SHELL_EMBEDDED_WINDOW_H__ -#define __SHELL_EMBEDDED_WINDOW_H__ - -#include -#include - -#define SHELL_TYPE_EMBEDDED_WINDOW (shell_embedded_window_get_type ()) -G_DECLARE_DERIVABLE_TYPE (ShellEmbeddedWindow, shell_embedded_window, - SHELL, EMBEDDED_WINDOW, GtkWindow) - -struct _ShellEmbeddedWindowClass -{ - GtkWindowClass parent_class; -}; - -GtkWidget *shell_embedded_window_new (void); - -#endif /* __SHELL_EMBEDDED_WINDOW_H__ */ diff --git a/src/shell-gtk-embed.c b/src/shell-gtk-embed.c deleted file mode 100644 index 2ad18a185..000000000 --- a/src/shell-gtk-embed.c +++ /dev/null @@ -1,364 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#include "config.h" - -#include "shell-embedded-window-private.h" -#include "shell-global.h" -#include "shell-util.h" - -#include -#include -#include - -enum { - PROP_0, - - PROP_WINDOW -}; - -typedef struct _ShellGtkEmbedPrivate ShellGtkEmbedPrivate; - -struct _ShellGtkEmbedPrivate -{ - ShellEmbeddedWindow *window; - - ClutterActor *window_actor; - gulong window_actor_destroyed_handler; - - gulong window_created_handler; -}; - -G_DEFINE_TYPE_WITH_PRIVATE (ShellGtkEmbed, shell_gtk_embed, CLUTTER_TYPE_CLONE); - -static void shell_gtk_embed_set_window (ShellGtkEmbed *embed, - ShellEmbeddedWindow *window); - -static void -shell_gtk_embed_on_window_destroy (GtkWidget *object, - ShellGtkEmbed *embed) -{ - shell_gtk_embed_set_window (embed, NULL); -} - -static void -shell_gtk_embed_remove_window_actor (ShellGtkEmbed *embed) -{ - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - - if (priv->window_actor) - { - g_clear_signal_handler (&priv->window_actor_destroyed_handler, - priv->window_actor); - - g_object_unref (priv->window_actor); - priv->window_actor = NULL; - } - - clutter_clone_set_source (CLUTTER_CLONE (embed), NULL); -} - -static void -shell_gtk_embed_window_created_cb (MetaDisplay *display, - MetaWindow *window, - ShellGtkEmbed *embed) -{ - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - Window xwindow = meta_window_get_xwindow (window); - GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (priv->window)); - - if (gdk_window && xwindow == gdk_x11_window_get_xid (gdk_window)) - { - ClutterActor *window_actor = - CLUTTER_ACTOR (meta_window_get_compositor_private (window)); - GCallback remove_cb = G_CALLBACK (shell_gtk_embed_remove_window_actor); - cairo_region_t *empty_region; - - clutter_clone_set_source (CLUTTER_CLONE (embed), window_actor); - - /* We want to explicitly clear the clone source when the window - actor is destroyed because otherwise we might end up keeping - it alive after it has been disposed. Otherwise this can cause - a crash if there is a paint after mutter notices that the top - level window has been destroyed, which causes it to dispose - the window, and before the tray manager notices that the - window is gone which would otherwise reset the window and - unref the clone */ - priv->window_actor = g_object_ref (window_actor); - priv->window_actor_destroyed_handler = - g_signal_connect_swapped (window_actor, - "destroy", - remove_cb, - embed); - - /* Hide the original actor otherwise it will appear in the scene - as a normal window */ - clutter_actor_set_opacity (window_actor, 0); - - /* Also make sure it (or any of its children) doesn't block - events on wayland */ - shell_util_set_hidden_from_pick (window_actor, TRUE); - - /* Set an empty input shape on the window so that it can't get - any input. This probably isn't the ideal way to achieve this. - It would probably be better to force the window to go behind - Mutter's guard window, but this is quite difficult to do as - Mutter doesn't manage the stacking for override redirect - windows and the guard window is repeatedly lowered to the - bottom of the stack. */ - empty_region = cairo_region_create (); - gdk_window_input_shape_combine_region (gdk_window, - empty_region, - 0, 0 /* offset x/y */); - cairo_region_destroy (empty_region); - - gdk_window_lower (gdk_window); - - /* Now that we've found the window we don't need to listen for - new windows anymore */ - g_clear_signal_handler (&priv->window_created_handler, - display); - } -} - -static void -shell_gtk_embed_on_window_mapped (GtkWidget *object, - ShellGtkEmbed *embed) -{ - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - MetaDisplay *display = shell_global_get_display (shell_global_get ()); - - if (priv->window_created_handler == 0 && priv->window_actor == NULL) - /* Listen for new windows so we can detect when Mutter has - created a MutterWindow for this window */ - priv->window_created_handler = - g_signal_connect (display, - "window-created", - G_CALLBACK (shell_gtk_embed_window_created_cb), - embed); -} - -static void -shell_gtk_embed_set_window (ShellGtkEmbed *embed, - ShellEmbeddedWindow *window) -{ - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - MetaDisplay *display = shell_global_get_display (shell_global_get ()); - - if (priv->window) - { - g_clear_signal_handler (&priv->window_created_handler, display); - - shell_gtk_embed_remove_window_actor (embed); - - _shell_embedded_window_set_actor (priv->window, NULL); - - g_object_unref (priv->window); - - g_signal_handlers_disconnect_by_func (priv->window, - (gpointer)shell_gtk_embed_on_window_destroy, - embed); - - g_signal_handlers_disconnect_by_func (priv->window, - (gpointer)shell_gtk_embed_on_window_mapped, - embed); - } - - priv->window = window; - - if (priv->window) - { - g_object_ref (priv->window); - - _shell_embedded_window_set_actor (priv->window, embed); - - g_signal_connect (priv->window, "destroy", - G_CALLBACK (shell_gtk_embed_on_window_destroy), embed); - - g_signal_connect (priv->window, "map", - G_CALLBACK (shell_gtk_embed_on_window_mapped), embed); - } - - clutter_actor_queue_relayout (CLUTTER_ACTOR (embed)); -} - -static void -shell_gtk_embed_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ShellGtkEmbed *embed = SHELL_GTK_EMBED (object); - - switch (prop_id) - { - case PROP_WINDOW: - shell_gtk_embed_set_window (embed, (ShellEmbeddedWindow *)g_value_get_object (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -shell_gtk_embed_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - ShellGtkEmbed *embed = SHELL_GTK_EMBED (object); - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - - switch (prop_id) - { - case PROP_WINDOW: - g_value_set_object (value, priv->window); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -shell_gtk_embed_get_preferred_width (ClutterActor *actor, - float for_height, - float *min_width_p, - float *natural_width_p) -{ - ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor); - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - - if (priv->window - && gtk_widget_get_visible (GTK_WIDGET (priv->window))) - { - GtkRequisition min_req, natural_req; - gtk_widget_get_preferred_size (GTK_WIDGET (priv->window), &min_req, &natural_req); - - *min_width_p = min_req.width; - *natural_width_p = natural_req.width; - } - else - *min_width_p = *natural_width_p = 0; -} - -static void -shell_gtk_embed_get_preferred_height (ClutterActor *actor, - float for_width, - float *min_height_p, - float *natural_height_p) -{ - ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor); - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - - if (priv->window - && gtk_widget_get_visible (GTK_WIDGET (priv->window))) - { - GtkRequisition min_req, natural_req; - gtk_widget_get_preferred_size (GTK_WIDGET (priv->window), &min_req, &natural_req); - - *min_height_p = min_req.height; - *natural_height_p = natural_req.height; - } - else - *min_height_p = *natural_height_p = 0; -} - -static void -shell_gtk_embed_allocate (ClutterActor *actor, - const ClutterActorBox *box) -{ - ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor); - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - float wx, wy; - - CLUTTER_ACTOR_CLASS (shell_gtk_embed_parent_class)-> - allocate (actor, box); - - /* Find the actor's new coordinates in terms of the stage (which is - * priv->window's parent window. - */ - clutter_actor_get_transformed_position (actor, &wx, &wy); - - _shell_embedded_window_allocate (priv->window, - (int)(0.5 + wx), (int)(0.5 + wy), - box->x2 - box->x1, - box->y2 - box->y1); -} - -static void -shell_gtk_embed_map (ClutterActor *actor) -{ - ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor); - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - - _shell_embedded_window_map (priv->window); - - CLUTTER_ACTOR_CLASS (shell_gtk_embed_parent_class)->map (actor); -} - -static void -shell_gtk_embed_unmap (ClutterActor *actor) -{ - ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor); - ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed); - - _shell_embedded_window_unmap (priv->window); - - CLUTTER_ACTOR_CLASS (shell_gtk_embed_parent_class)->unmap (actor); -} - -static void -shell_gtk_embed_dispose (GObject *object) -{ - ShellGtkEmbed *embed = SHELL_GTK_EMBED (object); - - G_OBJECT_CLASS (shell_gtk_embed_parent_class)->dispose (object); - - shell_gtk_embed_set_window (embed, NULL); -} - -static void -shell_gtk_embed_class_init (ShellGtkEmbedClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); - - object_class->get_property = shell_gtk_embed_get_property; - object_class->set_property = shell_gtk_embed_set_property; - object_class->dispose = shell_gtk_embed_dispose; - - actor_class->get_preferred_width = shell_gtk_embed_get_preferred_width; - actor_class->get_preferred_height = shell_gtk_embed_get_preferred_height; - actor_class->allocate = shell_gtk_embed_allocate; - actor_class->map = shell_gtk_embed_map; - actor_class->unmap = shell_gtk_embed_unmap; - - g_object_class_install_property (object_class, - PROP_WINDOW, - g_param_spec_object ("window", - "Window", - "ShellEmbeddedWindow to embed", - SHELL_TYPE_EMBEDDED_WINDOW, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} - -static void -shell_gtk_embed_init (ShellGtkEmbed *embed) -{ -} - -/* - * Public API - */ -ClutterActor * -shell_gtk_embed_new (ShellEmbeddedWindow *window) -{ - g_return_val_if_fail (SHELL_IS_EMBEDDED_WINDOW (window), NULL); - - return g_object_new (SHELL_TYPE_GTK_EMBED, - "window", window, - NULL); -} diff --git a/src/shell-gtk-embed.h b/src/shell-gtk-embed.h deleted file mode 100644 index 4cfc489be..000000000 --- a/src/shell-gtk-embed.h +++ /dev/null @@ -1,20 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -#ifndef __SHELL_GTK_EMBED_H__ -#define __SHELL_GTK_EMBED_H__ - -#include - -#include "shell-embedded-window.h" - -#define SHELL_TYPE_GTK_EMBED (shell_gtk_embed_get_type ()) -G_DECLARE_DERIVABLE_TYPE (ShellGtkEmbed, shell_gtk_embed, - SHELL, GTK_EMBED, ClutterClone) - -struct _ShellGtkEmbedClass -{ - ClutterCloneClass parent_class; -}; - -ClutterActor *shell_gtk_embed_new (ShellEmbeddedWindow *window); - -#endif /* __SHELL_GTK_EMBED_H__ */ diff --git a/src/shell-tray-icon-private.h b/src/shell-tray-icon-private.h new file mode 100644 index 000000000..e77ac0aae --- /dev/null +++ b/src/shell-tray-icon-private.h @@ -0,0 +1,11 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +#ifndef SHELL_TRAY_ICON_PRIVATE_H +#define SHELL_TRAY_ICON_PRIVATE_H + +#include "shell-tray-icon.h" + +#include "na-tray-child.h" + +ClutterActor * shell_tray_icon_new (NaTrayChild *tray_child); + +#endif /* SHELL_TRAY_ICON_PRIVATE_H */ diff --git a/src/shell-tray-icon.c b/src/shell-tray-icon.c index 14b219100..cac801654 100644 --- a/src/shell-tray-icon.c +++ b/src/shell-tray-icon.c @@ -2,13 +2,14 @@ #include "config.h" -#include "shell-tray-icon.h" -#include "shell-gtk-embed.h" +#include "shell-global.h" +#include "shell-tray-icon-private.h" +#include "shell-util.h" #include "tray/na-tray-child.h" -#include -#include #include "st.h" +#include + enum { PROP_0, @@ -21,76 +22,86 @@ typedef struct _ShellTrayIconPrivate ShellTrayIconPrivate; struct _ShellTrayIcon { - ShellGtkEmbed parent; - - ShellTrayIconPrivate *priv; -}; - -struct _ShellTrayIconPrivate -{ - NaTrayChild *socket; + ClutterClone parent; + NaTrayChild *tray_child; + ClutterActor *window_actor; + gulong window_actor_destroyed_handler; + gulong window_created_handler; pid_t pid; - char *title, *wm_class; + char *title; + char *wm_class; }; -G_DEFINE_TYPE_WITH_PRIVATE (ShellTrayIcon, shell_tray_icon, SHELL_TYPE_GTK_EMBED); +G_DEFINE_TYPE (ShellTrayIcon, shell_tray_icon, CLUTTER_TYPE_CLONE); static void shell_tray_icon_finalize (GObject *object) { ShellTrayIcon *icon = SHELL_TRAY_ICON (object); - g_free (icon->priv->title); - g_free (icon->priv->wm_class); + g_free (icon->title); + g_free (icon->wm_class); G_OBJECT_CLASS (shell_tray_icon_parent_class)->finalize (object); } static void -shell_tray_icon_constructed (GObject *object) +shell_tray_icon_remove_window_actor (ShellTrayIcon *tray_icon) { - GdkWindow *icon_app_window; - ShellTrayIcon *icon = SHELL_TRAY_ICON (object); - ShellEmbeddedWindow *window; - GdkDisplay *display; - Window plug_xid; - Atom _NET_WM_PID, type; - int result, format; - gulong nitems, bytes_after, *val = NULL; + if (tray_icon->window_actor) + { + g_clear_signal_handler (&tray_icon->window_actor_destroyed_handler, + tray_icon->window_actor); + g_clear_object (&tray_icon->window_actor); + } - /* We do all this now rather than computing it on the fly later, - * because the shell 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. - */ + clutter_clone_set_source (CLUTTER_CLONE (tray_icon), NULL); +} - 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); +static void +shell_tray_icon_window_created_cb (MetaDisplay *display, + MetaWindow *window, + ShellTrayIcon *tray_icon) +{ + Window xwindow = meta_window_get_xwindow (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); + if (tray_icon->tray_child && + xwindow == na_xembed_get_socket_window (NA_XEMBED (tray_icon->tray_child))) + { + ClutterActor *window_actor = + CLUTTER_ACTOR (meta_window_get_compositor_private (window)); - icon_app_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket)); - plug_xid = GDK_WINDOW_XID (icon_app_window); + clutter_clone_set_source (CLUTTER_CLONE (tray_icon), window_actor); - display = gtk_widget_get_display (GTK_WIDGET (icon->priv->socket)); - gdk_x11_display_error_trap_push (display); - _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_x11_display_error_trap_pop (display) && - result == Success && - type == XA_CARDINAL && - nitems == 1) - icon->priv->pid = *val; + /* We want to explicitly clear the clone source when the window + actor is destroyed because otherwise we might end up keeping + it alive after it has been disposed. Otherwise this can cause + a crash if there is a paint after mutter notices that the top + level window has been destroyed, which causes it to dispose + the window, and before the tray manager notices that the + window is gone which would otherwise reset the window and + unref the clone */ + tray_icon->window_actor = g_object_ref (window_actor); + tray_icon->window_actor_destroyed_handler = + g_signal_connect_swapped (window_actor, + "destroy", + G_CALLBACK (shell_tray_icon_remove_window_actor), + tray_icon); - if (val) - XFree (val); + /* Hide the original actor otherwise it will appear in the scene + as a normal window */ + clutter_actor_set_opacity (window_actor, 0); + + /* Also make sure it (or any of its children) doesn't block + events on wayland */ + shell_util_set_hidden_from_pick (window_actor, TRUE); + + /* Now that we've found the window we don't need to listen for + new windows anymore */ + g_clear_signal_handler (&tray_icon->window_created_handler, + display); + } } static void @@ -104,15 +115,15 @@ shell_tray_icon_get_property (GObject *object, switch (prop_id) { case PROP_PID: - g_value_set_uint (value, icon->priv->pid); + g_value_set_uint (value, icon->pid); break; case PROP_TITLE: - g_value_set_string (value, icon->priv->title); + g_value_set_string (value, icon->title); break; case PROP_WM_CLASS: - g_value_set_string (value, icon->priv->wm_class); + g_value_set_string (value, icon->wm_class); break; default: @@ -121,14 +132,78 @@ shell_tray_icon_get_property (GObject *object, } } +static void +shell_tray_icon_dispose (GObject *object) +{ + ShellTrayIcon *tray_icon = SHELL_TRAY_ICON (object); + MetaDisplay *display = shell_global_get_display (shell_global_get ()); + + g_clear_signal_handler (&tray_icon->window_created_handler, + display); + shell_tray_icon_remove_window_actor (tray_icon); + + G_OBJECT_CLASS (shell_tray_icon_parent_class)->dispose (object); +} + +static void +shell_tray_icon_get_preferred_width (ClutterActor *actor, + float for_height, + float *min_width_p, + float *natural_width_p) +{ + ShellTrayIcon *tray_icon = SHELL_TRAY_ICON (actor); + int width; + + na_xembed_get_size (NA_XEMBED (tray_icon->tray_child), &width, NULL); + + *min_width_p = width; + *natural_width_p = width; +} + +static void +shell_tray_icon_get_preferred_height (ClutterActor *actor, + float for_width, + float *min_height_p, + float *natural_height_p) +{ + ShellTrayIcon *tray_icon = SHELL_TRAY_ICON (actor); + int height; + + na_xembed_get_size (NA_XEMBED (tray_icon->tray_child), NULL, &height); + + *min_height_p = height; + *natural_height_p = height; +} + +static void +shell_tray_icon_allocate (ClutterActor *actor, + const ClutterActorBox *box) +{ + ShellTrayIcon *tray_icon = SHELL_TRAY_ICON (actor); + float wx, wy; + + CLUTTER_ACTOR_CLASS (shell_tray_icon_parent_class)->allocate (actor, box); + + /* Find the actor's new coordinates in terms of the stage. + */ + clutter_actor_get_transformed_position (actor, &wx, &wy); + na_xembed_set_root_position (NA_XEMBED (tray_icon->tray_child), + (int)(0.5 + wx), (int)(0.5 + wy)); +} + static void shell_tray_icon_class_init (ShellTrayIconClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); object_class->get_property = shell_tray_icon_get_property; - object_class->constructed = shell_tray_icon_constructed; - object_class->finalize = shell_tray_icon_finalize; + object_class->finalize = shell_tray_icon_finalize; + object_class->dispose = shell_tray_icon_dispose; + + actor_class->get_preferred_width = shell_tray_icon_get_preferred_width; + actor_class->get_preferred_height = shell_tray_icon_get_preferred_height; + actor_class->allocate = shell_tray_icon_allocate; g_object_class_install_property (object_class, PROP_PID, @@ -156,20 +231,77 @@ shell_tray_icon_class_init (ShellTrayIconClass *klass) static void shell_tray_icon_init (ShellTrayIcon *icon) { - icon->priv = shell_tray_icon_get_instance_private (icon); +} + +static void +shell_tray_icon_set_child (ShellTrayIcon *tray_icon, + NaTrayChild *tray_child) +{ + MetaDisplay *display = shell_global_get_display (shell_global_get ()); + MetaX11Display *x11_display; + Display *xdisplay; + Window plug_xid; + Atom type; + int result, format; + gulong nitems, bytes_after, *val = NULL; + + g_return_if_fail (tray_icon != NULL); + g_return_if_fail (tray_child != NULL); + + x11_display = meta_display_get_x11_display (display); + + /* We do all this now rather than computing it on the fly later, + * because the shell 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. + */ + + tray_icon->tray_child = tray_child; + + tray_icon->title = na_tray_child_get_title (tray_icon->tray_child); + na_tray_child_get_wm_class (tray_icon->tray_child, + NULL, &tray_icon->wm_class); + + plug_xid = na_xembed_get_plug_window (NA_XEMBED (tray_icon->tray_child)); + + xdisplay = meta_x11_display_get_xdisplay (x11_display); + meta_x11_error_trap_push (x11_display); + result = XGetWindowProperty (xdisplay, plug_xid, + XInternAtom (xdisplay, "_NET_WM_PID", False), + 0, G_MAXLONG, False, XA_CARDINAL, + &type, &format, &nitems, + &bytes_after, (guchar **)&val); + + if (!meta_x11_error_trap_pop_with_return (x11_display) && + result == Success && + type == XA_CARDINAL && + nitems == 1) + tray_icon->pid = *val; + + if (val) + XFree (val); + + tray_icon->window_created_handler = + g_signal_connect (display, + "window-created", + G_CALLBACK (shell_tray_icon_window_created_cb), + tray_icon); } /* * Public API */ ClutterActor * -shell_tray_icon_new (ShellEmbeddedWindow *window) +shell_tray_icon_new (NaTrayChild *tray_child) { - g_return_val_if_fail (SHELL_IS_EMBEDDED_WINDOW (window), NULL); + ShellTrayIcon *tray_icon; - return g_object_new (SHELL_TYPE_TRAY_ICON, - "window", window, - NULL); + g_return_val_if_fail (NA_IS_TRAY_CHILD (tray_child), NULL); + + tray_icon = g_object_new (SHELL_TYPE_TRAY_ICON, NULL); + shell_tray_icon_set_child (tray_icon, tray_child); + + return CLUTTER_ACTOR (tray_icon); } /** @@ -187,37 +319,37 @@ void shell_tray_icon_click (ShellTrayIcon *icon, ClutterEvent *event) { + MetaDisplay *display = shell_global_get_display (shell_global_get ()); + MetaX11Display *x11_display; XKeyEvent xkevent; XButtonEvent xbevent; XCrossingEvent xcevent; - GdkDisplay *display; - GdkWindow *remote_window; - GdkScreen *screen; - int x_root, y_root; Display *xdisplay; Window xwindow, xrootwindow; ClutterEventType event_type = clutter_event_type (event); + int width, height; g_return_if_fail (event_type == CLUTTER_BUTTON_RELEASE || event_type == CLUTTER_KEY_PRESS || event_type == CLUTTER_KEY_RELEASE); - remote_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket)); - if (remote_window == NULL) + x11_display = meta_display_get_x11_display (display); + if (!x11_display) + return; + + xwindow = na_xembed_get_plug_window (NA_XEMBED (icon->tray_child)); + if (xwindow == None) { g_warning ("shell tray: plug window is gone"); return; } - xdisplay = GDK_WINDOW_XDISPLAY (remote_window); - display = gdk_x11_lookup_xdisplay (xdisplay); - gdk_x11_display_error_trap_push (display); + na_xembed_get_size (NA_XEMBED (icon->tray_child), &width, &height); - xwindow = GDK_WINDOW_XID (remote_window); - screen = gdk_window_get_screen (remote_window); - xrootwindow = GDK_WINDOW_XID (gdk_screen_get_root_window (screen)); - gdk_window_get_origin (remote_window, &x_root, &y_root); + meta_x11_error_trap_push (x11_display); + xdisplay = meta_x11_display_get_xdisplay (x11_display); + xrootwindow = XDefaultRootWindow (xdisplay); /* First make the icon believe the pointer is inside it */ xcevent.type = EnterNotify; @@ -225,10 +357,10 @@ shell_tray_icon_click (ShellTrayIcon *icon, xcevent.root = xrootwindow; xcevent.subwindow = None; xcevent.time = clutter_event_get_time (event); - xcevent.x = gdk_window_get_width (remote_window) / 2; - xcevent.y = gdk_window_get_height (remote_window) / 2; - xcevent.x_root = x_root + xcevent.x; - xcevent.y_root = y_root + xcevent.y; + xcevent.x = width / 2; + xcevent.y = height / 2; + xcevent.x_root = xcevent.x; + xcevent.y_root = xcevent.y; xcevent.mode = NotifyNormal; xcevent.detail = NotifyNonlinear; xcevent.same_screen = True; @@ -290,5 +422,5 @@ shell_tray_icon_click (ShellTrayIcon *icon, xcevent.type = LeaveNotify; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent); - gdk_x11_display_error_trap_pop_ignored (display); + meta_x11_error_trap_pop (x11_display); } diff --git a/src/shell-tray-icon.h b/src/shell-tray-icon.h index f0e119114..434bd3d12 100644 --- a/src/shell-tray-icon.h +++ b/src/shell-tray-icon.h @@ -2,15 +2,13 @@ #ifndef __SHELL_TRAY_ICON_H__ #define __SHELL_TRAY_ICON_H__ -#include "shell-gtk-embed.h" +#include #define SHELL_TYPE_TRAY_ICON (shell_tray_icon_get_type ()) G_DECLARE_FINAL_TYPE (ShellTrayIcon, shell_tray_icon, - SHELL, TRAY_ICON, ShellGtkEmbed) + SHELL, TRAY_ICON, ClutterClone) -ClutterActor *shell_tray_icon_new (ShellEmbeddedWindow *window); - -void shell_tray_icon_click (ShellTrayIcon *icon, - ClutterEvent *event); +void shell_tray_icon_click (ShellTrayIcon *icon, + ClutterEvent *event); #endif /* __SHELL_TRAY_ICON_H__ */ diff --git a/src/shell-tray-manager.c b/src/shell-tray-manager.c index c8e325978..4b332a87c 100644 --- a/src/shell-tray-manager.c +++ b/src/shell-tray-manager.c @@ -4,14 +4,12 @@ #include #include -#include #include #include "shell-tray-manager.h" #include "na-tray-manager.h" -#include "shell-tray-icon.h" -#include "shell-embedded-window.h" +#include "shell-tray-icon-private.h" #include "shell-global.h" typedef struct _ShellTrayManagerPrivate ShellTrayManagerPrivate; @@ -33,8 +31,7 @@ struct _ShellTrayManagerPrivate { typedef struct { ShellTrayManager *manager; - GtkWidget *socket; - GtkWidget *window; + NaTrayChild *tray_child; ClutterActor *actor; } ShellTrayManagerChild; @@ -60,15 +57,19 @@ static const ClutterColor default_color = { 0x00, 0x00, 0x00, 0xff }; static void shell_tray_manager_release_resources (ShellTrayManager *manager); -static void na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *child, gpointer manager); -static void na_tray_icon_removed (NaTrayManager *na_manager, GtkWidget *child, gpointer manager); +static void na_tray_icon_added (NaTrayManager *na_manager, + NaTrayChild *child, + gpointer manager); + +static void na_tray_icon_removed (NaTrayManager *na_manager, + NaTrayChild *child, + gpointer manager); static void free_tray_icon (gpointer data) { ShellTrayManagerChild *child = data; - gtk_widget_destroy (child->window); if (child->actor) { g_signal_handlers_disconnect_matched (child->actor, G_SIGNAL_MATCH_DATA, @@ -188,13 +189,19 @@ shell_tray_manager_new (void) static void shell_tray_manager_ensure_resources (ShellTrayManager *manager) { + MetaDisplay *display; + MetaX11Display *x11_display; + if (manager->priv->na_manager != NULL) return; manager->priv->icons = g_hash_table_new_full (NULL, NULL, NULL, free_tray_icon); - manager->priv->na_manager = na_tray_manager_new (); + display = shell_global_get_display (shell_global_get ()); + x11_display = meta_display_get_x11_display (display); + + manager->priv->na_manager = na_tray_manager_new (x11_display); g_signal_connect (manager->priv->na_manager, "tray-icon-added", G_CALLBACK (na_tray_icon_added), manager); @@ -231,7 +238,7 @@ static void shell_tray_manager_manage_screen_internal (ShellTrayManager *manager) { shell_tray_manager_ensure_resources (manager); - na_tray_manager_manage_screen (manager->priv->na_manager); + na_tray_manager_manage (manager->priv->na_manager); } void @@ -277,98 +284,63 @@ shell_tray_manager_unmanage_screen (ShellTrayManager *manager) } static void -shell_tray_manager_child_on_realize (GtkWidget *widget, - ShellTrayManagerChild *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.); -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - gdk_window_set_background_pattern (gtk_widget_get_window (widget), - bg_pattern); -G_GNUC_END_IGNORE_DEPRECATIONS - - cairo_pattern_destroy (bg_pattern); - } -} - -static void -on_plug_added (GtkSocket *socket, +on_plug_added (NaTrayChild *tray_child, ShellTrayManager *manager) { ShellTrayManagerChild *child; - g_signal_handlers_disconnect_by_func (socket, on_plug_added, manager); + g_signal_handlers_disconnect_by_func (tray_child, on_plug_added, manager); - child = g_hash_table_lookup (manager->priv->icons, socket); + child = g_hash_table_lookup (manager->priv->icons, tray_child); - child->actor = shell_tray_icon_new (SHELL_EMBEDDED_WINDOW (child->window)); + child->actor = shell_tray_icon_new (tray_child); g_object_ref_sink (child->actor); + na_xembed_set_background_color (NA_XEMBED (tray_child), + &manager->priv->bg_color); + g_signal_emit (manager, shell_tray_manager_signals[TRAY_ICON_ADDED], 0, child->actor); } static void -na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket, - gpointer user_data) +na_tray_icon_added (NaTrayManager *na_manager, + NaTrayChild *tray_child, + gpointer user_data) { ShellTrayManager *manager = user_data; - GtkWidget *win; ShellTrayManagerChild *child; - win = shell_embedded_window_new (); - 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_new0 (ShellTrayManagerChild, 1); child->manager = manager; - child->window = win; - child->socket = socket; + child->tray_child = tray_child; - g_signal_connect (win, "realize", - G_CALLBACK (shell_tray_manager_child_on_realize), child); + g_hash_table_insert (manager->priv->icons, tray_child, 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); + g_signal_connect (tray_child, "plug-added", + G_CALLBACK (on_plug_added), manager); } static void -na_tray_icon_removed (NaTrayManager *na_manager, GtkWidget *socket, - gpointer user_data) +na_tray_icon_removed (NaTrayManager *na_manager, + NaTrayChild *tray_child, + gpointer user_data) { ShellTrayManager *manager = user_data; ShellTrayManagerChild *child; - child = g_hash_table_lookup (manager->priv->icons, socket); + child = g_hash_table_lookup (manager->priv->icons, tray_child); g_return_if_fail (child != NULL); if (child->actor != NULL) { /* Only emit signal if a corresponding tray-icon-added signal was emitted, - that is, if embedding did not fail and we got a plug-added - */ + * that is, if embedding did not fail and we got a plug-added + */ g_signal_emit (manager, shell_tray_manager_signals[TRAY_ICON_REMOVED], 0, child->actor); } - g_hash_table_remove (manager->priv->icons, socket); + + g_hash_table_remove (manager->priv->icons, tray_child); } diff --git a/src/tray/meson.build b/src/tray/meson.build index 092e7f689..9d28e8cf1 100644 --- a/src/tray/meson.build +++ b/src/tray/meson.build @@ -9,6 +9,6 @@ tray_sources = [ libtray = static_library('tray', tray_sources, c_args: ['-DG_LOG_DOMAIN="notification_area"'], - dependencies: [mutter_dep, gtk_dep], + dependencies: [mutter_dep], include_directories: conf_inc ) diff --git a/src/tray/na-tray-child.c b/src/tray/na-tray-child.c index 175ac8a5a..1f1bae9b1 100644 --- a/src/tray/na-tray-child.c +++ b/src/tray/na-tray-child.c @@ -22,203 +22,16 @@ #include "na-tray-child.h" -#include -#include #include +#include -G_DEFINE_TYPE (NaTrayChild, na_tray_child, GTK_TYPE_SOCKET) - -static void -na_tray_child_finalize (GObject *object) +struct _NaTrayChild { - G_OBJECT_CLASS (na_tray_child_parent_class)->finalize (object); -} + NaXembed parent_instance; + guint parent_relative_bg : 1; +}; -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); -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - gdk_window_set_background_pattern (window, transparent); -G_GNUC_END_IGNORE_DEPRECATIONS - 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. */ -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - gdk_window_set_background_pattern (window, NULL); -G_GNUC_END_IGNORE_DEPRECATIONS - - 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; - } - - 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. - * The function is deprecated because it is only meaningful on X11 - the - * same is true for XEmbed of course, so just ignore the warning. - */ -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - gtk_widget_set_double_buffered (GTK_WIDGET (child), - child->parent_relative_bg); -G_GNUC_END_IGNORE_DEPRECATIONS -} - -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 re-enabled. 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 (%ix%i), resizing to (%ix%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); - 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); - } -} - -/* 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; -} +G_DEFINE_TYPE (NaTrayChild, na_tray_child, NA_TYPE_XEMBED) static void na_tray_child_init (NaTrayChild *child) @@ -228,78 +41,47 @@ 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->draw = na_tray_child_draw; } -GtkWidget * -na_tray_child_new (GdkScreen *screen, - Window icon_window) +NaTrayChild * +na_tray_child_new (MetaX11Display *x11_display, + Window icon_window) { XWindowAttributes window_attributes; - GdkDisplay *display; Display *xdisplay; NaTrayChild *child; - GdkVisual *visual; - gboolean visual_has_alpha; - int red_prec, green_prec, blue_prec, depth; int result; - g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + g_return_val_if_fail (META_IS_X11_DISPLAY (x11_display), NULL); g_return_val_if_fail (icon_window != None, NULL); - xdisplay = GDK_SCREEN_XDISPLAY (screen); - display = gdk_x11_lookup_xdisplay (xdisplay); + xdisplay = meta_x11_display_get_xdisplay (x11_display); /* We need to determine the visual of the window we are embedding and create * the socket in the same visual. */ - gdk_x11_display_error_trap_push (display); + meta_x11_error_trap_push (x11_display); result = XGetWindowAttributes (xdisplay, icon_window, &window_attributes); - gdk_x11_display_error_trap_pop_ignored (display); + meta_x11_error_trap_pop (x11_display); 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; + child = g_object_new (NA_TYPE_TRAY_CHILD, + "x11-display", x11_display, + NULL); - child = g_object_new (NA_TYPE_TRAY_CHILD, NULL); - child->icon_window = icon_window; - - gtk_widget_set_visual (GTK_WIDGET (child), visual); - - /* We have alpha if the visual has something other than red, green, - * and blue */ - gdk_visual_get_red_pixel_details (visual, NULL, NULL, &red_prec); - gdk_visual_get_green_pixel_details (visual, NULL, NULL, &green_prec); - gdk_visual_get_blue_pixel_details (visual, NULL, NULL, &blue_prec); - depth = gdk_visual_get_depth (visual); - - visual_has_alpha = red_prec + blue_prec + green_prec < depth; - child->has_alpha = visual_has_alpha; - - return GTK_WIDGET (child); + return child; } char * na_tray_child_get_title (NaTrayChild *child) { char *retval = NULL; - GdkDisplay *display; + MetaX11Display *x11_display; + Display *xdisplay; Atom utf8_string, atom, type; int result; int format; @@ -309,22 +91,23 @@ na_tray_child_get_title (NaTrayChild *child) g_return_val_if_fail (NA_IS_TRAY_CHILD (child), NULL); - display = gtk_widget_get_display (GTK_WIDGET (child)); + x11_display = na_xembed_get_x11_display (NA_XEMBED (child)); + xdisplay = meta_x11_display_get_xdisplay (x11_display); - 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"); + utf8_string = XInternAtom (xdisplay, "UTF8_STRING", False); + atom = XInternAtom (xdisplay, "_NET_WM_NAME", False); - gdk_x11_display_error_trap_push (display); + meta_x11_error_trap_push (x11_display); - result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), - child->icon_window, + result = XGetWindowProperty (xdisplay, + na_xembed_get_plug_window (NA_XEMBED (child)), atom, 0, G_MAXLONG, False, utf8_string, &type, &format, &nitems, &bytes_after, (guchar **)&val); - - if (gdk_x11_display_error_trap_pop (display) || result != Success) + + if (meta_x11_error_trap_pop_with_return (x11_display) || result != Success) return NULL; if (type != utf8_string || @@ -349,73 +132,6 @@ na_tray_child_get_title (NaTrayChild *child) return retval; } -/** - * na_tray_child_has_alpha; - * @child: a #NaTrayChild - * - * Checks if the child has an ARGB visual and real alpha transparence. - * (as opposed to faked alpha transparency with an parent-relative - * background) - * - * Return value: %TRUE if the child has an alpha transparency - */ -gboolean -na_tray_child_has_alpha (NaTrayChild *child) -{ - g_return_val_if_fail (NA_IS_TRAY_CHILD (child), FALSE); - - return child->has_alpha; -} - -/* 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_get_mapped (widget) && 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. - */ - GdkDisplay *display = gtk_widget_get_display (widget); - Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); - XEvent xev; - GdkWindow *plug_window; - GtkAllocation allocation; - - plug_window = gtk_socket_get_plug_window (GTK_SOCKET (child)); - gtk_widget_get_allocation (widget, &allocation); - - xev.xexpose.type = Expose; - xev.xexpose.window = GDK_WINDOW_XID (plug_window); - xev.xexpose.x = 0; - xev.xexpose.y = 0; - xev.xexpose.width = allocation.width; - xev.xexpose.height = allocation.height; - xev.xexpose.count = 0; - - gdk_x11_display_error_trap_push (display); - XSendEvent (xdisplay, - xev.xexpose.window, - False, ExposureMask, - &xev); - gdk_x11_display_error_trap_pop_ignored (display); -#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 - } -} - /* from libwnck/xutils.c, comes as LGPLv2+ */ static char * latin1_to_utf8 (const char *latin1) @@ -437,21 +153,22 @@ latin1_to_utf8 (const char *latin1) /* derived from libwnck/xutils.c, comes as LGPLv2+ */ static void -_get_wmclass (Display *xdisplay, - Window xwindow, - char **res_class, - char **res_name) +_get_wmclass (MetaX11Display *x11_display, + Window xwindow, + char **res_class, + char **res_name) { - GdkDisplay *display; XClassHint ch; + Display *xdisplay; ch.res_name = NULL; ch.res_class = NULL; - display = gdk_x11_lookup_xdisplay (xdisplay); - gdk_x11_display_error_trap_push (display); + xdisplay = meta_x11_display_get_xdisplay (x11_display); + + meta_x11_error_trap_push (x11_display); XGetClassHint (xdisplay, xwindow, &ch); - gdk_x11_display_error_trap_pop_ignored (display); + meta_x11_error_trap_pop (x11_display); if (res_class) *res_class = NULL; @@ -491,14 +208,14 @@ na_tray_child_get_wm_class (NaTrayChild *child, char **res_name, char **res_class) { - GdkDisplay *display; + MetaX11Display *x11_display; g_return_if_fail (NA_IS_TRAY_CHILD (child)); - display = gtk_widget_get_display (GTK_WIDGET (child)); + x11_display = na_xembed_get_x11_display (NA_XEMBED (child)); - _get_wmclass (GDK_DISPLAY_XDISPLAY (display), - child->icon_window, + _get_wmclass (x11_display, + na_xembed_get_plug_window (NA_XEMBED (child)), res_class, res_name); } diff --git a/src/tray/na-tray-child.h b/src/tray/na-tray-child.h index d14367642..c50a0f928 100644 --- a/src/tray/na-tray-child.h +++ b/src/tray/na-tray-child.h @@ -21,42 +21,18 @@ #ifndef __NA_TRAY_CHILD_H__ #define __NA_TRAY_CHILD_H__ -#include -#include +#include "na-xembed.h" + +#include 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)) +#define NA_TYPE_TRAY_CHILD (na_tray_child_get_type ()) +G_DECLARE_FINAL_TYPE (NaTrayChild, na_tray_child, NA, TRAY_CHILD, NaXembed) -typedef struct _NaTrayChild NaTrayChild; -typedef struct _NaTrayChildClass NaTrayChildClass; -typedef struct _NaTrayChildChild NaTrayChildChild; - -struct _NaTrayChild -{ - GtkSocket parent_instance; - Window icon_window; - guint has_alpha : 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); +NaTrayChild *na_tray_child_new (MetaX11Display *x11_display, + Window icon_window); char *na_tray_child_get_title (NaTrayChild *child); -gboolean na_tray_child_has_alpha (NaTrayChild *child); -void na_tray_child_force_redraw (NaTrayChild *child); void na_tray_child_get_wm_class (NaTrayChild *child, char **res_name, char **res_class); diff --git a/src/tray/na-tray-manager.c b/src/tray/na-tray-manager.c index 15e1d80ec..1fbb7ac20 100644 --- a/src/tray/na-tray-manager.c +++ b/src/tray/na-tray-manager.c @@ -24,13 +24,8 @@ #include "na-tray-manager.h" -#if defined (GDK_WINDOWING_X11) -#include #include -#elif defined (GDK_WINDOWING_WIN32) -#include -#endif -#include +#include /* Signals */ enum @@ -43,36 +38,53 @@ enum LAST_SIGNAL }; -enum { +static guint manager_signals[LAST_SIGNAL]; + +enum +{ PROP_0, - PROP_ORIENTATION + PROP_X11_DISPLAY, + N_PROPS, }; +static GParamSpec *props[N_PROPS]; + typedef struct { long id, len; long remaining_len; - + long timeout; char *str; -#ifdef GDK_WINDOWING_X11 Window window; -#endif } PendingMessage; -static guint manager_signals[LAST_SIGNAL]; +struct _NaTrayManager +{ + GObject parent_instance; + + MetaX11Display *x11_display; + + Atom selection_atom; + Atom opcode_atom; + Atom message_data_atom; + + Window window; + ClutterColor fg; + ClutterColor error; + ClutterColor warning; + ClutterColor success; + + unsigned int event_func_id; + + GList *messages; + GHashTable *children; +}; #define SYSTEM_TRAY_REQUEST_DOCK 0 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 -#define SYSTEM_TRAY_ORIENTATION_HORZ 0 -#define SYSTEM_TRAY_ORIENTATION_VERT 1 - -#ifdef GDK_WINDOWING_X11 -static gboolean na_tray_manager_check_running_screen_x11 (void); -#endif - static void na_tray_manager_finalize (GObject *object); static void na_tray_manager_set_property (GObject *object, guint prop_id, @@ -90,8 +102,8 @@ G_DEFINE_TYPE (NaTrayManager, na_tray_manager, G_TYPE_OBJECT) static void na_tray_manager_init (NaTrayManager *manager) { - manager->invisible = NULL; - manager->socket_table = g_hash_table_new (NULL, NULL); + manager->window = None; + manager->children = g_hash_table_new (NULL, NULL); manager->fg.red = 0; manager->fg.green = 0; @@ -121,83 +133,69 @@ na_tray_manager_class_init (NaTrayManagerClass *klass) gobject_class->set_property = na_tray_manager_set_property; gobject_class->get_property = na_tray_manager_get_property; - g_object_class_install_property (gobject_class, - PROP_ORIENTATION, - g_param_spec_enum ("orientation", - "orientation", - "orientation", - GTK_TYPE_ORIENTATION, - GTK_ORIENTATION_HORIZONTAL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS | - G_PARAM_CONSTRUCT)); - manager_signals[TRAY_ICON_ADDED] = g_signal_new ("tray_icon_added", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NaTrayManagerClass, tray_icon_added), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, - GTK_TYPE_SOCKET); + G_TYPE_NONE, 1, + NA_TYPE_TRAY_CHILD); manager_signals[TRAY_ICON_REMOVED] = g_signal_new ("tray_icon_removed", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NaTrayManagerClass, tray_icon_removed), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, - GTK_TYPE_SOCKET); + G_TYPE_NONE, 1, + NA_TYPE_TRAY_CHILD); manager_signals[MESSAGE_SENT] = g_signal_new ("message_sent", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NaTrayManagerClass, message_sent), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 4, - GTK_TYPE_SOCKET, - G_TYPE_STRING, - G_TYPE_LONG, - G_TYPE_LONG); + G_TYPE_NONE, 4, + NA_TYPE_TRAY_CHILD, + G_TYPE_STRING, + G_TYPE_LONG, + G_TYPE_LONG); manager_signals[MESSAGE_CANCELLED] = g_signal_new ("message_cancelled", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NaTrayManagerClass, message_cancelled), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, - GTK_TYPE_SOCKET, - G_TYPE_LONG); + G_TYPE_NONE, 2, + NA_TYPE_TRAY_CHILD, + G_TYPE_LONG); manager_signals[LOST_SELECTION] = g_signal_new ("lost_selection", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NaTrayManagerClass, lost_selection), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 0); -#if defined (GDK_WINDOWING_X11) - /* Nothing */ -#elif defined (GDK_WINDOWING_WIN32) - g_warning ("Port NaTrayManager to Win32"); -#else - g_warning ("Port NaTrayManager to this GTK+ backend"); -#endif + props[PROP_X11_DISPLAY] = + g_param_spec_object ("x11-display", + "x11-display", + "x11-display", + META_TYPE_X11_DISPLAY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (gobject_class, N_PROPS, props); } static void na_tray_manager_finalize (GObject *object) { NaTrayManager *manager; - + manager = NA_TRAY_MANAGER (object); na_tray_manager_unmanage (manager); g_list_free (manager->messages); - g_hash_table_destroy (manager->socket_table); - + g_hash_table_destroy (manager->children); + G_OBJECT_CLASS (na_tray_manager_parent_class)->finalize (object); } @@ -211,8 +209,8 @@ na_tray_manager_set_property (GObject *object, switch (prop_id) { - case PROP_ORIENTATION: - na_tray_manager_set_orientation (manager, g_value_get_enum (value)); + case PROP_X11_DISPLAY: + manager->x11_display = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -230,8 +228,8 @@ na_tray_manager_get_property (GObject *object, switch (prop_id) { - case PROP_ORIENTATION: - g_value_set_enum (value, manager->orientation); + case PROP_X11_DISPLAY: + g_value_set_object (value, manager->x11_display); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -240,26 +238,24 @@ na_tray_manager_get_property (GObject *object, } NaTrayManager * -na_tray_manager_new (void) +na_tray_manager_new (MetaX11Display *x11_display) { - NaTrayManager *manager; - - manager = g_object_new (NA_TYPE_TRAY_MANAGER, NULL); - - return manager; + return g_object_new (NA_TYPE_TRAY_MANAGER, + "x11-display", x11_display, + NULL); } -#ifdef GDK_WINDOWING_X11 - static gboolean -na_tray_manager_plug_removed (GtkSocket *socket, - NaTrayManager *manager) +na_tray_manager_plug_removed (NaTrayChild *tray_child, + NaTrayManager *manager) { - NaTrayChild *child = NA_TRAY_CHILD (socket); + Window icon_window; - g_hash_table_remove (manager->socket_table, - GINT_TO_POINTER (child->icon_window)); - g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child); + icon_window = na_xembed_get_plug_window (NA_XEMBED (tray_child)); + + g_hash_table_remove (manager->children, + GINT_TO_POINTER (icon_window)); + g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, tray_child); /* This destroys the socket. */ return FALSE; @@ -267,49 +263,40 @@ na_tray_manager_plug_removed (GtkSocket *socket, static void na_tray_manager_handle_dock_request (NaTrayManager *manager, - XClientMessageEvent *xevent) + XClientMessageEvent *xevent) { Window icon_window = xevent->data.l[2]; - GtkWidget *child; + NaTrayChild *child; - if (g_hash_table_lookup (manager->socket_table, + if (g_hash_table_lookup (manager->children, GINT_TO_POINTER (icon_window))) { /* We already got this notification earlier, ignore this one */ return; } - child = na_tray_child_new (manager->screen, icon_window); + child = na_tray_child_new (manager->x11_display, icon_window); if (child == NULL) /* already gone or other error */ return; g_signal_emit (manager, manager_signals[TRAY_ICON_ADDED], 0, - child); + child); - /* If the child wasn't attached, then destroy it */ + g_signal_connect (child, "plug-removed", + G_CALLBACK (na_tray_manager_plug_removed), manager); - if (!GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (child)))) - { - gtk_widget_destroy (child); - return; - } + na_xembed_add_id (NA_XEMBED (child), icon_window); - g_signal_connect (child, "plug_removed", - G_CALLBACK (na_tray_manager_plug_removed), manager); - - gtk_socket_add_id (GTK_SOCKET (child), icon_window); - - if (!gtk_socket_get_plug_window (GTK_SOCKET (child))) + if (!na_xembed_get_plug_window (NA_XEMBED (child))) { /* Embedding failed, we won't get a plug-removed signal */ - /* This signal destroys the socket */ + /* This signal destroys the tray child */ g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child); return; } - g_hash_table_insert (manager->socket_table, + g_hash_table_insert (manager->children, GINT_TO_POINTER (icon_window), child); - gtk_widget_show (child); } static void @@ -321,11 +308,11 @@ pending_message_free (PendingMessage *message) static void na_tray_manager_handle_message_data (NaTrayManager *manager, - XClientMessageEvent *xevent) + XClientMessageEvent *xevent) { GList *p; - int len; - + int len; + /* Try to see if we can find the pending message in the list */ for (p = manager->messages; p; p = p->next) { @@ -340,21 +327,23 @@ na_tray_manager_handle_message_data (NaTrayManager *manager, &xevent->data, len); msg->remaining_len -= len; - if (msg->remaining_len == 0) - { - GtkSocket *socket; + if (msg->remaining_len == 0) + { + NaTrayChild *child; - socket = g_hash_table_lookup (manager->socket_table, - GINT_TO_POINTER (msg->window)); + child = g_hash_table_lookup (manager->children, + GINT_TO_POINTER (msg->window)); - if (socket) - g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0, - socket, msg->str, msg->id, msg->timeout); + if (child) + { + g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0, + child, msg->str, msg->id, msg->timeout); + } - pending_message_free (msg); - manager->messages = g_list_remove_link (manager->messages, p); + pending_message_free (msg); + manager->messages = g_list_remove_link (manager->messages, p); g_list_free_1 (p); - } + } break; } @@ -363,24 +352,22 @@ na_tray_manager_handle_message_data (NaTrayManager *manager, static void na_tray_manager_handle_begin_message (NaTrayManager *manager, - XClientMessageEvent *xevent) + XClientMessageEvent *xevent) { - GtkSocket *socket; - GList *p; + NaTrayChild *child; + GList *p; PendingMessage *msg; - long timeout; - long len; - long id; + long timeout, len, id; - socket = g_hash_table_lookup (manager->socket_table, - GINT_TO_POINTER (xevent->window)); + child = g_hash_table_lookup (manager->children, + GINT_TO_POINTER (xevent->window)); /* we don't know about this tray icon, so ignore the message */ - if (!socket) + if (!child) return; timeout = xevent->data.l[2]; - len = xevent->data.l[3]; - id = xevent->data.l[4]; + len = xevent->data.l[3]; + id = xevent->data.l[4]; /* Check if the same message is already in the queue and remove it if so */ for (p = manager->messages; p; p = p->next) @@ -401,7 +388,7 @@ na_tray_manager_handle_begin_message (NaTrayManager *manager, if (len == 0) { g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0, - socket, "", id, timeout); + child, "", id, timeout); } else { @@ -420,14 +407,14 @@ na_tray_manager_handle_begin_message (NaTrayManager *manager, static void na_tray_manager_handle_cancel_message (NaTrayManager *manager, - XClientMessageEvent *xevent) + XClientMessageEvent *xevent) { - GList *p; - GtkSocket *socket; - long id; + NaTrayChild *child; + GList *p; + long id; id = xevent->data.l[2]; - + /* Check if the message is in the queue and remove it if so */ for (p = manager->messages; p; p = p->next) { @@ -443,166 +430,98 @@ na_tray_manager_handle_cancel_message (NaTrayManager *manager, } } - socket = g_hash_table_lookup (manager->socket_table, - GINT_TO_POINTER (xevent->window)); - - if (socket) + child = g_hash_table_lookup (manager->children, + GINT_TO_POINTER (xevent->window)); + + if (child) { g_signal_emit (manager, manager_signals[MESSAGE_CANCELLED], 0, - socket, xevent->data.l[2]); + child, xevent->data.l[2]); } } -static GdkFilterReturn -na_tray_manager_window_filter (GdkXEvent *xev, - GdkEvent *event, - gpointer data) +static void +na_tray_manager_event_func (MetaX11Display *x11_display, + XEvent *xevent, + gpointer data) { - XEvent *xevent = (GdkXEvent *)xev; NaTrayManager *manager = data; - if (xevent->type == ClientMessage) + if (xevent->type == ClientMessage && + xevent->xany.window == manager->window) { /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_REQUEST_DOCK */ if (xevent->xclient.message_type == manager->opcode_atom && - xevent->xclient.data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) - { + xevent->xclient.data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) + { na_tray_manager_handle_dock_request (manager, (XClientMessageEvent *) xevent); - return GDK_FILTER_REMOVE; - } + } /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_BEGIN_MESSAGE */ else if (xevent->xclient.message_type == manager->opcode_atom && - xevent->xclient.data.l[1] == SYSTEM_TRAY_BEGIN_MESSAGE) + xevent->xclient.data.l[1] == SYSTEM_TRAY_BEGIN_MESSAGE) { na_tray_manager_handle_begin_message (manager, - (XClientMessageEvent *) event); - return GDK_FILTER_REMOVE; + (XClientMessageEvent *) xevent); } /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_CANCEL_MESSAGE */ else if (xevent->xclient.message_type == manager->opcode_atom && - xevent->xclient.data.l[1] == SYSTEM_TRAY_CANCEL_MESSAGE) + xevent->xclient.data.l[1] == SYSTEM_TRAY_CANCEL_MESSAGE) { na_tray_manager_handle_cancel_message (manager, - (XClientMessageEvent *) event); - return GDK_FILTER_REMOVE; + (XClientMessageEvent *) xevent); } /* _NET_SYSTEM_TRAY_MESSAGE_DATA */ else if (xevent->xclient.message_type == manager->message_data_atom) { na_tray_manager_handle_message_data (manager, - (XClientMessageEvent *) event); - return GDK_FILTER_REMOVE; + (XClientMessageEvent *) xevent); } } - else if (xevent->type == SelectionClear) + else if (xevent->type == SelectionClear && + xevent->xany.window == manager->window) { g_signal_emit (manager, manager_signals[LOST_SELECTION], 0); na_tray_manager_unmanage (manager); } - - return GDK_FILTER_CONTINUE; } -#if 0 -//FIXME investigate why this doesn't work -static gboolean -na_tray_manager_selection_clear_event (GtkWidget *widget, - GdkEventSelection *event, - NaTrayManager *manager) -{ - g_signal_emit (manager, manager_signals[LOST_SELECTION], 0); - na_tray_manager_unmanage (manager); - - return FALSE; -} -#endif -#endif - static void na_tray_manager_unmanage (NaTrayManager *manager) { -#ifdef GDK_WINDOWING_X11 - GdkDisplay *display; - guint32 timestamp; - GtkWidget *invisible; - GdkWindow *window; + Display *xdisplay; - if (manager->invisible == NULL) + if (manager->window == None) return; - invisible = manager->invisible; - window = gtk_widget_get_window (invisible); + xdisplay = meta_x11_display_get_xdisplay (manager->x11_display); - g_assert (GTK_IS_INVISIBLE (invisible)); - g_assert (gtk_widget_get_realized (invisible)); - g_assert (GDK_IS_WINDOW (window)); - - display = gtk_widget_get_display (invisible); - - if (gdk_selection_owner_get_for_display (display, manager->selection_atom) == - window) + if (XGetSelectionOwner (xdisplay, manager->selection_atom) == manager->window) { - timestamp = gdk_x11_get_server_time (window); - gdk_selection_owner_set_for_display (display, - NULL, - manager->selection_atom, - timestamp, - TRUE); + XSetSelectionOwner (xdisplay, + manager->selection_atom, + None, + CurrentTime); } - gdk_window_remove_filter (window, - na_tray_manager_window_filter, manager); + meta_x11_display_remove_event_func (manager->x11_display, + manager->event_func_id); + manager->event_func_id = 0; - manager->invisible = NULL; /* prior to destroy for reentrancy paranoia */ - gtk_widget_destroy (invisible); - g_object_unref (G_OBJECT (invisible)); -#endif -} - -static void -na_tray_manager_set_orientation_property (NaTrayManager *manager) -{ -#ifdef GDK_WINDOWING_X11 - GdkWindow *window; - GdkDisplay *display; - Atom orientation_atom; - gulong data[1]; - - g_return_if_fail (manager->invisible != NULL); - window = gtk_widget_get_window (manager->invisible); - g_return_if_fail (window != NULL); - - display = gtk_widget_get_display (manager->invisible); - orientation_atom = gdk_x11_get_xatom_by_name_for_display (display, - "_NET_SYSTEM_TRAY_ORIENTATION"); - - data[0] = manager->orientation == GTK_ORIENTATION_HORIZONTAL ? - SYSTEM_TRAY_ORIENTATION_HORZ : - SYSTEM_TRAY_ORIENTATION_VERT; - - XChangeProperty (GDK_DISPLAY_XDISPLAY (display), - GDK_WINDOW_XID (window), - orientation_atom, - XA_CARDINAL, 32, - PropModeReplace, - (guchar *) &data, 1); -#endif + XDestroyWindow (xdisplay, manager->window); + manager->window = None; } static void na_tray_manager_set_visual_property (NaTrayManager *manager) { -#ifdef GDK_WINDOWING_X11 - GdkWindow *window; - GdkDisplay *display; - Visual *xvisual; - Atom visual_atom; - gulong data[1]; + Display *xdisplay; + Atom visual_atom; + XVisualInfo xvisual_info; + gulong data[1]; + int result; - g_return_if_fail (manager->invisible != NULL); - window = gtk_widget_get_window (manager->invisible); - g_return_if_fail (window != NULL); + g_return_if_fail (manager->window != None); /* 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 @@ -611,49 +530,35 @@ na_tray_manager_set_visual_property (NaTrayManager *manager) * the icon to use our colormap, and we'll do some hacks with parent * relative backgrounds to simulate transparency. */ + xdisplay = meta_x11_display_get_xdisplay (manager->x11_display); + visual_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_VISUAL", False); - display = gtk_widget_get_display (manager->invisible); - visual_atom = gdk_x11_get_xatom_by_name_for_display (display, - "_NET_SYSTEM_TRAY_VISUAL"); + result = XMatchVisualInfo (xdisplay, DefaultScreen (xdisplay), 32, TrueColor, &xvisual_info); - if (gdk_screen_get_rgba_visual (manager->screen) != NULL) - xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_rgba_visual (manager->screen)); + if (result == Success) + data[0] = xvisual_info.visualid; 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. - */ - xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (manager->screen)); - } + data[0] = XVisualIDFromVisual (DefaultVisual (xdisplay, DefaultScreen (xdisplay))); - data[0] = XVisualIDFromVisual (xvisual); - - XChangeProperty (GDK_DISPLAY_XDISPLAY (display), - GDK_WINDOW_XID (window), + XChangeProperty (xdisplay, + manager->window, visual_atom, XA_VISUALID, 32, PropModeReplace, (guchar *) &data, 1); -#endif } static void na_tray_manager_set_colors_property (NaTrayManager *manager) { -#ifdef GDK_WINDOWING_X11 - GdkWindow *window; - GdkDisplay *display; - Atom atom; - gulong data[12]; + Display *xdisplay; + Atom atom; + gulong data[12]; - g_return_if_fail (manager->invisible != NULL); - window = gtk_widget_get_window (manager->invisible); - g_return_if_fail (window != NULL); + g_return_if_fail (manager->window != None); - display = gtk_widget_get_display (manager->invisible); - atom = gdk_x11_get_xatom_by_name_for_display (display, - "_NET_SYSTEM_TRAY_COLORS"); + xdisplay = meta_x11_display_get_xdisplay (manager->x11_display); + atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_COLORS", False); data[0] = manager->fg.red * 0x101; data[1] = manager->fg.green * 0x101; @@ -668,194 +573,87 @@ na_tray_manager_set_colors_property (NaTrayManager *manager) data[10] = manager->success.green * 0x101; data[11] = manager->success.blue * 0x101; - XChangeProperty (GDK_DISPLAY_XDISPLAY (display), - GDK_WINDOW_XID (window), + XChangeProperty (xdisplay, + manager->window, atom, XA_CARDINAL, 32, PropModeReplace, (guchar *) &data, 12); -#endif } -#ifdef GDK_WINDOWING_X11 - -static gboolean -na_tray_manager_manage_screen_x11 (NaTrayManager *manager) +gboolean +na_tray_manager_manage (NaTrayManager *manager) { - GdkDisplay *display; - GdkScreen *screen; - Screen *xscreen; - GtkWidget *invisible; - GdkWindow *window; - char *selection_atom_name; - guint32 timestamp; - + Display *xdisplay; + g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), FALSE); - g_return_val_if_fail (manager->screen == NULL, FALSE); - /* If there's already a manager running on the screen - * we can't create another one. - */ -#if 0 - if (na_tray_manager_check_running_screen_x11 ()) + xdisplay = meta_x11_display_get_xdisplay (manager->x11_display); + + meta_x11_error_trap_push (manager->x11_display); + manager->window = XCreateSimpleWindow (xdisplay, + XDefaultRootWindow (xdisplay), + 0, 0, 1, 1, + 0, 0, 0); + XSelectInput (xdisplay, manager->window, + StructureNotifyMask | PropertyChangeMask); + + if (meta_x11_error_trap_pop_with_return (manager->x11_display) || + !manager->window) return FALSE; -#endif - - screen = gdk_screen_get_default (); - manager->screen = screen; - display = gdk_screen_get_display (screen); - xscreen = GDK_SCREEN_XSCREEN (screen); - - invisible = gtk_invisible_new_for_screen (screen); - gtk_widget_realize (invisible); - - gtk_widget_add_events (invisible, - GDK_PROPERTY_CHANGE_MASK | GDK_STRUCTURE_MASK); + manager->selection_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_S0", False); - selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d", - gdk_x11_get_default_screen ()); - 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); na_tray_manager_set_colors_property (manager); - - window = gtk_widget_get_window (invisible); - timestamp = gdk_x11_get_server_time (window); + meta_x11_error_trap_push (manager->x11_display); + + XSetSelectionOwner (xdisplay, manager->selection_atom, + manager->window, CurrentTime); /* Check if we could set the selection owner successfully */ - if (gdk_selection_owner_set_for_display (display, - window, - manager->selection_atom, - timestamp, - TRUE)) + if (!meta_x11_error_trap_pop_with_return (manager->x11_display)) { XClientMessageEvent xev; - GdkAtom opcode_atom; - GdkAtom message_data_atom; xev.type = ClientMessage; - xev.window = RootWindowOfScreen (xscreen); - xev.message_type = gdk_x11_get_xatom_by_name_for_display (display, - "MANAGER"); + xev.window = XDefaultRootWindow (xdisplay); + xev.message_type = XInternAtom (xdisplay, "MANAGER", False); xev.format = 32; - xev.data.l[0] = timestamp; - xev.data.l[1] = gdk_x11_atom_to_xatom_for_display (display, - manager->selection_atom); - xev.data.l[2] = GDK_WINDOW_XID (window); - xev.data.l[3] = 0; /* manager specific data */ - xev.data.l[4] = 0; /* manager specific data */ + xev.data.l[0] = CurrentTime; + xev.data.l[1] = manager->selection_atom; + xev.data.l[2] = manager->window; + xev.data.l[3] = 0; /* manager specific data */ + xev.data.l[4] = 0; /* manager specific data */ - XSendEvent (GDK_DISPLAY_XDISPLAY (display), - RootWindowOfScreen (xscreen), - False, StructureNotifyMask, (XEvent *)&xev); + XSendEvent (xdisplay, + XDefaultRootWindow (xdisplay), + False, StructureNotifyMask, (XEvent *)&xev); - opcode_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_OPCODE", FALSE); - manager->opcode_atom = gdk_x11_atom_to_xatom_for_display (display, - opcode_atom); + manager->opcode_atom = + XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_OPCODE", False); + manager->message_data_atom = + XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); - message_data_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_MESSAGE_DATA", - FALSE); - manager->message_data_atom = gdk_x11_atom_to_xatom_for_display (display, - message_data_atom); - - /* Add a window filter */ -#if 0 - /* This is for when we lose the selection of _NET_SYSTEM_TRAY_Sx */ - g_signal_connect (invisible, "selection-clear-event", - G_CALLBACK (na_tray_manager_selection_clear_event), - manager); -#endif - gdk_window_add_filter (window, - na_tray_manager_window_filter, manager); + /* Add an event filter */ + manager->event_func_id = + meta_x11_display_add_event_func (manager->x11_display, + na_tray_manager_event_func, + manager, + NULL); return TRUE; } else { - gtk_widget_destroy (invisible); - g_object_unref (invisible); - manager->invisible = NULL; + XDestroyWindow (xdisplay, manager->window); + manager->window = None; - manager->screen = NULL; - return FALSE; } } -#endif - -gboolean -na_tray_manager_manage_screen (NaTrayManager *manager) -{ - g_return_val_if_fail (manager->screen == NULL, FALSE); - -#ifdef GDK_WINDOWING_X11 - return na_tray_manager_manage_screen_x11 (manager); -#else - return FALSE; -#endif -} - -#ifdef GDK_WINDOWING_X11 - -static gboolean -na_tray_manager_check_running_screen_x11 (void) -{ - GdkDisplay *display; - GdkScreen *screen; - Atom selection_atom; - char *selection_atom_name; - - screen = gdk_screen_get_default (); - display = gdk_screen_get_display (screen); - selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d", - gdk_x11_get_default_screen ()); - selection_atom = gdk_x11_get_xatom_by_name_for_display (display, - selection_atom_name); - g_free (selection_atom_name); - - if (XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), - selection_atom) != None) - return TRUE; - else - return FALSE; -} - -#endif - -gboolean -na_tray_manager_check_running (void) -{ -#ifdef GDK_WINDOWING_X11 - return na_tray_manager_check_running_screen_x11 (); -#else - return FALSE; -#endif -} - -void -na_tray_manager_set_orientation (NaTrayManager *manager, - GtkOrientation orientation) -{ - g_return_if_fail (NA_IS_TRAY_MANAGER (manager)); - - if (manager->orientation != orientation) - { - manager->orientation = orientation; - - na_tray_manager_set_orientation_property (manager); - - g_object_notify (G_OBJECT (manager), "orientation"); - } -} - void na_tray_manager_set_colors (NaTrayManager *manager, ClutterColor *fg, @@ -878,11 +676,3 @@ na_tray_manager_set_colors (NaTrayManager *manager, na_tray_manager_set_colors_property (manager); } } - -GtkOrientation -na_tray_manager_get_orientation (NaTrayManager *manager) -{ - g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), GTK_ORIENTATION_HORIZONTAL); - - return manager->orientation; -} diff --git a/src/tray/na-tray-manager.h b/src/tray/na-tray-manager.h index 727b02d40..a417ce726 100644 --- a/src/tray/na-tray-manager.h +++ b/src/tray/na-tray-manager.h @@ -22,84 +22,24 @@ #ifndef __NA_TRAY_MANAGER_H__ #define __NA_TRAY_MANAGER_H__ -#ifdef GDK_WINDOWING_X11 -#include -#endif -#include #include #include "na-tray-child.h" G_BEGIN_DECLS -#define NA_TYPE_TRAY_MANAGER (na_tray_manager_get_type ()) -#define NA_TRAY_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NA_TYPE_TRAY_MANAGER, NaTrayManager)) -#define NA_TRAY_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NA_TYPE_TRAY_MANAGER, NaTrayManagerClass)) -#define NA_IS_TRAY_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NA_TYPE_TRAY_MANAGER)) -#define NA_IS_TRAY_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NA_TYPE_TRAY_MANAGER)) -#define NA_TRAY_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NA_TYPE_TRAY_MANAGER, NaTrayManagerClass)) - -typedef struct _NaTrayManager NaTrayManager; -typedef struct _NaTrayManagerClass NaTrayManagerClass; +#define NA_TYPE_TRAY_MANAGER (na_tray_manager_get_type ()) +G_DECLARE_FINAL_TYPE (NaTrayManager, na_tray_manager, NA, TRAY_MANAGER, GObject) -struct _NaTrayManager -{ - GObject parent_instance; +NaTrayManager *na_tray_manager_new (MetaX11Display *x11_display); -#ifdef GDK_WINDOWING_X11 - GdkAtom selection_atom; - Atom opcode_atom; - Atom message_data_atom; -#endif - - GtkWidget *invisible; - GdkScreen *screen; - GtkOrientation orientation; - ClutterColor fg; - ClutterColor error; - ClutterColor warning; - ClutterColor success; - - GList *messages; - GHashTable *socket_table; -}; - -struct _NaTrayManagerClass -{ - GObjectClass parent_class; - - void (* tray_icon_added) (NaTrayManager *manager, - NaTrayChild *child); - void (* tray_icon_removed) (NaTrayManager *manager, - NaTrayChild *child); - - void (* message_sent) (NaTrayManager *manager, - NaTrayChild *child, - const gchar *message, - glong id, - glong timeout); - - void (* message_cancelled) (NaTrayManager *manager, - NaTrayChild *child, - glong id); - - void (* lost_selection) (NaTrayManager *manager); -}; - -GType na_tray_manager_get_type (void); - -gboolean na_tray_manager_check_running (void); -NaTrayManager *na_tray_manager_new (void); -gboolean na_tray_manager_manage_screen (NaTrayManager *manager); -void na_tray_manager_set_orientation (NaTrayManager *manager, - GtkOrientation orientation); -GtkOrientation na_tray_manager_get_orientation (NaTrayManager *manager); -void na_tray_manager_set_colors (NaTrayManager *manager, - ClutterColor *fg, - ClutterColor *error, - ClutterColor *warning, - ClutterColor *success); +gboolean na_tray_manager_manage (NaTrayManager *manager); +void na_tray_manager_set_colors (NaTrayManager *manager, + ClutterColor *fg, + ClutterColor *error, + ClutterColor *warning, + ClutterColor *success); G_END_DECLS