diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js index 28d2cfbda..dec74064d 100644 --- a/js/ui/notificationDaemon.js +++ b/js/ui/notificationDaemon.js @@ -244,7 +244,7 @@ const NotificationDaemon = new Lang.Class({ Main.overview.connect('hidden', Lang.bind(this, this._onFocusAppChanged)); - this._trayManager.manage_stage(global.stage, Main.messageTray.actor); + this._trayManager.manage_screen(global.screen, Main.messageTray.actor); }, _imageForNotificationData: function(hints) { diff --git a/src/shell-embedded-window.c b/src/shell-embedded-window.c index d1d273fe0..6475e20d3 100644 --- a/src/shell-embedded-window.c +++ b/src/shell-embedded-window.c @@ -8,9 +8,7 @@ #include "shell-embedded-window-private.h" /* This type is a subclass of GtkWindow that ties the window to a - * ShellGtkEmbed; the window is reparented into the stage - * window for the actor and the resizing logic is bound to the clutter - * logic. + * ShellGtkEmbed; the resizing logic is bound to the clutter logic. * * The typical usage we might expect is * @@ -28,16 +26,13 @@ G_DEFINE_TYPE (ShellEmbeddedWindow, shell_embedded_window, GTK_TYPE_WINDOW); enum { - PROP_0, - - PROP_STAGE + PROP_0 }; struct _ShellEmbeddedWindowPrivate { ShellGtkEmbed *actor; GdkRectangle position; - Window stage_xwindow; }; /* @@ -80,27 +75,6 @@ shell_embedded_window_hide (GtkWidget *widget) GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->hide (widget); } -static void -shell_embedded_window_realize (GtkWidget *widget) -{ - ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget); - - GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->realize (widget); - - - /* Using XReparentWindow() is simpler than using gdk_window_reparent(), - * since it avoids maybe having to create a new foreign GDK window for - * the stage. However, GDK will be left thinking that the parent of - * window->window is the root window - it's not immediately clear - * to me whether that is more or less likely to cause problems than - * modifying the GDK hierarchy. - */ - XReparentWindow (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)), - gdk_x11_window_get_xid (gtk_widget_get_window (widget)), - window->priv->stage_xwindow, - window->priv->position.x, window->priv->position.y); -} - static gboolean shell_embedded_window_configure_event (GtkWidget *widget, GdkEventConfigure *event) @@ -127,27 +101,6 @@ shell_embedded_window_check_resize (GtkContainer *container) clutter_actor_queue_relayout (CLUTTER_ACTOR (window->priv->actor)); } -static void -shell_embedded_window_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (object); - - switch (prop_id) - { - case PROP_STAGE: - window->priv->stage_xwindow = - clutter_x11_get_stage_window (g_value_get_object (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static GObject * shell_embedded_window_constructor (GType gtype, guint n_properties, @@ -182,23 +135,13 @@ shell_embedded_window_class_init (ShellEmbeddedWindowClass *klass) g_type_class_add_private (klass, sizeof (ShellEmbeddedWindowPrivate)); - object_class->set_property = shell_embedded_window_set_property; object_class->constructor = shell_embedded_window_constructor; widget_class->show = shell_embedded_window_show; widget_class->hide = shell_embedded_window_hide; - widget_class->realize = shell_embedded_window_realize; widget_class->configure_event = shell_embedded_window_configure_event; container_class->check_resize = shell_embedded_window_check_resize; - - g_object_class_install_property (object_class, - PROP_STAGE, - g_param_spec_object ("stage", - "Stage", - "ClutterStage to embed on", - CLUTTER_TYPE_STAGE, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); } static void @@ -282,9 +225,8 @@ _shell_embedded_window_unmap (ShellEmbeddedWindow *window) * Public API */ GtkWidget * -shell_embedded_window_new (ClutterStage *stage) +shell_embedded_window_new (void) { return g_object_new (SHELL_TYPE_EMBEDDED_WINDOW, - "stage", stage, NULL); } diff --git a/src/shell-embedded-window.h b/src/shell-embedded-window.h index 145bac3a9..fde8006c6 100644 --- a/src/shell-embedded-window.h +++ b/src/shell-embedded-window.h @@ -30,6 +30,6 @@ struct _ShellEmbeddedWindowClass }; GType shell_embedded_window_get_type (void) G_GNUC_CONST; -GtkWidget *shell_embedded_window_new (ClutterStage *stage); +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 index 2232919c5..045435eeb 100644 --- a/src/shell-gtk-embed.c +++ b/src/shell-gtk-embed.c @@ -3,8 +3,11 @@ #include "config.h" #include "shell-embedded-window-private.h" +#include "shell-global.h" #include +#include +#include enum { PROP_0, @@ -15,9 +18,14 @@ enum { struct _ShellGtkEmbedPrivate { ShellEmbeddedWindow *window; + + ClutterActor *window_actor; + guint window_actor_destroyed_handler; + + guint window_created_handler; }; -G_DEFINE_TYPE (ShellGtkEmbed, shell_gtk_embed, CLUTTER_X11_TYPE_TEXTURE_PIXMAP); +G_DEFINE_TYPE (ShellGtkEmbed, shell_gtk_embed, CLUTTER_TYPE_CLONE); static void shell_gtk_embed_set_window (ShellGtkEmbed *embed, ShellEmbeddedWindow *window); @@ -30,39 +38,106 @@ shell_gtk_embed_on_window_destroy (GtkWidget *object, } static void -shell_gtk_embed_on_window_realize (GtkWidget *widget, +shell_gtk_embed_remove_window_actor (ShellGtkEmbed *embed) +{ + ShellGtkEmbedPrivate *priv = embed->priv; + + if (priv->window_actor) + { + g_signal_handler_disconnect (priv->window_actor, + priv->window_actor_destroyed_handler); + priv->window_actor_destroyed_handler = 0; + + 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) { - /* Here automatic=FALSE means to use CompositeRedirectManual. - * That is, the X server shouldn't draw the window onto the - * screen. - */ - clutter_x11_texture_pixmap_set_window (CLUTTER_X11_TEXTURE_PIXMAP (embed), - gdk_x11_window_get_xid (gtk_widget_get_window (widget)), - FALSE); + ShellGtkEmbedPrivate *priv = embed->priv; + Window xwindow = meta_window_get_xwindow (window); + GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (priv->window)); + + if (xwindow == gdk_x11_window_get_xid (gdk_window)) + { + ClutterActor *window_actor = + CLUTTER_ACTOR (meta_window_get_compositor_private (window)); + MetaDisplay *display = shell_global_get_display (shell_global_get ()); + 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); + + /* Set an empty input shape on the window so that it can't get + any input. This probably isn't the ideal way to acheive 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); + + /* Now that we've found the window we don't need to listen for + new windows anymore */ + g_signal_handler_disconnect (display, + priv->window_created_handler); + priv->window_created_handler = 0; + } } static void shell_gtk_embed_set_window (ShellGtkEmbed *embed, ShellEmbeddedWindow *window) { + MetaDisplay *display = shell_global_get_display (shell_global_get ()); if (embed->priv->window) { + if (embed->priv->window_created_handler) + { + g_signal_handler_disconnect (display, + embed->priv->window_created_handler); + embed->priv->window_created_handler = 0; + } + + shell_gtk_embed_remove_window_actor (embed); + _shell_embedded_window_set_actor (embed->priv->window, NULL); g_object_unref (embed->priv->window); - clutter_x11_texture_pixmap_set_window (CLUTTER_X11_TEXTURE_PIXMAP (embed), - None, - FALSE); - g_signal_handlers_disconnect_by_func (embed->priv->window, (gpointer)shell_gtk_embed_on_window_destroy, embed); - g_signal_handlers_disconnect_by_func (embed->priv->window, - (gpointer)shell_gtk_embed_on_window_realize, - embed); } embed->priv->window = window; @@ -75,11 +150,14 @@ shell_gtk_embed_set_window (ShellGtkEmbed *embed, g_signal_connect (embed->priv->window, "destroy", G_CALLBACK (shell_gtk_embed_on_window_destroy), embed); - g_signal_connect (embed->priv->window, "realize", - G_CALLBACK (shell_gtk_embed_on_window_realize), embed); - if (gtk_widget_get_realized (GTK_WIDGET (window))) - shell_gtk_embed_on_window_realize (GTK_WIDGET (embed->priv->window), embed); + /* Listen for new windows so we can detect when Mutter has + created a MutterWindow for this window */ + embed->priv->window_created_handler = + g_signal_connect (display, + "window-created", + G_CALLBACK (shell_gtk_embed_window_created_cb), + embed); } clutter_actor_queue_relayout (CLUTTER_ACTOR (embed)); @@ -260,11 +338,6 @@ shell_gtk_embed_init (ShellGtkEmbed *embed) { embed->priv = G_TYPE_INSTANCE_GET_PRIVATE (embed, SHELL_TYPE_GTK_EMBED, ShellGtkEmbedPrivate); - - /* automatic here means whether ClutterX11TexturePixmap should - * process damage update and refresh the pixmap itself. - */ - clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (embed), TRUE); } /* diff --git a/src/shell-gtk-embed.h b/src/shell-gtk-embed.h index 3d20fb09c..fb6943e54 100644 --- a/src/shell-gtk-embed.h +++ b/src/shell-gtk-embed.h @@ -2,7 +2,7 @@ #ifndef __SHELL_GTK_EMBED_H__ #define __SHELL_GTK_EMBED_H__ -#include +#include #include "shell-embedded-window.h" @@ -19,14 +19,14 @@ typedef struct _ShellGtkEmbedPrivate ShellGtkEmbedPrivate; struct _ShellGtkEmbed { - ClutterX11TexturePixmap parent; + ClutterClone parent; ShellGtkEmbedPrivate *priv; }; struct _ShellGtkEmbedClass { - ClutterX11TexturePixmapClass parent_class; + ClutterCloneClass parent_class; }; GType shell_gtk_embed_get_type (void) G_GNUC_CONST; diff --git a/src/shell-tray-icon.c b/src/shell-tray-icon.c index 15b4e34fc..a4274e376 100644 --- a/src/shell-tray-icon.c +++ b/src/shell-tray-icon.c @@ -7,6 +7,7 @@ #include "shell-window-tracker.h" #include "tray/na-tray-child.h" #include +#include #include "st.h" enum { diff --git a/src/shell-tray-manager.c b/src/shell-tray-manager.c index d5674c945..d74ade795 100644 --- a/src/shell-tray-manager.c +++ b/src/shell-tray-manager.c @@ -17,7 +17,6 @@ struct _ShellTrayManagerPrivate { NaTrayManager *na_manager; - ClutterStage *stage; ClutterColor bg_color; GHashTable *icons; @@ -135,7 +134,6 @@ shell_tray_manager_finalize (GObject *object) ShellTrayManager *manager = SHELL_TRAY_MANAGER (object); g_object_unref (manager->priv->na_manager); - g_object_unref (manager->priv->stage); g_hash_table_destroy (manager->priv->icons); G_OBJECT_CLASS (shell_tray_manager_parent_class)->finalize (object); @@ -219,42 +217,19 @@ shell_tray_manager_style_changed (StWidget *theme_widget, } void -shell_tray_manager_manage_stage (ShellTrayManager *manager, - ClutterStage *stage, - StWidget *theme_widget) +shell_tray_manager_manage_screen (ShellTrayManager *manager, + MetaScreen *screen, + StWidget *theme_widget) { - Window stage_xwindow; - GdkWindow *stage_window; GdkDisplay *display; - GdkScreen *screen; + GdkScreen *gdk_screen; + int screen_number; - g_return_if_fail (manager->priv->stage == NULL); + display = gdk_display_get_default (); + screen_number = meta_screen_get_screen_number (screen); + gdk_screen = gdk_display_get_screen (display, screen_number); - manager->priv->stage = g_object_ref (stage); - - stage_xwindow = clutter_x11_get_stage_window (stage); - - /* This is a pretty ugly way to get the GdkScreen for the stage; it - * will normally go through the foreign_new() case with a - * round-trip to the X server, it might be nicer to pass the screen - * in in some way. (The Clutter/Mutter combo is currently incapable - * of multi-screen operation, so alternatively we could just assume - * that clutter_x11_get_default_screen() gives us the right - * screen.) We assume, in any case, that we are using the default - * GDK display. - */ - display = gdk_display_get_default(); - stage_window = gdk_x11_window_lookup_for_display (display, stage_xwindow); - if (stage_window) - g_object_ref (stage_window); - else - stage_window = gdk_x11_window_foreign_new_for_display (display, stage_xwindow); - - screen = gdk_window_get_screen (stage_window); - - g_object_unref (stage_window); - - na_tray_manager_manage_screen (manager->priv->na_manager, screen); + na_tray_manager_manage_screen (manager->priv->na_manager, gdk_screen); g_signal_connect (theme_widget, "style-changed", G_CALLBACK (shell_tray_manager_style_changed), manager); @@ -320,7 +295,7 @@ na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket, */ na_tray_child_set_composited (NA_TRAY_CHILD (socket), FALSE); - win = shell_embedded_window_new (manager->priv->stage); + win = shell_embedded_window_new (); gtk_container_add (GTK_CONTAINER (win), socket); /* The visual of the socket matches that of its contents; make diff --git a/src/shell-tray-manager.h b/src/shell-tray-manager.h index bc4dc4e93..f19167aef 100644 --- a/src/shell-tray-manager.h +++ b/src/shell-tray-manager.h @@ -41,9 +41,9 @@ struct _ShellTrayManagerClass GType shell_tray_manager_get_type (void); ShellTrayManager *shell_tray_manager_new (void); -void shell_tray_manager_manage_stage (ShellTrayManager *manager, - ClutterStage *stage, - StWidget *theme_widget); +void shell_tray_manager_manage_screen (ShellTrayManager *manager, + MetaScreen *screen, + StWidget *theme_widget); G_END_DECLS